From 80583809041717f499c46aeb9b23f97562bcc9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 5 Jun 2018 13:23:00 +0200 Subject: [PATCH 001/123] macOS: Manually compute frame rect for zoomed/maximized state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot rely on AppKit to compute the zoomed frame for us, as it will not allow borderless windows to be zoomed, and also has bugs in corner cases with multiple screens, where the zoomed window jumps from the current screen to a nearby screen. The latter happens when the zoomed rect overlaps more with a nearby screen than it does with the current screen. In this case AppKit zooms the window on the nearby screen, but this is unexpected from the user's perspective, who zoomed the window on the current screen, so we make sure to always keep the window on the current screen by repositioning the window correspondingly. Task-number: QTBUG-67543 Change-Id: I8762c5cbf2e3b317a6caf11d820712596e15114a Reviewed-by: Morten Johan Sørvig --- .../platforms/cocoa/qnswindowdelegate.mm | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 15c141448d0..057a4c2943d 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -69,25 +69,38 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); /*! Overridden to ensure that the zoomed state always results in a maximized window, which would otherwise not be the case for borderless windows. + + We also keep the window on the same screen as before; something AppKit + sometimes fails to do using its built in logic. */ - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)proposedFrame { Q_UNUSED(proposedFrame); Q_ASSERT(window == m_cocoaWindow->nativeWindow()); - - // We compute the maximized state based on the maximum size, and - // the current position of the window. This may result in the window - // geometry falling outside of the current screen's available geometry, - // e.g. when there is not maximize size set, but this is okey, AppKit - // will then shift and possibly clip the geometry for us. const QWindow *w = m_cocoaWindow->window(); - QRect maximizedRect = QRect(w->framePosition(), w->maximumSize()); - // QWindow::maximumSize() refers to the client size, - // but AppKit expects the full frame size. - maximizedRect.adjust(0, 0, 0, w->frameMargins().top()); + // maximumSize() refers to the client size, but AppKit expects the full frame size + QSizeF maximumSize = w->maximumSize() + QSize(0, w->frameMargins().top()); - return QCocoaScreen::mapToNative(maximizedRect); + // The window should never be larger than the current screen geometry + const QRectF screenGeometry = m_cocoaWindow->screen()->geometry(); + maximumSize = maximumSize.boundedTo(screenGeometry.size()); + + // Use the current frame position for the initial maximized frame, + // so that the window stays put and just expand, in case its maximum + // size is within the screen bounds. + QRectF maximizedFrame = QRectF(w->framePosition(), maximumSize); + + // But constrain the frame to the screen bounds in case the frame + // extends beyond the screen bounds as a result of starting out + // with the current frame position. + maximizedFrame.translate(QPoint( + qMax(screenGeometry.left() - maximizedFrame.left(), 0.0) + + qMin(screenGeometry.right() - maximizedFrame.right(), 0.0), + qMax(screenGeometry.top() - maximizedFrame.top(), 0.0) + + qMin(screenGeometry.bottom() - maximizedFrame.bottom(), 0.0))); + + return QCocoaScreen::mapToNative(maximizedFrame); } - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu From a15db3a81aa6053d1b3ce346b4cb160c064a2c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 7 May 2018 16:17:21 +0200 Subject: [PATCH 002/123] iOS: Guard all uses of APIs not available in application extensions Change-Id: Ic058a0c07f6cdd0a015f46db96fce1536a712711 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/kernel.pro | 2 -- .../platforms/ios/qiosapplicationstate.mm | 4 +-- src/plugins/platforms/ios/qiosfiledialog.mm | 4 ++- src/plugins/platforms/ios/qiosglobal.mm | 14 ++++++-- src/plugins/platforms/ios/qiosinputcontext.mm | 9 ++++- src/plugins/platforms/ios/qiosintegration.mm | 2 +- .../platforms/ios/qiosmessagedialog.mm | 4 ++- src/plugins/platforms/ios/qiosscreen.mm | 33 +++++++++++-------- src/plugins/platforms/ios/qiosservices.mm | 25 ++++++++++++-- .../platforms/ios/qiostextinputoverlay.mm | 8 ++++- src/plugins/platforms/ios/qiostheme.mm | 3 +- .../platforms/ios/qiosviewcontroller.mm | 10 ++++-- 12 files changed, 88 insertions(+), 30 deletions(-) diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro index 6eb9f2c5345..71257d09f73 100644 --- a/src/plugins/platforms/ios/kernel.pro +++ b/src/plugins/platforms/ios/kernel.pro @@ -5,8 +5,6 @@ TARGET = qios # application's main() when the plugin is a shared library. qtConfig(shared): CONFIG += static -CONFIG += no_app_extension_api_only - QT += \ core-private gui-private \ clipboard_support-private fontdatabase_support-private graphics_support-private diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm index cc76d198f55..bf4e9cc900f 100644 --- a/src/plugins/platforms/ios/qiosapplicationstate.mm +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -86,7 +86,7 @@ static void qRegisterApplicationStateNotifications() QLatin1String("Extension loaded, assuming state is active")); } else { // Initialize correct startup state, which may not be the Qt default (inactive) - UIApplicationState startupState = [UIApplication sharedApplication].applicationState; + UIApplicationState startupState = qt_apple_sharedApplication().applicationState; QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application loaded")); } } @@ -95,7 +95,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterApplicationStateNotifications) QIOSApplicationState::QIOSApplicationState() { if (!qt_apple_isApplicationExtension()) { - UIApplicationState startupState = [UIApplication sharedApplication].applicationState; + UIApplicationState startupState = qt_apple_sharedApplication().applicationState; QIOSApplicationState::handleApplicationStateChanged(startupState, QLatin1String("Application launched")); } } diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm index 5987bc15408..e8a3f5b30e9 100644 --- a/src/plugins/platforms/ios/qiosfiledialog.mm +++ b/src/plugins/platforms/ios/qiosfiledialog.mm @@ -43,6 +43,8 @@ #include #include +#include + #include "qiosfiledialog.h" #include "qiosintegration.h" #include "qiosoptionalplugininterface.h" @@ -94,7 +96,7 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent) } UIWindow *window = parent ? reinterpret_cast(parent->winId()).window - : [UIApplication sharedApplication].keyWindow; + : qt_apple_sharedApplication().keyWindow; [window.rootViewController presentViewController:m_viewController animated:YES completion:nil]; return true; diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index f27b2242dfb..a523d1be45a 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -42,6 +42,8 @@ #include "qiosviewcontroller.h" #include "qiosscreen.h" +#include + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application"); @@ -50,13 +52,16 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window"); bool isQtApplication() { + if (qt_apple_isApplicationExtension()) + return false; + // Returns \c true if the plugin is in full control of the whole application. This means // that we control the application delegate and the top view controller, and can take // actions that impacts all parts of the application. The opposite means that we are // embedded inside a native iOS application, and should be more focused on playing along // with native UIControls, and less inclined to change structures that lies outside the // scope of our QWindows/UIViews. - static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]); + static bool isQt = ([qt_apple_sharedApplication().delegate isKindOfClass:[QIOSApplicationDelegate class]]); return isQt; } @@ -152,8 +157,13 @@ QT_END_NAMESPACE + (id)currentFirstResponder { + if (qt_apple_isApplicationExtension()) { + qWarning() << "can't get first responder in application extensions!"; + return nil; + } + QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease]; - [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; + [qt_apple_sharedApplication() sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; return event.firstResponder; } diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 050c592aca1..493c283ec1f 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -49,6 +49,8 @@ #include "qioswindow.h" #include "quiview.h" +#include + #include #include @@ -536,6 +538,11 @@ void QIOSInputContext::scroll(int y) if (!rootView) return; + if (qt_apple_isApplicationExtension()) { + qWarning() << "can't scroll root view in application extension"; + return; + } + CATransform3D translationTransform = CATransform3DMakeTranslation(0.0, -y, 0.0); if (CATransform3DEqualToTransform(translationTransform, rootView.layer.sublayerTransform)) return; @@ -574,7 +581,7 @@ void QIOSInputContext::scroll(int y) // Raise all known windows to above the status-bar if we're scrolling the screen, // while keeping the relative window level between the windows the same. - NSArray *applicationWindows = [[UIApplication sharedApplication] windows]; + NSArray *applicationWindows = [qt_apple_sharedApplication() windows]; static QHash originalWindowLevels; for (UIWindow *window in applicationWindows) { if (keyboardScrollIsActive && !originalWindowLevels.contains(window)) diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index b8ce49aacad..ed2bfbc0d8c 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -86,7 +86,7 @@ QIOSIntegration::QIOSIntegration() , m_accessibility(0) , m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin"))) { - if (Q_UNLIKELY(![UIApplication sharedApplication])) { + if (Q_UNLIKELY(!qt_apple_isApplicationExtension() && !qt_apple_sharedApplication())) { qFatal("Error: You are creating QApplication before calling UIApplicationMain.\n" \ "If you are writing a native iOS application, and only want to use Qt for\n" \ "parts of the application, a good place to create QApplication is from within\n" \ diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm index 9d05b792c20..a7de9b473ac 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -43,6 +43,8 @@ #include #include +#include + #include "qiosglobal.h" #include "quiview.h" #include "qiosmessagedialog.h" @@ -126,7 +128,7 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win [m_alertController addAction:createAction(NoButton)]; } - UIWindow *window = parent ? reinterpret_cast(parent->winId()).window : [UIApplication sharedApplication].keyWindow; + UIWindow *window = parent ? reinterpret_cast(parent->winId()).window : qt_apple_sharedApplication().keyWindow; [window.rootViewController presentViewController:m_alertController animated:YES completion:nil]; return true; } diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index c394592d761..f367d1e75e4 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -46,6 +46,8 @@ #include "qiosviewcontroller.h" #include "quiview.h" +#include + #include #include @@ -271,17 +273,19 @@ QIOSScreen::QIOSScreen(UIScreen *screen) m_physicalDpi = 96; } - for (UIWindow *existingWindow in [[UIApplication sharedApplication] windows]) { - if (existingWindow.screen == m_uiScreen) { - m_uiWindow = [m_uiWindow retain]; - break; + if (!qt_apple_isApplicationExtension()) { + for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) { + if (existingWindow.screen == m_uiScreen) { + m_uiWindow = [m_uiWindow retain]; + break; + } } - } - if (!m_uiWindow) { - // Create a window and associated view-controller that we can use - m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]]; - m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; + if (!m_uiWindow) { + // Create a window and associated view-controller that we can use + m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]]; + m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease]; + } } updateProperties(); @@ -327,17 +331,20 @@ void QIOSScreen::updateProperties() #ifndef Q_OS_TVOS if (m_uiScreen == [UIScreen mainScreen]) { - Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation)); - QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ? static_cast(m_uiWindow.rootViewController) : nil; if (qtViewController.lockedOrientation) { + Q_ASSERT(!qt_apple_isApplicationExtension()); + // Setting the statusbar orientation (content orientation) on will affect the screen geometry, // which is not what we want. We want to reflect the screen geometry based on the locked orientation, // and adjust the available geometry based on the repositioned status bar for the current status // bar orientation. + Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation( + UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation)); + Qt::ScreenOrientation lockedOrientation = toQtScreenOrientation(UIDeviceOrientation(qtViewController.lockedOrientation)); QTransform transform = transformBetween(lockedOrientation, statusBarOrientation, m_geometry).inverted(); @@ -487,8 +494,8 @@ Qt::ScreenOrientation QIOSScreen::orientation() const // the orientation the application was started up in (which may not match // the physical orientation of the device, but typically does unless the // application has been locked to a subset of the available orientations). - if (deviceOrientation == UIDeviceOrientationUnknown) - deviceOrientation = UIDeviceOrientation([UIApplication sharedApplication].statusBarOrientation); + if (deviceOrientation == UIDeviceOrientationUnknown && !qt_apple_isApplicationExtension()) + deviceOrientation = UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation); // If the device reports face up or face down orientations, we can't map // them to Qt orientations, so we pretend we're in the same orientation diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm index 3c44e1d7d65..7222bf67937 100644 --- a/src/plugins/platforms/ios/qiosservices.mm +++ b/src/plugins/platforms/ios/qiosservices.mm @@ -40,6 +40,9 @@ #include "qiosservices.h" #include +#include +#include + #include #import @@ -48,6 +51,11 @@ QT_BEGIN_NAMESPACE bool QIOSServices::openUrl(const QUrl &url) { + if (qt_apple_isApplicationExtension()) { + qWarning() << "openUrl not implement for application extensions yet"; + return false; + } + if (url == m_handlingUrl) return false; @@ -55,12 +63,25 @@ bool QIOSServices::openUrl(const QUrl &url) return openDocument(url); NSURL *nsUrl = url.toNSURL(); - UIApplication *application = [UIApplication sharedApplication]; + UIApplication *application = qt_apple_sharedApplication(); if (![application canOpenURL:nsUrl]) return false; - [application openURL:nsUrl options:@{} completionHandler:nil]; + static SEL openUrlSelector = @selector(openURL:options:completionHandler:); + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [UIApplication instanceMethodSignatureForSelector:openUrlSelector]]; + invocation.target = application; + invocation.selector = openUrlSelector; + + static auto kEmptyDictionary = @{}; + // Indices 0 and 1 are self and _cmd + [invocation setArgument:&nsUrl atIndex:2]; + [invocation setArgument:&kEmptyDictionary atIndex:3]; + // Fourth argument is nil, so left unset + + [invocation invoke]; + return true; } diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index fe3c29d0371..87c282e24af 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -46,6 +46,7 @@ #include #include +#include #include "qiosglobal.h" #include "qiostextinputoverlay.h" @@ -475,7 +476,7 @@ static void executeBlockWithoutAnimation(Block block) if (enabled) { _focusView = [reinterpret_cast(qApp->focusWindow()->winId()) retain]; - _desktopView = [[UIApplication sharedApplication].keyWindow.rootViewController.view retain]; + _desktopView = [qt_apple_sharedApplication().keyWindow.rootViewController.view retain]; Q_ASSERT(_focusView && _desktopView && _desktopView.superview); [_desktopView addGestureRecognizer:self]; } else { @@ -991,6 +992,11 @@ QIOSTextInputOverlay::QIOSTextInputOverlay() , m_selectionRecognizer(nullptr) , m_openMenuOnTapRecognizer(nullptr) { + if (qt_apple_isApplicationExtension()) { + qWarning() << "text input overlays disabled in application extensions"; + return; + } + connect(qApp, &QGuiApplication::focusObjectChanged, this, &QIOSTextInputOverlay::updateFocusObject); } diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index 91980d3f359..5534264a601 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -41,6 +41,7 @@ #include #include +#include #include @@ -103,7 +104,7 @@ bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const switch (type) { case FileDialog: case MessageDialog: - return true; + return !qt_apple_isApplicationExtension(); default: return false; } diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index d7db6ba8569..aa909d6f632 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -41,6 +41,7 @@ #import "qiosviewcontroller.h" #include +#include #include #include @@ -307,15 +308,17 @@ { [super viewDidLoad]; + Q_ASSERT(!qt_apple_isApplicationExtension()); + #ifndef Q_OS_TVOS NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(willChangeStatusBarFrame:) name:UIApplicationWillChangeStatusBarFrameNotification - object:[UIApplication sharedApplication]]; + object:qt_apple_sharedApplication()]; [center addObserver:self selector:@selector(didChangeStatusBarOrientation:) name:UIApplicationDidChangeStatusBarOrientationNotification - object:[UIApplication sharedApplication]]; + object:qt_apple_sharedApplication()]; #endif } @@ -455,7 +458,6 @@ focusWindow = qt_window_private(focusWindow)->topLevelWindow(); #ifndef Q_OS_TVOS - UIApplication *uiApplication = [UIApplication sharedApplication]; // -------------- Status bar style and visbility --------------- @@ -479,6 +481,8 @@ // -------------- Content orientation --------------- + UIApplication *uiApplication = qt_apple_sharedApplication(); + static BOOL kAnimateContentOrientationChanges = YES; Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation(); From 36d2ef5af9875afd9d398f5e37102194040cb1d9 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 1 Jun 2018 15:12:05 +0200 Subject: [PATCH 003/123] Ignore XDG_SESSION_TYPE=wayland on gnome-shell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ChangeLog][Wayland] In Qt 5.11.0, support for selecting a platform plugin based on the XDG_SESSION_TYPE environment variable was added. On gnome-shell, however, bugs—in both Qt and gnome-shell—made many widget applications almost unusable. So until those bugs are fixed XDG_SESSION_TYPE=wayland is now ignored on gnome-shell. Task-number: QTBUG-68619 Change-Id: I902acd1c4fc996f46e8431c12c0a5cdbab883abf Reviewed-by: Paul Olav Tvete Reviewed-by: Thiago Macieira --- src/gui/kernel/qguiapplication.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c73dac42d68..2ef689b5b90 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1297,10 +1297,18 @@ void QGuiApplicationPrivate::createPlatformIntegration() #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) QByteArray sessionType = qgetenv("XDG_SESSION_TYPE"); if (!sessionType.isEmpty()) { - if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) + if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) { platformName = QByteArrayLiteral("xcb"); - else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) - platformName = QByteArrayLiteral("wayland"); + } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) { + QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); + QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower(); + if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) { + qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome." + << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway."; + } else { + platformName = QByteArrayLiteral("wayland"); + } + } } #ifdef QT_QPA_DEFAULT_PLATFORM_NAME // Add it as fallback in case XDG_SESSION_TYPE is something wrong From 21e9c7c24f6430fc694e4ec0d34fba64427587dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Tue, 5 Jun 2018 16:29:06 +0200 Subject: [PATCH 004/123] Opt out of new Xcode build system until we can handle its requirements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new build system in Xcode 10 requires outputs from shell script to be explicitly declared if they are used by subsequent build phases, otherwise the build system may attempt to search for the file before it has been generated, causing the build to fail. The build phase we use for Qt preprocessing (moc, rcc, etc), does not list these output files, so we need to disable the new build system for now. Change-Id: I7404c19021f57489e985bd1203ad09ce9b83b090 Reviewed-by: Simon Hausmann Reviewed-by: Gabriel de Dietrich Reviewed-by: Tor Arne Vestbø --- mkspecs/macx-xcode/WorkspaceSettings.xcsettings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings index 08de0be8d3c..a3f43a8b380 100644 --- a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings +++ b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ + BuildSystemType + Original IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded From 689a071e843dfbac49901018ba3c49b08e22fd94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 6 Jun 2018 12:44:18 +0200 Subject: [PATCH 005/123] xcode: Take effective platform name into account for configuration build dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default value for CONFIGURATION_BUILD_DIR includes EFFECTIVE_PLATFORM_NAME, but when overriding it in 554e44b77 we only used the CONFIGURATION variable. This left the .app in iOS builds in Debug instead of Debug-iphoneos, breaking deployment from within Qt Creator, which had this directory hard-coded. We now include EFFECTIVE_PLATFORM_NAME to restore the original destination for the .app bundle. Task-number: QTBUG-68705 Change-Id: If304193d3e351e19fb84d250a62ae331af6966c6 Reviewed-by: Morten Johan Sørvig --- qmake/generators/mac/pbuilder_pbx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 18b62c5135f..80891e682f3 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -1613,7 +1613,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) // The configuration build dir however is not treated as excluded, // so we can safely point it to the root output dir. t << "\t\t\t\t" << writeSettings("CONFIGURATION_BUILD_DIR", - Option::output_dir + Option::dir_sep + "$(CONFIGURATION)") << ";\n"; + Option::output_dir + Option::dir_sep + "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)") << ";\n"; if (!project->isEmpty("DESTDIR")) { ProString dir = project->first("DESTDIR"); From 225dcf355a95f272aaa7ac236c7274e254dca41c Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 5 Jun 2018 14:40:36 +0200 Subject: [PATCH 006/123] Don't set the wasDeleted flag in ~QWidget Setting it too early can cause issues, as we are still doing lots of work here as e.g. calling hide() on children. But the flag is required when we delete the declarative data, so set and reset it when destroying that data. Amends c579f49e2a80a55a4004ff8e5b2ee76bda146387 Task-number: QTBUG-68637 Change-Id: I7ed35828c26912aa6d703ba6025e46b7911353fa Reviewed-by: Simon Hausmann Reviewed-by: Christian Stenger Reviewed-by: Friedemann Kleint --- src/widgets/graphicsview/qgraphicsitem.cpp | 2 ++ src/widgets/kernel/qwidget.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index cef1d1b6da8..fdf21fb4995 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -1579,6 +1579,7 @@ QGraphicsItem::~QGraphicsItem() QObjectPrivate *p = QObjectPrivate::get(o); p->wasDeleted = true; if (p->declarativeData) { + p->wasDeleted = true; // needed, so that destroying the declarative data does the right thing if (static_cast(p->declarativeData)->ownedByQml1) { if (QAbstractDeclarativeData::destroyed_qml1) QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o); @@ -1587,6 +1588,7 @@ QGraphicsItem::~QGraphicsItem() QAbstractDeclarativeData::destroyed(p->declarativeData, o); } p->declarativeData = 0; + p->wasDeleted = false; } } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 41f9d69c12a..5f1f6d880aa 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -1677,8 +1677,8 @@ QWidget::~QWidget() } } - d->wasDeleted = true; if (d->declarativeData) { + d->wasDeleted = true; // needed, so that destroying the declarative data does the right thing if (static_cast(d->declarativeData)->ownedByQml1) { if (QAbstractDeclarativeData::destroyed_qml1) QAbstractDeclarativeData::destroyed_qml1(d->declarativeData, this); @@ -1687,6 +1687,7 @@ QWidget::~QWidget() QAbstractDeclarativeData::destroyed(d->declarativeData, this); } d->declarativeData = 0; // don't activate again in ~QObject + d->wasDeleted = false; } d->blockSig = blocked; From c6b3f4b28200a2f1a4af70cc30af91b74a6df64b Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 5 Jun 2018 15:12:57 +0200 Subject: [PATCH 007/123] Fix black border around main widget with non-integer scaling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All the other highdpi scaling uses rounding, and not using it here may offset the compositing by a line. Task-number: QTBUG-67994 Change-Id: I2f5f328c091d0e85c40b1663e22c82f364df65e5 Reviewed-by: Morten Johan Sørvig --- src/gui/painting/qplatformbackingstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index 09c23fdfa1c..cc8d850689a 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -344,7 +344,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i QWindowPrivate::get(window)->lastComposeTime.start(); QOpenGLFunctions *funcs = d_ptr->context->functions(); - funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio()); + funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio())); funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1); funcs->glClear(GL_COLOR_BUFFER_BIT); From c118f642c35f67a4ac475daa78fef14eae2fed61 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 28 Feb 2018 13:36:54 +0100 Subject: [PATCH 008/123] Doc: Update Elided Label example Updated connect syntax Task-number: QTBUG-60635 Change-Id: I8d770f62557d5056375d72d778c4e2079511b848 Reviewed-by: Paul Wicking Reviewed-by: Venugopal Shivashankar --- examples/widgets/widgets/elidedlabel/testwidget.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/widgets/widgets/elidedlabel/testwidget.cpp b/examples/widgets/widgets/elidedlabel/testwidget.cpp index 50c12374fdd..6392a4b4fa6 100644 --- a/examples/widgets/widgets/elidedlabel/testwidget.cpp +++ b/examples/widgets/widgets/elidedlabel/testwidget.cpp @@ -94,25 +94,25 @@ TestWidget::TestWidget(QWidget *parent): //! [2] QPushButton *switchButton = new QPushButton(tr("Switch text")); - connect(switchButton, SIGNAL(clicked(bool)), this, SLOT(switchText())); + connect(switchButton, &QPushButton::clicked, this, &TestWidget::switchText); QPushButton *exitButton = new QPushButton(tr("Exit")); - connect(exitButton, SIGNAL(clicked(bool)), this, SLOT(close())); + connect(exitButton, &QPushButton::clicked, this, &TestWidget::close); QLabel *label = new QLabel(tr("Elided")); label->setVisible(elidedText->isElided()); - connect(elidedText, SIGNAL(elisionChanged(bool)), label, SLOT(setVisible(bool))); + connect(elidedText, &ElidedLabel::elisionChanged, label, &QLabel::setVisible); //! [2] //! [3] widthSlider = new QSlider(Qt::Horizontal); widthSlider->setMinimum(0); - connect(widthSlider, SIGNAL(valueChanged(int)), this, SLOT(onWidthChanged(int))); + connect(widthSlider, &QSlider::valueChanged, this, &TestWidget::onWidthChanged); heightSlider = new QSlider(Qt::Vertical); heightSlider->setInvertedAppearance(true); heightSlider->setMinimum(0); - connect(heightSlider, SIGNAL(valueChanged(int)), this, SLOT(onHeightChanged(int))); + connect(heightSlider, &QSlider::valueChanged, this, &TestWidget::onHeightChanged); //! [3] //! [4] @@ -165,4 +165,3 @@ void TestWidget::onHeightChanged(int height) } //! [8] - From 9551d62d97c15a74f257df2219d719264ff9e68c Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 7 Mar 2018 15:52:37 +0100 Subject: [PATCH 009/123] Doc: Update Factorial Example Updated connect syntax Task-number: QTBUG-60635 Change-Id: Ib5280326c158221129c1817a4853bfd79bbcd895 Reviewed-by: Paul Wicking Reviewed-by: Venugopal Shivashankar --- examples/widgets/statemachine/factorial/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/widgets/statemachine/factorial/main.cpp b/examples/widgets/statemachine/factorial/main.cpp index 919988051f2..f100aa0110e 100644 --- a/examples/widgets/statemachine/factorial/main.cpp +++ b/examples/widgets/statemachine/factorial/main.cpp @@ -175,7 +175,7 @@ int main(int argc, char **argv) //! [6] machine.setInitialState(compute); - QObject::connect(&machine, SIGNAL(finished()), &app, SLOT(quit())); + QObject::connect(&machine, &QStateMachine::finished, &app, QCoreApplication::quit); machine.start(); return app.exec(); From f7c8a991c300f99da808ef2657b16a976c1dfc7a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 6 Jun 2018 19:42:42 -0700 Subject: [PATCH 010/123] QFileSystemWatcher/Linux: don't print warnings for benign cases ENOENT (no such file or directory) is a benign error, since it could happen also out of a race condition. All the other errors in the inotify_add_watch(2) man page indicate bugs in Qt or resource exhaustion, so those remain being printed. Task-number: QTBUG-68586 Change-Id: I04b94079b6da48f39a82fffd1535c08d8a3d8c33 Reviewed-by: Edward Welbourne Reviewed-by: David Faure --- src/corelib/io/qfilesystemwatcher_inotify.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index 048669b92f2..c0c5f9d744d 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -302,7 +302,8 @@ QStringList QInotifyFileSystemWatcherEngine::addPaths(const QStringList &paths, | IN_DELETE_SELF ))); if (wd < 0) { - qWarning().nospace() << "inotify_add_watch(" << path << ") failed: " << QSystemError(errno, QSystemError::NativeError).toString(); + if (errno != ENOENT) + qErrnoWarning("inotify_add_watch(%ls) failed:", path.constData()); continue; } From 73b2d7f612c0c01ac55da52612c198b5cac0fa26 Mon Sep 17 00:00:00 2001 From: Takumi ASAKI Date: Thu, 7 Jun 2018 16:03:04 +0900 Subject: [PATCH 011/123] QNX: Add QQnxEglWindow::format() overload QQnxEglWindow should return correct QSurfaceFormat. Task-number: QTBUG-64306 Change-Id: I3ba2a9d84f39af66c3b8f58ae3e26edc695f5612 Reviewed-by: James McDonnell --- src/plugins/platforms/qnx/qqnxeglwindow.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index 3a3840f13c2..d8cfd730acd 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -60,6 +60,8 @@ public: void setGeometry(const QRect &rect) override; + QSurfaceFormat format() const override { return m_format; } + protected: int pixelFormat() const override; void resetBuffers() override; From dbad7bd2345df603a98d7cd35fceb2e9c1998250 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Fri, 8 Jun 2018 11:59:52 +0200 Subject: [PATCH 012/123] Doc: Sql example Books lock rating column width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lock the width of the rating column to prohibit the contents to escape the bounds of the column upon resize. Task-number: QTBUG-68652 Change-Id: I5c744833b19a8e5bcf88ef1b9ab657ac81f5aa50 Reviewed-by: Nico Vertriest Reviewed-by: Topi Reiniö --- examples/sql/books/bookwindow.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/sql/books/bookwindow.cpp b/examples/sql/books/bookwindow.cpp index d85b4389563..3aac5b55b72 100644 --- a/examples/sql/books/bookwindow.cpp +++ b/examples/sql/books/bookwindow.cpp @@ -115,6 +115,11 @@ BookWindow::BookWindow() ui.genreEdit->setModelColumn( model->relationModel(genreIdx)->fieldIndex("name")); + // Lock and prohibit resizing of the width of the rating column: + ui.bookTable->horizontalHeader()->setSectionResizeMode( + model->fieldIndex("rating"), + QHeaderView::ResizeToContents); + QDataWidgetMapper *mapper = new QDataWidgetMapper(this); mapper->setModel(model); mapper->setItemDelegate(new BookDelegate(this)); From 427e5d61b7b33c8a4cb8da14c1e465244e53cd88 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Thu, 17 May 2018 12:58:53 +0200 Subject: [PATCH 013/123] Add support for building QtWayland on macOS Change-Id: Ibed63a01abf32e10a31c610996ae93d3bd9ce153 Reviewed-by: Oswald Buddenhagen Reviewed-by: Paul Olav Tvete --- mkspecs/common/mac.conf | 7 +++++++ mkspecs/features/wayland-scanner.prf | 25 ++++++++++++++++--------- src/platformsupport/platformsupport.pro | 2 +- src/platformsupport/themes/themes.pro | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/mkspecs/common/mac.conf b/mkspecs/common/mac.conf index 5208379f9aa..d5e559ee124 100644 --- a/mkspecs/common/mac.conf +++ b/mkspecs/common/mac.conf @@ -33,6 +33,13 @@ QMAKE_LIBS_DYNLOAD = QMAKE_LIBS_OPENGL = -framework OpenGL -framework AGL QMAKE_LIBS_THREAD = +QMAKE_INCDIR_WAYLAND = +QMAKE_LIBS_WAYLAND_CLIENT = -lwayland-client +QMAKE_LIBS_WAYLAND_SERVER = -lwayland-server +QMAKE_LIBDIR_WAYLAND = +QMAKE_DEFINES_WAYLAND = +QMAKE_WAYLAND_SCANNER = wayland-scanner + QMAKE_ACTOOL = actool QMAKE_DSYMUTIL = dsymutil diff --git a/mkspecs/features/wayland-scanner.prf b/mkspecs/features/wayland-scanner.prf index 9166ae77501..4b8e2ef76e0 100644 --- a/mkspecs/features/wayland-scanner.prf +++ b/mkspecs/features/wayland-scanner.prf @@ -34,25 +34,32 @@ defineReplace(waylandScannerHeaderFiles) { return($$wayland_header_files_for_side) } -qt_install_headers { +# 1) if we are a module, we need to create the headers in our private inc dir in qtbase +# 2) if also qt_install_headers is set, we need to generate INSTALLS rules in addition +# 3) if we are not a module, we just generate the headers in the current directory +!isEmpty(MODULE) { header_dest = $$MODULE_BASE_OUTDIR/include/$$MODULE_INCNAME/$$VERSION/$$MODULE_INCNAME/private header_files_client = $$waylandScannerHeaderFiles(client, $$header_dest) !isEmpty(header_files_client) { - wayland_generated_client_headers.files = $$header_files_client - wayland_generated_client_headers.path = $$private_headers.path - wayland_generated_client_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_client_headers + qt_install_headers { + wayland_generated_client_headers.files = $$header_files_client + wayland_generated_client_headers.path = $$private_headers.path + wayland_generated_client_headers.CONFIG = no_check_exist + INSTALLS += wayland_generated_client_headers + } WAYLAND_CLIENT_HEADER_DEST = $$header_dest/ WAYLAND_CLIENT_INCLUDE_DIR = $$MODULE_INCNAME/private } header_files_server = $$waylandScannerHeaderFiles(server, $$header_dest) !isEmpty(header_files_server) { - wayland_generated_server_headers.files = $$header_files_server - wayland_generated_server_headers.path = $$private_headers.path - wayland_generated_server_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_server_headers + qt_install_headers { + wayland_generated_server_headers.files = $$header_files_server + wayland_generated_server_headers.path = $$private_headers.path + wayland_generated_server_headers.CONFIG = no_check_exist + INSTALLS += wayland_generated_server_headers + } WAYLAND_SERVER_HEADER_DEST = $$header_dest/ WAYLAND_SERVER_INCLUDE_DIR = $$MODULE_INCNAME/private } diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 7dbb6f6cae7..6d4f1b93bd1 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -16,7 +16,7 @@ qtConfig(evdev)|qtConfig(tslib)|qtConfig(libinput)|qtConfig(integrityhid) { input.depends += devicediscovery } -if(unix:!darwin)|qtConfig(xcb): \ +if(unix:!uikit)|qtConfig(xcb): \ SUBDIRS += services qtConfig(opengl): \ diff --git a/src/platformsupport/themes/themes.pro b/src/platformsupport/themes/themes.pro index 44f94fafc84..668a8434732 100644 --- a/src/platformsupport/themes/themes.pro +++ b/src/platformsupport/themes/themes.pro @@ -6,7 +6,7 @@ CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII -if(unix:!darwin)|qtConfig(xcb): \ +if(unix:!uikit)|qtConfig(xcb): \ include($$PWD/genericunix/genericunix.pri) HEADERS += \ From 02be6850841d143ffb6c8b15c5ecf611b81fe81c Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Wed, 6 Jun 2018 11:32:39 +0200 Subject: [PATCH 014/123] xcb: fix mouse event compression with certain configurations The bug was that we are accessing memory beyond 32 bytes. It is not safe to cast xcb_generic_event_t to Xlib's XI2 structs before we have memmoved bits to the expected layout (for details see QXcbConnection::xi2PrepareXIGenericDeviceEvent). We do this memmove later in the stack, when processing the XI2 events. Here at the compression step we can simply extract the necessary sourceId by reading the sourceId offset in the data. Task-number: QTBUG-68033 Change-Id: I6962bbb8f8b0834d6f780f62017fefa2de7f47df Reviewed-by: Mikhail Svetkin Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 879d31f29a2..d971de766df 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1683,12 +1683,14 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, if (!hasXInput2()) return false; - // compress XI_Motion, but not from tablet devices + // compress XI_Motion if (isXIType(event, m_xiOpCode, XI_Motion)) { #if QT_CONFIG(tabletevent) xXIDeviceEvent *xdev = reinterpret_cast(event); + // Xlib's XI2 events need memmove, see xi2PrepareXIGenericDeviceEvent() + auto sourceId = *reinterpret_cast(reinterpret_cast(&xdev->sourceid) + 4); if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && - const_cast(this)->tabletDataForDevice(xdev->sourceid)) + const_cast(this)->tabletDataForDevice(sourceId)) return false; #endif // QT_CONFIG(tabletevent) for (int j = nextIndex; j < eventqueue->size(); ++j) { From 3f295f272a4bf7afb073e5cbb3958c86da1199c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 8 Jun 2018 16:19:18 +0200 Subject: [PATCH 015/123] Update platform defines for Apple OSes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS 10.14 (Mojave) and iOS 12 has been added, and older defines for platforms below our deployment target have been removed. Change-Id: Ib7b3e657d11136179b669a94da56963d4716bcb7 Reviewed-by: Morten Johan Sørvig --- src/corelib/global/qsystemdetection.h | 79 +++------------------------ 1 file changed, 8 insertions(+), 71 deletions(-) diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index ff0e03108bb..cacb95b6745 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -216,18 +216,6 @@ # // Numerical checks are preferred to named checks, but to be safe # // we define the missing version names in case Qt uses them. # -# if !defined(__MAC_10_7) -# define __MAC_10_7 1070 -# endif -# if !defined(__MAC_10_8) -# define __MAC_10_8 1080 -# endif -# if !defined(__MAC_10_9) -# define __MAC_10_9 1090 -# endif -# if !defined(__MAC_10_10) -# define __MAC_10_10 101000 -# endif # if !defined(__MAC_10_11) # define __MAC_10_11 101100 # endif @@ -237,17 +225,8 @@ # if !defined(__MAC_10_13) # define __MAC_10_13 101300 # endif -# if !defined(MAC_OS_X_VERSION_10_7) -# define MAC_OS_X_VERSION_10_7 1070 -# endif -# if !defined(MAC_OS_X_VERSION_10_8) -# define MAC_OS_X_VERSION_10_8 1080 -# endif -# if !defined(MAC_OS_X_VERSION_10_9) -# define MAC_OS_X_VERSION_10_9 1090 -# endif -# if !defined(MAC_OS_X_VERSION_10_10) -# define MAC_OS_X_VERSION_10_10 101000 +# if !defined(__MAC_10_14) +# define __MAC_10_14 101400 # endif # if !defined(MAC_OS_X_VERSION_10_11) # define MAC_OS_X_VERSION_10_11 101100 @@ -258,55 +237,10 @@ # if !defined(MAC_OS_X_VERSION_10_13) # define MAC_OS_X_VERSION_10_13 101300 # endif +# if !defined(MAC_OS_X_VERSION_10_14) +# define MAC_OS_X_VERSION_10_14 101400 +# endif # -# if !defined(__IPHONE_4_3) -# define __IPHONE_4_3 40300 -# endif -# if !defined(__IPHONE_5_0) -# define __IPHONE_5_0 50000 -# endif -# if !defined(__IPHONE_5_1) -# define __IPHONE_5_1 50100 -# endif -# if !defined(__IPHONE_6_0) -# define __IPHONE_6_0 60000 -# endif -# if !defined(__IPHONE_6_1) -# define __IPHONE_6_1 60100 -# endif -# if !defined(__IPHONE_7_0) -# define __IPHONE_7_0 70000 -# endif -# if !defined(__IPHONE_7_1) -# define __IPHONE_7_1 70100 -# endif -# if !defined(__IPHONE_8_0) -# define __IPHONE_8_0 80000 -# endif -# if !defined(__IPHONE_8_1) -# define __IPHONE_8_1 80100 -# endif -# if !defined(__IPHONE_8_2) -# define __IPHONE_8_2 80200 -# endif -# if !defined(__IPHONE_8_3) -# define __IPHONE_8_3 80300 -# endif -# if !defined(__IPHONE_8_4) -# define __IPHONE_8_4 80400 -# endif -# if !defined(__IPHONE_9_0) -# define __IPHONE_9_0 90000 -# endif -# if !defined(__IPHONE_9_1) -# define __IPHONE_9_1 90100 -# endif -# if !defined(__IPHONE_9_2) -# define __IPHONE_9_2 90200 -# endif -# if !defined(__IPHONE_9_3) -# define __IPHONE_9_3 90300 -# endif # if !defined(__IPHONE_10_0) # define __IPHONE_10_0 100000 # endif @@ -322,6 +256,9 @@ # if !defined(__IPHONE_11_0) # define __IPHONE_11_0 110000 # endif +# if !defined(__IPHONE_12_0) +# define __IPHONE_12_0 120000 +# endif #endif #ifdef __LSB_VERSION__ From de4eb79c2bc761372858ddc35f771191c57e9943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 8 Jun 2018 11:48:04 +0200 Subject: [PATCH 016/123] Fix warning about receiver 'UIApplication' being a forward class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iffe11d85916274c85c16314c44b023887b43322d Reviewed-by: Morten Johan Sørvig --- src/corelib/kernel/qcore_mac_objc.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index c29c4dfc149..7263d812282 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -44,6 +44,10 @@ #include #endif +#if defined(QT_PLATFORM_UIKIT) +#include +#endif + #include QT_BEGIN_NAMESPACE From 89f9a3db15940ea87d6ad89f93bfa5aa1d7564fb Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 7 Jun 2018 12:21:23 +0200 Subject: [PATCH 017/123] Revert "xcb: round down the scale factor for values < 0.8" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 23b139038a1dc9a769a358ab112453abcdd39290. The commit causes a regression on Ubuntu where the DPI setting of the display is ignored. Task-number: QTBUG-68620 Change-Id: Id176f8cda0daef1755abb3aa9382476cc4ed7d71 Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/xcb/qxcbscreen.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index e1bd8eb752f..df458e85d7c 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -750,12 +750,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) m_sizeMillimeters = sizeInMillimeters(geometry.size(), virtualDpi()); qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4); - qreal rawFactor = dpi/96; - int roundedFactor = qFloor(rawFactor); - // Round up for .8 and higher. This favors "small UI" over "large UI". - if (rawFactor - roundedFactor >= 0.8) - roundedFactor = qCeil(rawFactor); - m_pixelDensity = qMax(1, roundedFactor); + m_pixelDensity = qMax(1, qRound(dpi/96)); m_geometry = geometry; m_availableGeometry = geometry & m_virtualDesktop->workArea(); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); From 3e201d645e1276c5168d7fef6943f95cc67d8643 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 7 May 2018 22:55:09 -0700 Subject: [PATCH 018/123] MSVC: Enable the detection of C++14 and 17 in MSVC 2017 15.7 We need -Zc:__cplusplus in order to enable the __cplusplus macro having the correct value. This causes configure to now print: Checking for C++14 support... yes Checking for C++1z support... yes and Using C++ standard ..................... C++1z Change-Id: I5d0ee9389a794d80983efffd152c95a4d9d8adbc Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- mkspecs/common/msvc-version.conf | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mkspecs/common/msvc-version.conf b/mkspecs/common/msvc-version.conf index ccd809abf3a..3fb55c9d816 100644 --- a/mkspecs/common/msvc-version.conf +++ b/mkspecs/common/msvc-version.conf @@ -100,11 +100,16 @@ greaterThan(QMAKE_MSC_VER, 1909) { # API is used in direct2d, but also in multimedia, positioning and sensors. # We can try again with a later version of Visual Studio. # QMAKE_CXXFLAGS_STRICTCXX = -permissive- + # MSVC partially supports the following, but '__cplusplus' definition is set # as for C++98 until MSVC fully conforms with C++14, see # https://developercommunity.visualstudio.com/content/problem/139261/msvc-incorrectly-defines-cplusplus.html - # QMAKE_CXXFLAGS_CXX14 = -std:c++14 - # QMAKE_CXXFLAGS_CXX1Z = -std:c++latest + # Support became available in MSVC 2017 15.7: + greaterThan(QMAKE_MSC_VER, 1913) { + QMAKE_CXXFLAGS += -Zc:__cplusplus + QMAKE_CXXFLAGS_CXX14 = -std:c++14 + QMAKE_CXXFLAGS_CXX1Z = -std:c++17 + } } greaterThan(QMAKE_MSC_VER, 1910) { From 835c79bc4f21b6503a03d9d9ad6cf6434fb74d43 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Fri, 25 May 2018 12:07:20 +0300 Subject: [PATCH 019/123] Add changes file for Qt 5.9.6 Change-Id: I8f342db47d12a835a8698265c68f3906298e82ad Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll (cherry picked from commit 4e68ad5f120f9c883ad5fde5a68278ba3b01e8e3) --- dist/changes-5.9.6 | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 dist/changes-5.9.6 diff --git a/dist/changes-5.9.6 b/dist/changes-5.9.6 new file mode 100644 index 00000000000..29f5ec2d575 --- /dev/null +++ b/dist/changes-5.9.6 @@ -0,0 +1,46 @@ +Qt 5.9.6 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0 through 5.9.5. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.9.6 Changes * +**************************************************************************** + + - This release contains only minor code improvements. + +QtCore +------ + + - [QTBUG-61159] Fixed QStandardPaths::standardLocations() returning some + incorrect paths on macOS. + - [QTBUG-57299] Fixed some issues with locking files during save using + QSaveFile if the target directory is monitored by Dropbox. + +QtWidgets +--------- + + - [QTBUG-16252] Fixed geometry not restored correctly for a dock widget + after being docked. + +qmake +----- + + - [QTBUG-52474][Xcode] Fixed sources being excluded from Time Machine + backups. + - [QTBUG-66156] $$relative_path() and $$absolute_path() now resolve + the base directory to an absolute path. From f9421af66eb979b187f83cd128fed525e072be7d Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Fri, 16 Mar 2018 13:05:22 +0200 Subject: [PATCH 020/123] Add changes file for Qt 5.9.5 Change-Id: I6de04b86f01467c326bf3194fe0bf432d1ee9f9b Reviewed-by: Thiago Macieira (cherry picked from commit f4c2fcc052e5c27e8765e68216f02e1e1915e5bc) --- dist/changes-5.9.5 | 122 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 dist/changes-5.9.5 diff --git a/dist/changes-5.9.5 b/dist/changes-5.9.5 new file mode 100644 index 00000000000..a71b09bf902 --- /dev/null +++ b/dist/changes-5.9.5 @@ -0,0 +1,122 @@ +Qt 5.9.5 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0 through 5.9.4. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.9.5 Changes * +**************************************************************************** + +QtCore +------ + + - QDateTime and QLocale: + * [QTBUG-66076] Fixed a crash if the date/time parsed with Qt::ISODate and + Qt::ISODateWithMS had a 'T' for the time, but no actual time. + + - QObject: + * [QTBUG-65712] Improved performance of QObject::deleteLater. + + - QPluginLoader: + * [QTBUG-65197] Fixed a bug that would cause the Qt plugin scanning + system to allocate too much memory and possibly crash the process. + + - QStandardPaths: + * [QTBUG-65687] Fixed a memory leak with displayName() on Apple platforms. + * [QTBUG-65820] Fixed QStandardPaths::AppDataLocation on Android. + +QtGui +----- + + - Text: + * [QTBUG-61882] Fixed a bug where mixing different writing systems with + emojis could lead to missing glyphs. + * [QTBUG-65519] Fixed ZWJ and ZWNJ control characters when fallback + fonts are in use. + +QtWidgets +--------- + + - QTreeView: + * [QTBUG-65980] Fixed missing update of QTreeView on changing tree + position. + + - QLabel: + * [QTBUG-66841] Fixed crash related to deleted buddy. + + - QHeaderView: + * [QTBUG-65478] Fixed crash that could happen during layout. + * [QTBUG-66444][QTBUG-65478][QTBUG-65478] Fixed section resize settings + getting lost after layouting. + * [QTBUG-66413][QTBUG-65478] Fixed hidden section issues during layout. + * [QTBUG-65478] Fixed section restore issues after a layout change. + + - QFusionStyle: + * [QTBUG-66343] Fixed checkbox rendering regression in low DPI settings. + + - QComboBox: + * [QTBUG-55251] Fixed context menu opening up at the wrong location. + + - QFileDialog: + * Fixed regression when using QFileDialog::getOpenFileUrl() using + remote URLs. + + - QWidget: + * [QTBUG-65783] Fixed crash when platform window creation fails. + +Third-Party Code +---------------- + + - Documented use of "Unicode Character Database (UCD)" in Qt Core. + - Clarified use of "Unicode Common Local Data Repository (CLDR)" in the + documentation. Also updated SPDX license name / ID. + +Platform-specific changes +------------------------- + + - Android: + * [QTBUG-65863] Fixed the detection of which thread is the main thread on + Android. + + - Windows: + * Named pipes internally created by QProcess now contain the PID in their + name to ensure uniqueness. + + - winrt: + * -qdevel and -qdebug are removed from the command line arguments and + not passed to the application. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-65753] Fixed installation of example sources for qrc/rc files. + - [Windows] cl.exe is now preferred over clang-cl.exe again. + +qmake +----- + + - [QTBUG-50839][Windows] Paths starting with a (back-)slash but without + a drive letter are not considered absolute any more. + - [QTBUG-63637][MinGW] Fixed cross-compilation from Linux. + - [QTBUG-65106] Fixed complaints about missing modules in $$QT after the + project has already failed requires() (or REQUIRES=). + - [QTBUG-65477][Darwin] Bundle identifiers are now properly escaped. + - [Windows] Fixed 'make check' for executables in subdirectories. From 5b2d33db7c1e6db8f6b7021b9f7c8594880c7003 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 22 May 2018 19:06:04 -0300 Subject: [PATCH 021/123] Remove extraneous text after #if Added by accident in 0ac2dca977ecc4020f51af57908a2640d00bcd9e, but apparently no one is compiling with ICC. Change-Id: I052407b777ec43f78378fffd153116c06362bfd7 Reviewed-by: Lars Knoll --- src/corelib/global/qcompilerdetection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index f3f3139d1a6..f46ff73527e 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -629,7 +629,7 @@ # define Q_COMPILER_THREAD_LOCAL # define Q_COMPILER_UDL # endif -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L s +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ > 199901L // C11 features supported. Only tested with ICC 17 and up. # define Q_COMPILER_STATIC_ASSERT # if __has_include() From 67227aeffdf94be8d177309d27291d5b3247586c Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Mon, 4 Jun 2018 17:24:53 +0200 Subject: [PATCH 022/123] xcb: fix regression with remote X11 clients There were several issues here: We were attempting to use MIT-SHM functions over SSH connection, which is not supported. X server should detect this and return with an appropriate error message. It does actually return BadAccess for non-fd code path, but Qt was stubbornly trying to repeat this action and always falling back to malloc (during window resizing). For fd code path we were hitting X server bug, which would result in window freeze [1]. During the initialization we check if xcb_shm_attach_checked() fails, and disable MIT-SHM if it does. We use this logic to detect if we are running remotely, as there are no public APIs for it. This way we can avoid X server bug and avoid needless calling of code path which will _always_ fail on a remote X11 connection. [1] https://lists.x.org/archives/xorg-devel/2018-June/057011.html Task-number: QTBUG-68449 Task-number: QTBUG-68783 Change-Id: I7ab3dcf0f323fd53001b9f7b88c2cb10809af509 Reviewed-by: Gatis Paeglis --- .../platforms/xcb/qxcbbackingstore.cpp | 113 ++++++++++-------- src/plugins/platforms/xcb/qxcbbackingstore.h | 3 + src/plugins/platforms/xcb/qxcbconnection.cpp | 31 +++-- 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 8cfcc49f9a1..b81cb8efa1a 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -95,6 +95,9 @@ public: void put(xcb_drawable_t dst, const QRegion ®ion, const QPoint &offset); void preparePaint(const QRegion ®ion); + static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + xcb_shm_segment_info_t *shm_info = nullptr); + private: void createShmSegment(size_t segmentSize); void destroyShmSegment(size_t segmentSize); @@ -325,15 +328,16 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { if (Q_UNLIKELY(segmentSize > std::numeric_limits::max())) { - qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u", - segmentSize, std::numeric_limits::max()); + qCWarning(lcQpaXcb, "xcb_shm_create_segment() can't be called for size %zu, maximum" + "allowed size is %u", segmentSize, std::numeric_limits::max()); return; } + const auto seg = xcb_generate_id(xcb_connection()); auto reply = Q_XCB_REPLY(xcb_shm_create_segment, xcb_connection(), seg, segmentSize, false); if (!reply) { - qWarning("QXcbShmImage: xcb_shm_create_segment() failed for size %zu", segmentSize); + qCWarning(lcQpaXcb, "xcb_shm_create_segment() failed for size %zu", segmentSize); return; } @@ -342,13 +346,13 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) for (int i = 0; i < reply->nfd; i++) close(fds[i]); - qWarning("QXcbShmImage: failed to get file descriptor for shm segment of size %zu", segmentSize); + qCWarning(lcQpaXcb, "failed to get file descriptor for shm segment of size %zu", segmentSize); return; } void *addr = mmap(nullptr, segmentSize, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0); if (addr == MAP_FAILED) { - qWarning("QXcbShmImage: failed to mmap segment from X server (%d: %s) for size %zu", + qCWarning(lcQpaXcb, "failed to mmap segment from X server (%d: %s) for size %zu", errno, strerror(errno), segmentSize); close(fds[0]); xcb_shm_detach(xcb_connection(), seg); @@ -358,49 +362,56 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) close(fds[0]); m_shm_info.shmseg = seg; m_shm_info.shmaddr = static_cast(addr); - m_segmentSize = segmentSize; } else #endif { - const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) { - qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %zu", - errno, strerror(errno), segmentSize); - return; - } - - void *addr = shmat(id, 0, 0); - if (addr == (void *)-1) { - qWarning("QXcbShmImage: shmat() failed (%d: %s) for id %d", - errno, strerror(errno), id); - return; - } - - if (shmctl(id, IPC_RMID, 0) == -1) - qWarning("QXcbBackingStore: Error while marking the shared memory segment to be destroyed"); - - const auto seg = xcb_generate_id(xcb_connection()); - auto cookie = xcb_shm_attach_checked(xcb_connection(), seg, id, false); - auto *error = xcb_request_check(xcb_connection(), cookie); - if (error) { - connection()->printXcbError("QXcbShmImage: xcb_shm_attach() failed with error", error); - free(error); - if (shmdt(addr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), addr); - } - return; - } - - m_shm_info.shmseg = seg; - m_shm_info.shmid = id; // unused - m_shm_info.shmaddr = static_cast(addr); - - m_segmentSize = segmentSize; + if (createSystemVShmSegment(connection(), segmentSize, &m_shm_info)) + m_segmentSize = segmentSize; } } +bool QXcbBackingStoreImage::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, + xcb_shm_segment_info_t *shmInfo) +{ + const int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); + if (id == -1) { + qCWarning(lcQpaXcb, "shmget() failed (%d: %s) for size %zu", errno, strerror(errno), segmentSize); + return false; + } + + void *addr = shmat(id, 0, 0); + if (addr == (void *)-1) { + qCWarning(lcQpaXcb, "shmat() failed (%d: %s) for id %d", errno, strerror(errno), id); + return false; + } + + if (shmctl(id, IPC_RMID, 0) == -1) + qCWarning(lcQpaXcb, "Error while marking the shared memory segment to be destroyed"); + + const auto seg = xcb_generate_id(c->xcb_connection()); + auto cookie = xcb_shm_attach_checked(c->xcb_connection(), seg, id, false); + auto *error = xcb_request_check(c->xcb_connection(), cookie); + if (error) { + c->printXcbError("xcb_shm_attach() failed with error", error); + free(error); + if (shmdt(addr) == -1) + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), addr); + return false; + } else if (!shmInfo) { // this was a test run, free the allocated test segment + xcb_shm_detach(c->xcb_connection(), seg); + auto shmaddr = static_cast(addr); + if (shmdt(shmaddr) == -1) + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", errno, strerror(errno), shmaddr); + } + if (shmInfo) { + shmInfo->shmseg = seg; + shmInfo->shmid = id; // unused + shmInfo->shmaddr = static_cast(addr); + } + return true; +} + void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) { #ifndef XCB_USE_SHM_FD @@ -409,21 +420,21 @@ void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) auto cookie = xcb_shm_detach_checked(xcb_connection(), m_shm_info.shmseg); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); if (error) - connection()->printXcbError("QXcbShmImage: xcb_shm_detach() failed with error", error); + connection()->printXcbError("xcb_shm_detach() failed with error", error); m_shm_info.shmseg = 0; #ifdef XCB_USE_SHM_FD if (connection()->hasShmFd()) { if (munmap(m_shm_info.shmaddr, segmentSize) == -1) { - qWarning("QXcbShmImage: munmap() failed (%d: %s) for %p with size %zu", - errno, strerror(errno), m_shm_info.shmaddr, segmentSize); + qCWarning(lcQpaXcb, "munmap() failed (%d: %s) for %p with size %zu", + errno, strerror(errno), m_shm_info.shmaddr, segmentSize); } } else #endif { if (shmdt(m_shm_info.shmaddr) == -1) { - qWarning("QXcbShmImage: shmdt() failed (%d: %s) for %p", - errno, strerror(errno), m_shm_info.shmaddr); + qCWarning(lcQpaXcb, "shmdt() failed (%d: %s) for %p", + errno, strerror(errno), m_shm_info.shmaddr); } m_shm_info.shmid = 0; // unused } @@ -718,6 +729,12 @@ void QXcbBackingStoreImage::preparePaint(const QRegion ®ion) m_pendingFlush |= region; } +bool QXcbBackingStore::createSystemVShmSegment(QXcbConnection *c, size_t segmentSize, void *shmInfo) +{ + auto info = reinterpret_cast(shmInfo); + return QXcbBackingStoreImage::createSystemVShmSegment(c, segmentSize, info); +} + QXcbBackingStore::QXcbBackingStore(QWindow *window) : QPlatformBackingStore(window) { @@ -757,7 +774,7 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) void QXcbBackingStore::endPaint() { if (Q_UNLIKELY(m_paintRegions.isEmpty())) { - qWarning("%s: paint regions empty!", Q_FUNC_INFO); + qCWarning(lcQpaXcb, "%s: paint regions empty!", Q_FUNC_INFO); return; } @@ -811,7 +828,7 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin QXcbWindow *platformWindow = static_cast(window->handle()); if (!platformWindow) { - qWarning("QXcbBackingStore::flush: QWindow has no platform window (QTBUG-32681)"); + qCWarning(lcQpaXcb, "%s QWindow has no platform window, see QTBUG-32681", Q_FUNC_INFO); return; } diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 747626c2130..734de1f7d76 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -74,6 +74,9 @@ public: void beginPaint(const QRegion &) override; void endPaint() override; + static bool createSystemVShmSegment(QXcbConnection *c, size_t segmentSize = 1, + void *shmInfo = nullptr); + private: QXcbBackingStoreImage *m_image = nullptr; QStack m_paintRegions; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index d971de766df..8ed73bc2702 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -55,6 +55,7 @@ #include "qxcbsystemtraytracker.h" #include "qxcbglintegrationfactory.h" #include "qxcbglintegration.h" +#include "qxcbbackingstore.h" #include #include @@ -973,7 +974,7 @@ void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *err uint clamped_error_code = qMin(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1); - qWarning("%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", + qCWarning(lcQpaXcb, "%s: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d", message, int(error->error_code), xcb_errors[clamped_error_code], int(error->sequence), int(error->resource_id), @@ -2103,20 +2104,34 @@ void QXcbConnection::initializeShm() { const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_shm_id); if (!reply || !reply->present) { - qWarning("QXcbConnection: MIT-SHM extension is not present on the X server."); + qCDebug(lcQpaXcb, "MIT-SHM extension is not present on the X server"); return; } - has_shm = true; auto shm_query = Q_XCB_REPLY(xcb_shm_query_version, m_connection); - if (!shm_query) { - qWarning("QXcbConnection: Failed to request MIT-SHM version"); - return; + if (shm_query) { + has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || + shm_query->major_version > 1; + } else { + qCWarning(lcQpaXcb, "QXcbConnection: Failed to request MIT-SHM version"); } - has_shm_fd = (shm_query->major_version == 1 && shm_query->minor_version >= 2) || - shm_query->major_version > 1; + qCDebug(lcQpaXcb) << "Has MIT-SHM :" << has_shm; + qCDebug(lcQpaXcb) << "Has MIT-SHM FD :" << has_shm_fd; + + // Temporary disable warnings (unless running in debug mode). + auto logging = const_cast(&lcQpaXcb()); + bool wasEnabled = logging->isEnabled(QtMsgType::QtWarningMsg); + if (!logging->isEnabled(QtMsgType::QtDebugMsg)) + logging->setEnabled(QtMsgType::QtWarningMsg, false); + if (!QXcbBackingStore::createSystemVShmSegment(this)) { + qCDebug(lcQpaXcb, "failed to create System V shared memory segment (remote " + "X11 connection?), disabling SHM"); + has_shm = has_shm_fd = false; + } + if (wasEnabled) + logging->setEnabled(QtMsgType::QtWarningMsg, true); } void QXcbConnection::initializeXFixes() From 8cc27590bd2a04ce841cdb66f234ff13f11148af Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Mon, 11 Jun 2018 13:48:43 +0200 Subject: [PATCH 023/123] Make sure MODULE is set even when we are not creating a pri file wayland-scanner.prf uses it as a trigger, so this is needed to make dynamic non-prefix builds work. amends 427e5d61b7. Task-number: QTBUG-68773 Change-Id: Ia7d3bc39cb2b0f225e827f64eb17d061d594b265 Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_plugin.prf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mkspecs/features/qt_plugin.prf b/mkspecs/features/qt_plugin.prf index bf90adcf1eb..40528a65e26 100644 --- a/mkspecs/features/qt_plugin.prf +++ b/mkspecs/features/qt_plugin.prf @@ -35,9 +35,9 @@ CONFIG += relative_qt_rpath # Qt's plugins should be relocatable # Qt libraries should only use Application Extension safe APIs darwin:!no_app_extension_api_only: CONFIG += app_extension_api_only -CONFIG(static, static|shared)|prefix_build { - isEmpty(MODULE): MODULE = $$basename(TARGET) +isEmpty(MODULE): MODULE = $$basename(TARGET) +CONFIG(static, static|shared)|prefix_build { mod_work_pfx = $$MODULE_QMAKE_OUTDIR/mkspecs/modules force_independent: \ mod_inst_pfx = $$MODULE_QMAKE_OUTDIR/mkspecs/modules-inst From 33fea7e7a9155632f7ac3804a1a6d1d35324b6d0 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 8 Jun 2018 16:00:44 +0200 Subject: [PATCH 024/123] qmake: use consistent path separators in makefile dependencies Task-number: QTBUG-65072 Change-Id: I3456d9b2cdfa9c65be5933f592abb640f81c39f2 Reviewed-by: Liang Qi Reviewed-by: Joerg Bornemann --- qmake/generators/makefile.cpp | 17 ++++++++++++++--- qmake/generators/makefile.h | 2 ++ qmake/generators/unix/unixmake2.cpp | 4 ++-- qmake/generators/win32/mingw_make.cpp | 4 ++-- qmake/generators/win32/msvc_nmake.cpp | 4 ++-- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 99aecdd8ced..dda323535d6 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1141,7 +1141,7 @@ MakefileGenerator::writeObj(QTextStream &t, const char *src) QString srcf = (*sit).toQString(); QString dstf = (*oit).toQString(); t << escapeDependencyPath(dstf) << ": " << escapeDependencyPath(srcf) - << " " << escapeDependencyPaths(findDependencies(srcf)).join(" \\\n\t\t"); + << " " << finalizeDependencyPaths(findDependencies(srcf)).join(" \\\n\t\t"); ProKey comp; for (const ProString &compiler : project->values("QMAKE_BUILTIN_COMPILERS")) { @@ -2013,7 +2013,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) if (config.indexOf("explicit_dependencies") != -1) { t << " " << valList(escapeDependencyPaths(fileFixify(tmp_dep, FileFixifyFromOutdir))); } else { - t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(escapeDependencyPaths(deps)); + t << " " << valList(escapeDependencyPaths(inputs)) << " " << valList(finalizeDependencyPaths(deps)); } t << "\n\t" << cmd << endl << endl; continue; @@ -2133,7 +2133,7 @@ MakefileGenerator::writeExtraCompilerTargets(QTextStream &t) else ++i; } - t << escapeDependencyPath(out) << ": " << valList(escapeDependencyPaths(deps)) << "\n\t" + t << escapeDependencyPath(out) << ": " << valList(finalizeDependencyPaths(deps)) << "\n\t" << cmd << endl << endl; } } @@ -2851,6 +2851,17 @@ MakefileGenerator::escapeDependencyPaths(const ProStringList &paths) const return ret; } +QStringList +MakefileGenerator::finalizeDependencyPaths(const QStringList &paths) const +{ + QStringList ret; + const int size = paths.size(); + ret.reserve(size); + for (int i = 0; i < size; ++i) + ret.append(escapeDependencyPath(Option::fixPathToTargetOS(paths.at(i), false))); + return ret; +} + QStringList MakefileGenerator::fileFixify(const QStringList &files, FileFixifyTypes fix, bool canon) const { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 4ced3bd1219..6341a141b97 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -139,6 +139,8 @@ protected: QStringList escapeDependencyPaths(const QStringList &paths) const; ProStringList escapeDependencyPaths(const ProStringList &paths) const; + QStringList finalizeDependencyPaths(const QStringList &paths) const; + //initialization void verifyCompilers(); virtual void init(); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 5468285c2e6..3cb3be474a5 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -375,7 +375,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) QStringList deps = findDependencies((*it).toQString()).filter(QRegExp( "((^|/)" + Option::h_moc_mod + "|" + Option::cpp_moc_ext + "$)")); if(!deps.isEmpty()) - t << d_file_d << ": " << escapeDependencyPaths(deps).join(' ') << endl; + t << d_file_d << ": " << finalizeDependencyPaths(deps).join(' ') << endl; t << "-include " << d_file_d << endl; project->values("QMAKE_DISTCLEAN") += d_file; } @@ -1191,7 +1191,7 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) << "EXPORT_QMAKE_XARCH_LFLAGS = $(EXPORT_QMAKE_XARCH_LFLAGS_" << arch << ")" << "\n\n"; } t << pchFilePath_d << ": " << escapeDependencyPath(pchInput) << ' ' - << escapeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t"); + << finalizeDependencyPaths(findDependencies(pchInput)).join(" \\\n\t\t"); if (project->isActiveConfig("icc_pch_style")) { QString sourceFile = pchArchOutput + Option::cpp_ext.first(); QString sourceFile_f = escapeFilePath(sourceFile); diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index d6d6b04148c..6140debf055 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -165,13 +165,13 @@ void MingwMakefileGenerator::writeMingwParts(QTextStream &t) QString header = project->first("PRECOMPILED_HEADER").toQString(); QString cHeader = preCompHeaderOut + Option::dir_sep + "c"; t << escapeDependencyPath(cHeader) << ": " << escapeDependencyPath(header) << " " - << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") << "\n\t" << mkdir_p_asstring(preCompHeaderOut) << "\n\t$(CC) -x c-header -c $(CFLAGS) $(INCPATH) -o " << escapeFilePath(cHeader) << ' ' << escapeFilePath(header) << endl << endl; QString cppHeader = preCompHeaderOut + Option::dir_sep + "c++"; t << escapeDependencyPath(cppHeader) << ": " << escapeDependencyPath(header) << " " - << escapeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(header)).join(" \\\n\t\t") << "\n\t" << mkdir_p_asstring(preCompHeaderOut) << "\n\t$(CXX) -x c++-header -c $(CXXFLAGS) $(INCPATH) -o " << escapeFilePath(cppHeader) << ' ' << escapeFilePath(header) << endl << endl; diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index ccc2ea6d2bf..680d3736c2c 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -321,7 +321,7 @@ void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t) QString precompRule = QString("-c -Yc -Fp%1 -Fo%2") .arg(escapeFilePath(precompPch), escapeFilePath(precompObj)); t << escapeDependencyPath(precompObj) << ": " << escapeDependencyPath(precompH) << ' ' - << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") << "\n\t$(CXX) " + precompRule +" $(CXXFLAGS) $(INCPATH) -TP " << escapeFilePath(precompH) << endl << endl; } @@ -329,7 +329,7 @@ void NmakeMakefileGenerator::writeNmakeParts(QTextStream &t) QString precompRuleC = QString("-c -Yc -Fp%1 -Fo%2") .arg(escapeFilePath(precompPchC), escapeFilePath(precompObjC)); t << escapeDependencyPath(precompObjC) << ": " << escapeDependencyPath(precompH) << ' ' - << escapeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") + << finalizeDependencyPaths(findDependencies(precompH)).join(" \\\n\t\t") << "\n\t$(CC) " + precompRuleC +" $(CFLAGS) $(INCPATH) -TC " << escapeFilePath(precompH) << endl << endl; } From de6b81399e4cb9f80c4c5bc95c7e32545b2934a3 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Tue, 12 Jun 2018 16:55:52 +0300 Subject: [PATCH 025/123] Qmake: Fix compilation with QMAKE_USE_CACHE Change-Id: Ib2872093d1e82a59baad94104dafe8329a9e8942 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefiledeps.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp index c68eeb13d6d..ffccdefbe1f 100644 --- a/qmake/generators/makefiledeps.cpp +++ b/qmake/generators/makefiledeps.cpp @@ -1050,7 +1050,7 @@ void QMakeSourceFileInfo::saveCache(const QString &cf) QFile file(QMakeLocalFileName(cf).local()); if(file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); - stream << qmake_version() << endl << endl; //version + stream << QMAKE_VERSION_STR << endl << endl; //version { //cache verification QMap verify = getCacheVerification(); stream << verify.count() << endl; @@ -1105,11 +1105,11 @@ void QMakeSourceFileInfo::loadCache(const QString &cf) return; QFile file; - if(!file.open(QIODevice::ReadOnly, fd)) + if (!file.open(fd, QIODevice::ReadOnly)) return; QTextStream stream(&file); - if(stream.readLine() == qmake_version()) { //version check + if (stream.readLine() == QMAKE_VERSION_STR) { //version check stream.skipWhiteSpace(); bool verified = true; From 26ff9aac8e884e09b7dc27de8b051ef4d0f8c077 Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 7 Mar 2018 13:02:42 +0100 Subject: [PATCH 026/123] Doc: Update Extension example -language review -rewrite some paragraphs Task-number: QTBUG-60635 Change-Id: I96154cd5d78b9517409ac67ec416c53031dcb909 Reviewed-by: Paul Wicking Reviewed-by: Venugopal Shivashankar --- examples/widgets/doc/src/extension.qdoc | 98 +++++++++++++------------ 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/examples/widgets/doc/src/extension.qdoc b/examples/widgets/doc/src/extension.qdoc index d040fbb9ce4..c895258acf1 100644 --- a/examples/widgets/doc/src/extension.qdoc +++ b/examples/widgets/doc/src/extension.qdoc @@ -36,23 +36,21 @@ \image extension-example.png Screenshot of the Extension example - The Extension application is a dialog that allows the user to - perform a simple search as well as a more advanced search. + The Extension application lets the user add search parameters in + a dialog and launch a simple or advanced search. The simple search has two options: \uicontrol {Match case} and \uicontrol - {Search from start}. The advanced search options include the - possibilities to search for \uicontrol {Whole words}, \uicontrol {Search - backward} and \uicontrol {Search selection}. Only the simple search is - visible when the application starts. The advanced search options - are located in the application's extension part, and can be made - visible by pressing the \uicontrol More button: + {Search from start}. The advanced search offers search for \uicontrol {Whole words}, + \uicontrol {Search backward}, and \uicontrol {Search selection}. The + application starts with simple search as the default. Click the \uicontrol More button + to show the advanced search options: \image extension_more.png Screenshot of the Extension example \section1 FindDialog Class Definition - The \c FindDialog class inherits QDialog. The QDialog class is the - base class of dialog windows. A dialog window is a top-level + The \c FindDialog class inherits QDialog. QDialog is the + base class for dialog windows. A dialog window is a top-level window mostly used for short-term tasks and brief communications with the user. @@ -62,45 +60,53 @@ displays the application's search options and controlling buttons. - In addition to a constructor, we declare the several child - widgets: We need a QLineEdit with an associated QLabel to let the - user type a word to search for, we need several \l - {QCheckBox}{QCheckBox}es to facilitate the search options, and we - need three \l {QPushButton}{QPushButton}s: the \uicontrol Find button to - start a search and the \uicontrol More button to enable an advanced search. - Finally, we need a QWidget representing the application's extension - part. + In addition to the constructor, there are several child widgets: + + \list + \li A QLineEdit with an associated QLabel to let the + user type a word to search for. + \li Several \l {QCheckBox}{QCheckBox}es to facilitate the search options. + \li Three \l {QPushButton}{QPushButton}s: + \list + \li the \uicontrol Find button to start a search + \li the \uicontrol More button to enable an advanced search + \li a QWidget representing the application's extension part + \endlist + \endlist \section1 FindDialog Class Implementation - In the constructor we first create the standard child widgets for - the simple search: the QLineEdit with the associated QLabel, two - of the \l {QCheckBox}{QCheckBox}es and all the \l - {QPushButton}{QPushButton}s. + Create the standard child widgets for the simple search in the constructor: + the QLineEdit with the associated QLabel, two {QCheckBox}es and all the + \l {QPushButton}{QPushButton}s. \snippet dialogs/extension/finddialog.cpp 0 - We give the options and buttons a shortcut key using the & - character. In the \uicontrol {Find what} option's case, we also need to - use the QLabel::setBuddy() function to make the shortcut key work - as expected; then, when the user presses the shortcut key - indicated by the label, the keyboard focus is transferred to the - label's buddy widget, the QLineEdit. + This snippet illustrates how you can define a shortcut key + for a widget. A shortcut should be defined by putting the ampersand + character (\c &) in front of the letter that should + become the shortcut. + For example, for \uicontrol {Find what}, pressing \uicontrol Alt + and \uicontrol w transfers focus to the QLineEdit widget. + Shortcuts can also be used for checking on or off a checkmark. + For example, pressing \uicontrol Alt and \uicontrol c puts the check mark + on \uicontrol {Match Case} if it was unchecked and vice versa. + It is the QLabel::setBuddy() method that links a widget to the shortcut + character if it has been defined. - We set the \uicontrol Find button's default property to true, using the + Set the \uicontrol Find button's default property to true, using the QPushButton::setDefault() function. Then the push button will be pressed if the user presses the Enter (or Return) key. Note that a QDialog can only have one default button. \snippet dialogs/extension/finddialog.cpp 2 - Then we create the extension widget, and the \l - {QCheckBox}{QCheckBox}es associated with the advanced search - options. + Create the extension widget, and the \l {QCheckBox}{QCheckBox}es associated + with the advanced search options. \snippet dialogs/extension/finddialog.cpp 3 - Now that the extension widget is created, we can connect the \uicontrol + Now that the extension widget is created, connect the \uicontrol More button's \l{QAbstractButton::toggled()}{toggled()} signal to the extension widget's \l{QWidget::setVisible()}{setVisible()} slot. @@ -111,26 +117,26 @@ the status is true the widget is shown, otherwise the widget is hidden. - Since we made the \uicontrol More button checkable when we created it, - the connection makes sure that the extension widget is shown - depending on the state of \uicontrol More button. + Since the \uicontrol More button is checkable, the connection makes + sure that the extension widget is shown depending on the state of + the \uicontrol More button. - We also put the check boxes associated with the advanced - search options into a layout we install on the extension widget. + Create checkboxes associated with the advanced search options in + a layout installed on the extension widget. \snippet dialogs/extension/finddialog.cpp 4 - Before we create the main layout, we create several child layouts - for the widgets: First we align the QLabel and its buddy, the - QLineEdit, using a QHBoxLayout. Then we vertically align the - QLabel and QLineEdit with the check boxes associated with the - simple search, using a QVBoxLayout. We also create a QVBoxLayout - for the buttons. In the end we lay out the two latter layouts and - the extension widget using a QGridLayout. + Before creating the main layout, create several child layouts + for the widgets. First align the QLabel and its buddy, the + QLineEdit, using a QHBoxLayout. Then align the QLabel and the QLineEdit + vertically with the checkboxes associated with the simple search, + using a QVBoxLayout. Create also a QVBoxLayout for the buttons. + Finally, lay out the two latter layouts and the extension widget + using a QGridLayout. \snippet dialogs/extension/finddialog.cpp 5 - Finally, we hide the extension widget using the QWidget::hide() + Hide the extension widget using the QWidget::hide() function, making the application only show the simple search options when it starts. When the user wants to access the advanced search options, the dialog only needs to change the visibility of From c42be96d808de23f26d71a1c7f2dbeafbe251b92 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 12 Jun 2018 10:56:46 +0200 Subject: [PATCH 027/123] Fix QMAKE_MANIFEST for Visual Studio >= 2012 The QMAKE_MANIFEST variable was ignored for VS linkers that support the /MANIFEST:embed option. Task-number: QTBUG-59967 Change-Id: I1cdb60ec3a7a5f117942952d4632378ff142daa5 Reviewed-by: Oswald Buddenhagen --- qmake/generators/win32/msvc_nmake.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 680d3736c2c..92b4eb5054e 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -619,6 +619,8 @@ void NmakeMakefileGenerator::writeBuildRulesPart(QTextStream &t) } } else { manifest = fileFixify(manifest); + if (linkerSupportsEmbedding) + extraLFlags = "/MANIFEST:embed /MANIFESTINPUT:" + escapeFilePath(manifest); } const QString resourceId = (templateName == "app") ? "1" : "2"; From a93d29198a506b385a006e22538a24c2450c5278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 6 Jun 2018 16:51:00 +0200 Subject: [PATCH 028/123] Access private properties via sandbox-safe API on Apple OSes We detect whether or not we're running inside a sandbox and bail out if so. We use runtime lookup of the property, so that static analysis of the application will not mistakenly think we're using the API in sandboxed situations. Change-Id: I5f5c42f5a4a44b62de061d945b62ac63167ece09 Reviewed-by: Gabriel de Dietrich --- src/corelib/kernel/kernel.pri | 2 +- src/corelib/kernel/qcore_mac_objc.mm | 37 +++++++++++++++++++++++++ src/corelib/kernel/qcore_mac_p.h | 11 ++++++++ src/plugins/styles/mac/qmacstyle_mac.mm | 31 ++++++--------------- 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index ca8bd306983..c528b16f9cf 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -120,7 +120,7 @@ mac { LIBS_PRIVATE += -framework Foundation - osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit + osx: LIBS_PRIVATE += -framework CoreServices -framework AppKit -framework Security ios|tvos { # We need UIKit for UIApplication in qeventdispatcher_cf.mm diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 7263d812282..6b11e90a4e4 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -193,6 +193,43 @@ AppleApplication *qt_apple_sharedApplication() } #endif +#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) +bool qt_apple_isSandboxed() +{ + static bool isSandboxed = []() { + QCFType staticCode = nullptr; + NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL]; + if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl, + kSecCSDefaultFlags, &staticCode) != errSecSuccess) + return false; + + QCFType sandboxRequirement; + if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"), + kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess) + return false; + + if (SecStaticCodeCheckValidityWithErrors(staticCode, + kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess) + return false; + + return true; + }(); + return isSandboxed; +} + +QT_END_NAMESPACE +@implementation NSObject (QtSandboxHelpers) +- (id)qt_valueForPrivateKey:(NSString *)key +{ + if (qt_apple_isSandboxed()) + return nil; + + return [self valueForKey:key]; +} +@end +QT_BEGIN_NAMESPACE +#endif + #ifdef Q_OS_MACOS /* Ensure that Objective-C objects auto-released in main(), directly or indirectly, diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 9bd2e31bc9e..af939abaac2 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -160,6 +160,17 @@ QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool); Q_CORE_EXPORT void qt_apple_check_os_version(); Q_CORE_EXPORT bool qt_apple_isApplicationExtension(); +#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) +Q_CORE_EXPORT bool qt_apple_isSandboxed(); +# ifdef __OBJC__ +QT_END_NAMESPACE +@interface NSObject (QtSandboxHelpers) +- (id)qt_valueForPrivateKey:(NSString *)key; +@end +QT_BEGIN_NAMESPACE +# endif +#endif + #if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS) QT_END_NAMESPACE # if defined(Q_OS_MACOS) diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 5999163c917..2d212bfe3b3 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -248,24 +248,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView); } @end -#if !QT_CONFIG(appstore_compliant) - -// This API was requested to Apple in rdar #36197888. -// We know it's safe to use up to macOS 10.13.3. -// See drawComplexControl(CC_ComboBox) for its usage. - -@interface NSComboBoxCell (QtButtonCell) -@property (readonly) NSButtonCell *qt_buttonCell; -@end - -@implementation NSComboBoxCell (QtButtonCell) -- (NSButtonCell *)qt_buttonCell { - return self->_buttonCell; -} -@end - -#endif - QT_BEGIN_NAMESPACE // The following constants are used for adjusting the size @@ -5215,11 +5197,14 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex auto *cb = static_cast(cc); const auto frameRect = cw.adjustedControlFrame(combo->rect); cb.frame = frameRect.toCGRect(); -#if !QT_CONFIG(appstore_compliant) - static_cast(cc.cell).qt_buttonCell.highlighted = isPressed; -#else - // TODO Render to pixmap and darken the button manually -#endif + + // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3 + if (NSButtonCell *cell = static_cast([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) { + cell.highlighted = isPressed; + } else { + // TODO Render to pixmap and darken the button manually + } + d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef __unused ctx, const CGRect &r) { // FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case [cb.cell drawWithFrame:r inView:cb]; From f9b11bcf786eb3ab189f0402fd1b0f023910c2df Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 4 Jun 2018 15:57:05 +0200 Subject: [PATCH 029/123] QHeaderView: Send the StatusTip events to itself if there is no parent If there is a parent (typically an itemview) then StatusTip events should be sent to that. However in the case of there not being a parent then the event should be sent to the QHeaderView itself. Task-number: QTBUG-68458 Change-Id: I2a8c11c973210c7adf1bf29443f224f968a357a9 Reviewed-by: Richard Moe Gustavsen --- src/widgets/itemviews/qheaderview.cpp | 2 +- .../itemviews/qheaderview/tst_qheaderview.cpp | 65 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 00e9ff7400d..9a8206de45c 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2725,7 +2725,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) statusTip = d->model->headerData(logical, d->orientation, Qt::StatusTipRole).toString(); if (d->shouldClearStatusTip || !statusTip.isEmpty()) { QStatusTipEvent tip(statusTip); - QCoreApplication::sendEvent(d->parent, &tip); + QCoreApplication::sendEvent(d->parent ? d->parent : this, &tip); d->shouldClearStatusTip = !statusTip.isEmpty(); } #endif // !QT_NO_STATUSTIP diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index fd83228c8be..0dd98cf61cf 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -43,6 +43,7 @@ #include #include #include +#include typedef QList IntList; @@ -243,7 +244,7 @@ private slots: void testMinMaxSectionSize_data(); void testMinMaxSectionSize(); void sizeHintCrash(); - + void statusTips(); protected: void setupTestData(bool use_reset_model = false); void additionalInit(); @@ -269,7 +270,19 @@ public: int rowCount(const QModelIndex&) const { return rows; } int columnCount(const QModelIndex&) const { return cols; } bool isEditable(const QModelIndex &) const { return true; } - + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const + { + if (section < 0 || (role != Qt::DisplayRole && role != Qt::StatusTipRole)) + return QVariant(); + const int row = (orientation == Qt::Vertical ? section : 0); + const int col = (orientation == Qt::Horizontal ? section : 0); + if (orientation == Qt::Vertical && row >= rows) + return QVariant(); + if (orientation == Qt::Horizontal && col >= cols) + return QVariant(); + return QLatin1Char('[') + QString::number(row) + QLatin1Char(',') + + QString::number(col) + QLatin1String(",0] -- Header"); + } QVariant data(const QModelIndex &idx, int) const { if (idx.row() < 0 || idx.column() < 0 || idx.column() >= cols || idx.row() >= rows) { @@ -3325,6 +3338,54 @@ void tst_QHeaderView::testMinMaxSectionSize() QTRY_COMPARE(header.sectionSize(0), defaultSectionSize); } +class StatusTipHeaderView : public QHeaderView +{ +public: + StatusTipHeaderView(Qt::Orientation orientation = Qt::Horizontal, QWidget *parent = 0) : + QHeaderView(orientation, parent), gotStatusTipEvent(false) {} + bool gotStatusTipEvent; + QString statusTipText; +protected: + bool event(QEvent *e) + { + if (e->type() == QEvent::StatusTip) { + gotStatusTipEvent = true; + statusTipText = static_cast(e)->tip(); + } + return QHeaderView::event(e); + } +}; + +void tst_QHeaderView::statusTips() +{ + StatusTipHeaderView headerView; + QtTestModel model; + model.rows = model.cols = 5; + headerView.setModel(&model); + headerView.viewport()->setMouseTracking(true); + headerView.setGeometry(QRect(QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), + QSize(500, 500))); + headerView.show(); + qApp->setActiveWindow(&headerView); + QVERIFY(QTest::qWaitForWindowActive(&headerView)); + + // Ensure it is moved away first and then moved to the relevant section + QTest::mouseMove(QApplication::desktop(), + headerView.rect().bottomLeft() + QPoint(20, 20)); + QPoint centerPoint = QRect(headerView.sectionPosition(0), headerView.y(), + headerView.sectionSize(0), headerView.height()).center(); + QTest::mouseMove(headerView.windowHandle(), centerPoint); + QTRY_VERIFY(headerView.gotStatusTipEvent); + QCOMPARE(headerView.statusTipText, QLatin1String("[0,0,0] -- Header")); + + headerView.gotStatusTipEvent = false; + headerView.statusTipText.clear(); + centerPoint = QRect(headerView.sectionPosition(1), headerView.y(), + headerView.sectionSize(1), headerView.height()).center(); + QTest::mouseMove(headerView.windowHandle(), centerPoint); + QTRY_VERIFY(headerView.gotStatusTipEvent); + QCOMPARE(headerView.statusTipText, QLatin1String("[0,1,0] -- Header")); +} QTEST_MAIN(tst_QHeaderView) #include "tst_qheaderview.moc" From 6afd5990c79d86d4136b41018066c05c95d1b0d2 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 13 Jun 2018 12:14:19 +0200 Subject: [PATCH 030/123] QNativeSocketEnginePrivate (win) read sender's port and address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit even if recvmsg results in WSAEMSGSIZE. Task-number: QTBUG-68755 Change-Id: I418e924b3e9001e7b7ad991e32d7d6f89ae499af Reviewed-by: Edward Welbourne Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- src/network/socket/qnativesocketengine_win.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp index c303f016481..1b84b26d83d 100644 --- a/src/network/socket/qnativesocketengine_win.cpp +++ b/src/network/socket/qnativesocketengine_win.cpp @@ -1232,6 +1232,8 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxL // it is ok the buffer was to small if bytesRead is larger than // maxLength then assume bytes read is really maxLenth ret = qint64(bytesRead) > maxLength ? maxLength : qint64(bytesRead); + if (options & QNativeSocketEngine::WantDatagramSender) + qt_socket_getPortAndAddress(socketDescriptor, &aa, &header->senderPort, &header->senderAddress); } else { WS_ERROR_DEBUG(err); switch (err) { From 91f3687ee51db83d9018bd61c3fbc736c6e9912e Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 8 Jun 2018 17:37:49 +0200 Subject: [PATCH 031/123] Make QString's formatting of doubles be consistent with other places QString::sprintf(), like the C printf-family, always includes two digits in any exponent it outputs. Up to 5.6, number() and arg() taking a double did the same; but changes at 5.7 to enable opting out of the leading zero this implies for a single-digit exponent accidentally opted out of it in args() and number(). This commit fixes number() and arg() to include QLocaleData::ZeroPadExponent in the flags they pass down to the C locale's doubleToString(), restoring the prior behavior, including consistency with sprintf(). [ChangeLog][QtCore][QString] Formatting of doubles with single-digit exponent, by number() or args(), now includes a leading zero in that exponent, consistently with sprintf(), as it did up to 5.6. Task-number: QTBUG-63620 Change-Id: I10c491902b8556e9f19e605177ead8d9fd32abd9 Reviewed-by: Thiago Macieira Reviewed-by: Ulf Hermann --- src/corelib/tools/qstring.cpp | 14 +++++------ .../corelib/tools/qstring/tst_qstring.cpp | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a4b34263df8..3787c496b24 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -7414,13 +7414,12 @@ QString QString::number(qulonglong n, int base) QString QString::number(double n, char f, int prec) { QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - uint flags = 0; + uint flags = QLocaleData::ZeroPadExponent; if (qIsUpper(f)) - flags = QLocaleData::CapitalEorX; - f = qToLower(f); + flags |= QLocaleData::CapitalEorX; - switch (f) { + switch (qToLower(f)) { case 'f': form = QLocaleData::DFDecimal; break; @@ -8487,14 +8486,13 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha unsigned flags = QLocaleData::NoFlags; if (fillChar == QLatin1Char('0')) - flags = QLocaleData::ZeroPadded; + flags |= QLocaleData::ZeroPadded; if (qIsUpper(fmt)) flags |= QLocaleData::CapitalEorX; - fmt = qToLower(fmt); QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - switch (fmt) { + switch (qToLower(fmt)) { case 'f': form = QLocaleData::DFDecimal; break; @@ -8513,7 +8511,7 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha QString arg; if (d.occurrences > d.locale_occurrences) - arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags); + arg = QLocaleData::c()->doubleToString(a, prec, form, fieldWidth, flags | QLocaleData::ZeroPadExponent); QString locale_arg; if (d.locale_occurrences > 0) { diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 28014840a36..2074c9789a0 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -516,6 +516,7 @@ private slots: void toUcs4(); void arg(); void number(); + void doubleOut(); void arg_fillChar_data(); void arg_fillChar(); void capacity_data(); @@ -4882,6 +4883,28 @@ void tst_QString::number() #endif } +void tst_QString::doubleOut() +{ + // Regression test for QTBUG-63620; the first two paths lost the exponent's + // leading 0 at 5.7; C's printf() family guarantee a two-digit exponent (in + // contrast with ECMAScript, which forbids leading zeros). + const QString expect(QStringLiteral("1e-06")); + const double micro = 1e-6; + QCOMPARE(QString::number(micro), expect); + QCOMPARE(QString("%1").arg(micro), expect); + { + QString text; + text.sprintf("%g", micro); + QCOMPARE(text, expect); + } + { + QString text; + QTextStream stream(&text); + stream << micro; + QCOMPARE(text, expect); + } +} + void tst_QString::capacity_data() { length_data(); From d4a5ea2d4a367d01990dd3bd01631d2769d844f0 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Wed, 19 Oct 2016 13:13:10 +0200 Subject: [PATCH 032/123] tst_bench_QUuid: eliminate an unused variable Fixes a warning while compiling. Change-Id: I6d463d5ab6e95714fcf96a883577249593490380 Reviewed-by: Timur Pocheptsov --- tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp b/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp index 6a93391896e..b52654d1b46 100644 --- a/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/benchmarks/corelib/plugin/quuid/tst_quuid.cpp @@ -138,13 +138,12 @@ void tst_bench_QUuid::createUuidV5() void tst_bench_QUuid::toDataStream() { - QUuid uuid1, uuid2; - uuid1 = QUuid::createUuid(); + QUuid uuid = QUuid::createUuid(); QByteArray ar; { QDataStream out(&ar,QIODevice::WriteOnly); QBENCHMARK { - out << uuid1; + out << uuid; } } } From a834b4d24582ef318ea1de51b6707e9605e6c52f Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Thu, 14 Jun 2018 14:50:39 +0200 Subject: [PATCH 033/123] CMake: Restore qt5_use_modules() function It appears that in the 5 years since we deprecated this function, people have not stopped using it. The removal of qt5_use_modules() caused lots of troubles in packages still using it when they were compiled against Qt 5.11.0. Instead, let's revive this function and keep it for the Qt5 life time. See discussion on qt-development mailing list: http://lists.qt-project.org/pipermail/development/2018-June/032837.html Change-Id: Ic263e3bb6706268cb9ea38a0711665f166a3aa9e Reviewed-by: David Faure Reviewed-by: Thiago Macieira --- src/corelib/Qt5CoreMacros.cmake | 51 +++++++++++++++++++ tests/auto/cmake/CMakeLists.txt | 1 + .../test_use_modules_function/CMakeLists.txt | 18 +++++++ .../cmake/test_use_modules_function/three.cpp | 45 ++++++++++++++++ .../cmake/test_use_modules_function/two.cpp | 43 ++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 tests/auto/cmake/test_use_modules_function/CMakeLists.txt create mode 100644 tests/auto/cmake/test_use_modules_function/three.cpp create mode 100644 tests/auto/cmake/test_use_modules_function/two.cpp diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 1627de40029..819b48f9734 100644 --- a/src/corelib/Qt5CoreMacros.cmake +++ b/src/corelib/Qt5CoreMacros.cmake @@ -294,3 +294,54 @@ function(QT5_ADD_RESOURCES outfiles ) endfunction() set(_Qt5_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..") + +if (NOT CMAKE_VERSION VERSION_LESS 2.8.9) + macro(qt5_use_modules _target _link_type) + if(NOT CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.11) + if(CMAKE_WARN_DEPRECATED) + set(messageType WARNING) + endif() + if(CMAKE_ERROR_DEPRECATED) + set(messageType FATAL_ERROR) + endif() + if(messageType) + message(${messageType} "The qt5_use_modules macro is obsolete. Use target_link_libraries with IMPORTED targets instead.") + endif() + endif() + + if (NOT TARGET ${_target}) + message(FATAL_ERROR "The first argument to qt5_use_modules must be an existing target.") + endif() + if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE" ) + set(_qt5_modules ${ARGN}) + set(_qt5_link_type ${_link_type}) + else() + set(_qt5_modules ${_link_type} ${ARGN}) + endif() + + if ("${_qt5_modules}" STREQUAL "") + message(FATAL_ERROR "qt5_use_modules requires at least one Qt module to use.") + endif() + + foreach(_module ${_qt5_modules}) + if (NOT Qt5${_module}_FOUND) + find_package(Qt5${_module} PATHS "${_Qt5_COMPONENT_PATH}" NO_DEFAULT_PATH) + if (NOT Qt5${_module}_FOUND) + message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.") + endif() + endif() + target_link_libraries(${_target} ${_qt5_link_type} ${Qt5${_module}_LIBRARIES}) + set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${Qt5${_module}_INCLUDE_DIRS}) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${Qt5${_module}_COMPILE_DEFINITIONS}) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE QT_NO_DEBUG) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO QT_NO_DEBUG) + set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL QT_NO_DEBUG) + if (Qt5_POSITION_INDEPENDENT_CODE + AND (CMAKE_VERSION VERSION_LESS 2.8.12 + AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))) + set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE}) + endif() + endforeach() + endmacro() +endif() diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index f1d86570919..ec75ec7caf7 100644 --- a/tests/auto/cmake/CMakeLists.txt +++ b/tests/auto/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ find_package(Qt5Core REQUIRED) include("${_Qt5CTestMacros}") +expect_pass(test_use_modules_function) expect_pass(test_umbrella_config) expect_pass(test_wrap_cpp_and_resources) if (NOT NO_WIDGETS) diff --git a/tests/auto/cmake/test_use_modules_function/CMakeLists.txt b/tests/auto/cmake/test_use_modules_function/CMakeLists.txt new file mode 100644 index 00000000000..be05c75054c --- /dev/null +++ b/tests/auto/cmake/test_use_modules_function/CMakeLists.txt @@ -0,0 +1,18 @@ + +cmake_minimum_required(VERSION 2.8) + +project(test_use_modules_function) + +set(CMAKE_AUTOMOC ON) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +add_executable(two two.cpp) +add_executable(three three.cpp) + +find_package(Qt5Core) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") + +qt5_use_modules(two Test) +qt5_use_modules(three Gui Test) diff --git a/tests/auto/cmake/test_use_modules_function/three.cpp b/tests/auto/cmake/test_use_modules_function/three.cpp new file mode 100644 index 00000000000..507cc8479d0 --- /dev/null +++ b/tests/auto/cmake/test_use_modules_function/three.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +class Three : public QObject +{ + Q_OBJECT +public: + Three(QObject *parent = 0) + { + QWindow *w = new QWindow; + w->show(); + } +}; + +QTEST_MAIN(Three) + +#include "three.moc" diff --git a/tests/auto/cmake/test_use_modules_function/two.cpp b/tests/auto/cmake/test_use_modules_function/two.cpp new file mode 100644 index 00000000000..44eb7fe96e3 --- /dev/null +++ b/tests/auto/cmake/test_use_modules_function/two.cpp @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +class Two : public QObject +{ + Q_OBJECT +public: + Two(QObject *parent = 0) + { + + } +}; + +QTEST_MAIN(Two) + +#include "two.moc" From ae52029ec512f4c0e36371a488b72744ec641d73 Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Thu, 14 Jun 2018 08:49:45 +0200 Subject: [PATCH 034/123] xcb: add QT_XCB_NO_MITSHM envvar for disabling MIT-SHM extension We had something like this already in Qt4: QT_X11_NO_MITSHM The logic from 67227aeffdf94be8d177309d27291d5b3247586c not always works. There can still be cases that xcb_shm_attach_checked() returns with no errors on remote clients. Task-number: QTBUG-68783 Change-Id: Idd27ac66eb8f1114e3d1e1ddaaab2b00f235c561 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbconnection.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 8ed73bc2702..5fd1fc6a475 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -586,7 +586,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); - initializeShm(); + if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM")) + initializeShm(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) initializeXRandr(); if (!has_randr_extension) From 74305ba470f48da8b4c4e806fc714fe9f7649156 Mon Sep 17 00:00:00 2001 From: Antti Kokko Date: Fri, 8 Jun 2018 09:57:37 +0300 Subject: [PATCH 035/123] Add changes file for Qt 5.11.1 Done-with: Oswald Buddenhagen Edited-by: Thiago Macieira Edited-by: Richard Moe Gustavsen Change-Id: I5d626a5593d92c0977c1aee3ce60635d02938da1 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Thiago Macieira --- dist/changes-5.11.1 | 144 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 dist/changes-5.11.1 diff --git a/dist/changes-5.11.1 b/dist/changes-5.11.1 new file mode 100644 index 00000000000..ed219df454c --- /dev/null +++ b/dist/changes-5.11.1 @@ -0,0 +1,144 @@ +Qt 5.11.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.11 series is binary compatible with the 5.10.x series. +Applications compiled for 5.10 will continue to run with 5.11. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + + - [QTBUG-68619] In Qt 5.11.0, support for selecting a platform plugin + based on the XDG_SESSION_TYPE environment variable was added. On + gnome-shell, however, bugs—in both Qt and gnome-shell—made many + widget applications almost unusable. So until those bugs are fixed + XDG_SESSION_TYPE=wayland is now ignored on gnome-shell. + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + - Item Models: + * [QTBUG-18001] Fixed a bug that made selecting or deselecting a column if + some flags are applied to certain items. + * [QTBUG-44962][QTBUG-67948][QTBUG-68427] Fixed issues with the replacing + of the source model in QSortFilterProxyModel that could lead to empty + views or failed assertions. + + - QJsonDocument + * [QTBUG-61969] Fixed a number of bugs in the parsing of binary data + (QJson::fromRawData) that could lead to crashes or out-of-bounds access. + + - QLocale: + * On Unix, when using LANGUAGE would lose information about script or + country, without changing language, use the locale implied by LC_ALL, + LC_MESSAGES or LANG. + + - QPointF/QRectF: + * [QTBUG-60359][QTBUG-62161] Fixed an issue that led to inconsistent + comparison results for the different edges of a rectangle. + + - QProcess: + * [QTBUG-68472] On Unix, the QProcess SIGCHLD handler now restores errno + on exit. + * [QTBUG-67744] QProcess now properly reports an error state if it failed + to create the communication pipes. + + - QSharedPointer: + * [QTBUG-68300] Fixed a problem that made create() on a type with const + qualification fail to compile. + +QtNetwork +--------- + + - QNetworkCookieJar: + * [QTBUG-52040] Cookies will no longer be rejected when the domain + matches a TLD. However (to avoid problems with TLDs), such cookies are + only accepted, or sent, when the host name matches exactly. + +QtWidgets +--------- + + - [QTBUG-48325] Sending a key press event with sendEvent() now sends a + ShortCutOverride event first to the widget to trigger any shortcuts set + first. + - [QTBUG-67533] QOpenGLWidget/QQuickWidget is now respecting AlwaysStackOnTop. + - [QTBUG-60404] Fixed crash in QMacPanGestureRecognizer. + - [QTBUG-67836] Fixed input method commits that end with newline. + - [QTBUG-33855] Fixed issue with fonts in QHeaderViews + - [QTBUG-56457] Fixed margin issue related to sections in QHeaderView. + +**************************************************************************** +* Platform-specific Changes * +**************************************************************************** + +Android +------- + + - [QTBUG-68344] QTemporaryFile does not try to use O_TMPFILE any more, + to work around outdated sandbox restrictions of linkat(). This also fixes + use of QSettings and QFile::copy(). + +Linux +----- + + - [QTBUG-68586] Fixed a bug that caused QFileSystemWatcher to print a warning + if the file being watched did not exist. The class is documented to return + the list of files that it could not watch. + +macOS +----- + + - [QTBUG-60676] Fixed a bug in using QFileSystemWatcher to watch different + file paths that shared a common prefix. + +Windows +------- + + - [QTBUG-68514] Reverted a change that caused static binaries compiled + with Visual Studio 2015 to crash on start-up. Note that this does not + apply to Visual Studio 2017 static binaries, even though the crash stack + traces are very similar: with 2017, the problem is compiler regression + and requires updating to version 15.8 for the fix. + +**************************************************************************** +* Tools * +**************************************************************************** + +configure & build system +------------------------ + + - [QTBUG-68478] Fixed parallel build of examples in some modules. + +qmake +----- + + - [QTBUG-37417][CMake] Fixed missing include paths in private modules. + - [QTBUG-47325] Fixed crash when $QMAKEFEATURES contains empty paths + (e.g., due to a trailing colon). + - [QTBUG-52474][Xcode] Fixed sources being excluded from Time Machine + backups. + - [QTBUG-66462][Darwin] Fixed overriding QMAKE_TARGET_BUNDLE_PREFIX in + project files. + - [QTBUG-68705][Xcode] Fixed build directory location of app bundles. + - [Xcode] Fixed compatibility with Xcode 10 by opting out from the new + build system. + - [Darwin] Fixed .prl file lookup for suffixed frameworks. + - Fixed look-up of relative files from extra compilers' .depend_command + in shadow builds. From cd02eb5b2090a8e263642ce900de9160e60f7d0f Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 15 Jun 2018 12:11:11 +0200 Subject: [PATCH 036/123] ibase: Silence warning about incompatible function types This correctly silents the warning about incompatible function types, it amends the previous fix - 6108d8f515d7911427b764647f1d6ab487ad5203 Task-number: QTBUG-68330 Change-Id: I9eda42817740f491b16ac19c553f35fb1c7aa755 Reviewed-by: Jesus Fernandez Reviewed-by: Ville Voutilainen --- src/plugins/sqldrivers/ibase/qsql_ibase.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index 484dad6e1dd..ead08dbce8a 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp +++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp @@ -1845,9 +1845,11 @@ bool QIBaseDriver::subscribeToNotification(const QString &name) eBuffer->bufferLength, eBuffer->eventBuffer, #if defined (FB_API_VER) && FB_API_VER >= 20 - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #else - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #endif eBuffer->resultBuffer); @@ -1925,9 +1927,11 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer) eBuffer->bufferLength, eBuffer->eventBuffer, #if defined (FB_API_VER) && FB_API_VER >= 20 - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #else - reinterpret_cast(qEventCallback), + reinterpret_cast(reinterpret_cast + (&qEventCallback)), #endif eBuffer->resultBuffer); if (Q_UNLIKELY(status[0] == 1 && status[1])) { From be37b9984605d9a6503b074e78acf612adb4ec43 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 5 Jun 2018 16:57:46 -0700 Subject: [PATCH 037/123] Doc: Point to the SG-10 SD-6 as a requirement for C++14 feature Task-number: QTBUG-68702 Change-Id: I04b94079b6da48f39a82fffd153568f8dab3ef1b Reviewed-by: Ville Voutilainen Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/corelib/global/qglobal.cpp | 5 +++++ src/corelib/kernel/qdeadlinetimer.cpp | 5 +++++ src/corelib/tools/qbytearraymatcher.cpp | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 605683b8523..f60e47928c9 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1037,6 +1037,11 @@ Q_STATIC_ASSERT((std::is_same::value)); \snippet code/src_corelib_global_qglobal.cpp 53 + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa qConstOverload(), qNonConstOverload(), {Differences between String-Based and Functor-Based Connections} */ diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp index d8a670310b0..4b9a946dd84 100644 --- a/src/corelib/kernel/qdeadlinetimer.cpp +++ b/src/corelib/kernel/qdeadlinetimer.cpp @@ -345,6 +345,11 @@ void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::Time deadline.setRemainingTime(250ms); \endcode + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa setDeadline(), remainingTime(), hasExpired(), isForever() */ diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp index 06d01f98297..96c2394dbd8 100644 --- a/src/corelib/tools/qbytearraymatcher.cpp +++ b/src/corelib/tools/qbytearraymatcher.cpp @@ -366,6 +366,11 @@ int qFindByteArray( Since this class is designed to do all the up-front calculations at compile-time, it does not offer a setPattern() method. + \note Qt detects the necessary C++14 compiler support by way of the feature + test recommendations from + \l{https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations} + {C++ Committee's Standing Document 6}. + \sa QByteArrayMatcher, QStringMatcher */ From b6421f9dd0c01d6c274a2dbedd79ba19b43f28c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 18 Jun 2018 13:02:10 +0200 Subject: [PATCH 038/123] Add macOS Mojave (10.14) to QOperatingSystemVersion Change-Id: I7dd53c9894b7d6ce4e41bf548e6ce0a17c3f3020 Reviewed-by: Gabriel de Dietrich --- src/corelib/global/qoperatingsystemversion.cpp | 8 ++++++++ src/corelib/global/qoperatingsystemversion.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp index 4d267e328d2..2f8d339ca7f 100644 --- a/src/corelib/global/qoperatingsystemversion.cpp +++ b/src/corelib/global/qoperatingsystemversion.cpp @@ -437,6 +437,14 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSSierra = const QOperatingSystemVersion QOperatingSystemVersion::MacOSHighSierra = QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 13); +/*! + \variable QOperatingSystemVersion::MacOSMojave + \brief a version corresponding to macOS Mojave (version 10.14). + \since 5.11.2 + */ +const QOperatingSystemVersion QOperatingSystemVersion::MacOSMojave = + QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14); + /*! \variable QOperatingSystemVersion::AndroidJellyBean \brief a version corresponding to Android Jelly Bean (version 4.1, API level 16). diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h index 5f27deab9e8..df01e5438a9 100644 --- a/src/corelib/global/qoperatingsystemversion.h +++ b/src/corelib/global/qoperatingsystemversion.h @@ -70,6 +70,7 @@ public: static const QOperatingSystemVersion OSXElCapitan; static const QOperatingSystemVersion MacOSSierra; static const QOperatingSystemVersion MacOSHighSierra; + static const QOperatingSystemVersion MacOSMojave; static const QOperatingSystemVersion AndroidJellyBean; static const QOperatingSystemVersion AndroidJellyBean_MR1; From d0acd26c37c7b98612308e47e635b792949d7210 Mon Sep 17 00:00:00 2001 From: Romain Pokrzywka Date: Mon, 18 Jun 2018 19:01:05 +0200 Subject: [PATCH 039/123] Fix evdevtouch input plugin crash when the device can't be opened If a device fails to open during the plugin startup, we exit the handler constructor early and leave the d member as nullptr. However the recently added m_handler->isFiltered() call after m_handler is instantiated assumes that d is always valid, which triggers a crash in the forementionned situation. Fix it to check for d's validity first. This can occur when a device is connected then disconnected right after, so that it's gone by the time we get the notification from udev. Change-Id: Ia755868338f92b91c181be8557e06e087d70fcc6 Reviewed-by: Laszlo Agocs --- src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index 7b7649bc5c0..f3cc160b3e9 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -368,7 +368,7 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() bool QEvdevTouchScreenHandler::isFiltered() const { - return d->m_filtered; + return d && d->m_filtered; } QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const From 67bbe59a373b169b550400187891f6f73a1c00b5 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 14 Jun 2018 14:05:12 +0200 Subject: [PATCH 040/123] Make some QEXPECT_FAIL()s consistent in form and content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They used different messages for the same excuse, which weren't well worded in any case; and their #if-ery was differently decorated. Change-Id: I28f5032693aff1036cb086ac4032c669110a5cb5 Reviewed-by: Mårten Nordheim --- tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index f8432b84721..7d16ec7fbbc 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -2697,14 +2697,14 @@ void tst_QDateTime::timeZoneAbbreviation() // Time definitely in Standard Time QDateTime dt4(QDate(2013, 1, 1), QTime(0, 0, 0), Qt::LocalTime); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); -#endif // Q_OS_WIN + QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); +#endif QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET")); // Time definitely in Daylight Time QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "Windows only returns long name (QTBUG-32759)", Continue); -#endif // Q_OS_WIN + QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); +#endif QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST")); } else { QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); @@ -2712,12 +2712,12 @@ void tst_QDateTime::timeZoneAbbreviation() QDateTime dt5(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); + QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif QCOMPARE(dt5.timeZoneAbbreviation(), QString("CET")); QDateTime dt6(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN - QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); + QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif QCOMPARE(dt6.timeZoneAbbreviation(), QString("CEST")); } From e08ba34f26197fb9893fd48a38bdd0dfff7d4a60 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 14 Jun 2018 14:07:23 +0200 Subject: [PATCH 041/123] Cope with Android's lack of time-zone abbreviations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have a test expect what it does produce rather than fail what we can't fix. Task-number: QTBUG-68837 Change-Id: Icda7bd9968682daf97d46d597f8bb0433560cde2 Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- .../corelib/tools/qdatetime/tst_qdatetime.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 7d16ec7fbbc..867ca52d6f2 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -2699,27 +2699,35 @@ void tst_QDateTime::timeZoneAbbreviation() #ifdef Q_OS_WIN QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); #endif - QCOMPARE(dt4.timeZoneAbbreviation(), QString("CET")); + QCOMPARE(dt4.timeZoneAbbreviation(), QStringLiteral("CET")); // Time definitely in Daylight Time QDateTime dt5(QDate(2013, 6, 1), QTime(0, 0, 0), Qt::LocalTime); #ifdef Q_OS_WIN QEXPECT_FAIL("", "Windows only reports long name (QTBUG-32759)", Continue); #endif - QCOMPARE(dt5.timeZoneAbbreviation(), QString("CEST")); + QCOMPARE(dt5.timeZoneAbbreviation(), QStringLiteral("CEST")); } else { QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); } +#ifdef Q_OS_ANDROID // Only reports (general) zones as offsets (QTBUG-68837) + const QString cet(QStringLiteral("GMT+01:00")); + const QString cest(QStringLiteral("GMT+02:00")); +#else + const QString cet(QStringLiteral("CET")); + const QString cest(QStringLiteral("CEST")); +#endif + QDateTime dt5(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif - QCOMPARE(dt5.timeZoneAbbreviation(), QString("CET")); + QCOMPARE(dt5.timeZoneAbbreviation(), cet); QDateTime dt6(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "Windows only reports long names (QTBUG-32759)", Continue); #endif - QCOMPARE(dt6.timeZoneAbbreviation(), QString("CEST")); + QCOMPARE(dt6.timeZoneAbbreviation(), cest); } void tst_QDateTime::getDate() From b248a35a090585dc81b52b3113a3a6a2926b9c50 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 14 Jun 2018 12:36:41 +0200 Subject: [PATCH 042/123] Add Android to exceptions in tst_QDateTime::toString_textDate_extra() Android doesn't use the proper zone-abbreviation, so just check it starts with the right date-time. Revised the way the #if-ery for that is handled, to avoid repetition of the (now more complex) condition in the two tests affected. Task-number: QTBUG-68833 Change-Id: Iceb5469f46c69ba5cdbaf7ca050ad70f2bb74f44 Reviewed-by: Thiago Macieira --- tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 867ca52d6f2..e9d2fba47f6 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -924,12 +924,16 @@ void tst_QDateTime::toString_textDate_extra() else QCOMPARE(dt.toString(), QLatin1String("Thu Jan 1 00:00:00 1970")); #if QT_CONFIG(timezone) +# if defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID +# define CORRECT_ZONE_ABBREV +# endif // QTBUG-57320, QTBUG-57298, QTBUG-68833 + QTimeZone PST("America/Vancouver"); if (PST.isValid()) { dt = QDateTime::fromMSecsSinceEpoch(0, PST); -# if defined Q_OS_UNIX && !defined Q_OS_DARWIN +# ifdef CORRECT_ZONE_ABBREV QCOMPARE(dt.toString(), QLatin1String("Wed Dec 31 16:00:00 1969 PST")); -# else // QTBUG-57320, QTBUG-57298 +# else QVERIFY(dt.toString().startsWith(QLatin1String("Wed Dec 31 16:00:00 1969 "))); # endif dt = dt.toLocalTime(); @@ -940,9 +944,9 @@ void tst_QDateTime::toString_textDate_extra() QTimeZone CET("Europe/Berlin"); if (CET.isValid()) { dt = QDateTime::fromMSecsSinceEpoch(0, CET); -# if defined Q_OS_UNIX && !defined Q_OS_DARWIN +# ifdef CORRECT_ZONE_ABBREV QCOMPARE(dt.toString(), QLatin1String("Thu Jan 1 01:00:00 1970 CET")); -# else // QTBUG-57320, QTBUG-57298 +# else QVERIFY(dt.toString().startsWith(QLatin1String("Thu Jan 1 01:00:00 1970 "))); # endif dt = dt.toLocalTime(); From 9f8938b89a67ff8da148b7b865576a3d5584c610 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Thu, 14 Jun 2018 12:18:20 +0200 Subject: [PATCH 043/123] Cope if mktime() deems times in a spring forward gap to be invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tst_QDateTime::springForward(), we test correct handling of times in the gap; these are formally invalid and a mktime() implementation may reasonably reject them causing our date-time code to produce an invalid result. So handle that case gracefully in the tests, only insisting on consistency between the two ways of preparing the date. In one test, package the repeated code I was going to adapt into a macro to save repeitition. Task-number: QTBUG-68832 Task-number: QTBUG-68839 Change-Id: Ib8a16ff007f4e75ab2ccff05b1ccf00a45e50dc8 Reviewed-by: Thiago Macieira Reviewed-by: Mårten Nordheim --- .../corelib/tools/qdatetime/tst_qdatetime.cpp | 62 +++++++++++-------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index e9d2fba47f6..4e77ff9461c 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -1868,12 +1868,14 @@ void tst_QDateTime::springForward() QFETCH(int, adjust); QDateTime direct = QDateTime(day.addDays(-step), time, Qt::LocalTime).addDays(step); - QCOMPARE(direct.date(), day); - QCOMPARE(direct.time().minute(), time.minute()); - QCOMPARE(direct.time().second(), time.second()); - int off = direct.time().hour() - time.hour(); - QVERIFY(off == 1 || off == -1); - // Note: function doc claims always +1, but this should be reviewed ! + if (direct.isValid()) { // mktime() may deem a time in the gap invalid + QCOMPARE(direct.date(), day); + QCOMPARE(direct.time().minute(), time.minute()); + QCOMPARE(direct.time().second(), time.second()); + int off = direct.time().hour() - time.hour(); + QVERIFY(off == 1 || off == -1); + // Note: function doc claims always +1, but this should be reviewed ! + } // Repeat, but getting there via .toLocalTime(): QDateTime detour = QDateTime(day.addDays(-step), @@ -1881,7 +1883,11 @@ void tst_QDateTime::springForward() Qt::UTC).toLocalTime(); QCOMPARE(detour.time(), time); detour = detour.addDays(step); - QCOMPARE(detour, direct); // Insist on consistency. + // Insist on consistency: + if (direct.isValid()) + QCOMPARE(detour, direct); + else + QVERIFY(!detour.isValid()); } void tst_QDateTime::operator_eqeq_data() @@ -2901,38 +2907,40 @@ void tst_QDateTime::daylightTransitions() const QCOMPARE(utc.date(), QDate(2012, 3, 25)); QCOMPARE(utc.time(), QTime(2, 0, 0)); - // Test date maths, if result falls in missing hour then becomes next hour + // Test date maths, if result falls in missing hour then becomes next + // hour (or is always invalid; mktime() may reject gap-times). QDateTime test(QDate(2011, 3, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addYears(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + const bool handled = test.isValid(); +#define CHECK_SPRING_FORWARD(test) \ + if (test.isValid()) { \ + QCOMPARE(test.date(), QDate(2012, 3, 25)); \ + QCOMPARE(test.time(), QTime(3, 0, 0)); \ + } else { \ + QVERIFY(!handled); \ + } + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 2, 25), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addMonths(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 24), QTime(2, 0, 0)); QVERIFY(test.isValid()); test = test.addDays(1); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); + CHECK_SPRING_FORWARD(test); test = QDateTime(QDate(2012, 3, 25), QTime(1, 0, 0)); QVERIFY(test.isValid()); QCOMPARE(test.toMSecsSinceEpoch(), daylight2012 - msecsOneHour); test = test.addMSecs(msecsOneHour); - QVERIFY(test.isValid()); - QCOMPARE(test.date(), QDate(2012, 3, 25)); - QCOMPARE(test.time(), QTime(3, 0, 0)); - QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); - + CHECK_SPRING_FORWARD(test); + if (handled) + QCOMPARE(test.toMSecsSinceEpoch(), daylight2012); +#undef CHECK_SPRING_FORWARD // Test for correct behviour for DaylightTime -> StandardTime transition, i.e. second occurrence @@ -2954,7 +2962,7 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(msecBefore.isValid()); QCOMPARE(msecBefore.date(), QDate(2012, 10, 28)); QCOMPARE(msecBefore.time(), QTime(2, 59, 59, 999)); -#if defined(Q_OS_MAC) || defined(Q_OS_WIN) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_WIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Win and Mac uses SecondOccurrence here QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_MAC @@ -2976,8 +2984,8 @@ void tst_QDateTime::daylightTransitions() const QVERIFY(afterTran.isValid()); QCOMPARE(afterTran.date(), QDate(2012, 10, 28)); QCOMPARE(afterTran.time(), QTime(2, 59, 59, 999)); -#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_QNX) - // Linux mktime bug uses last calculation +#ifdef __GLIBCXX__ + // Linux (i.e. glibc) mktime bug reuses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_UNIX QCOMPARE(afterTran.toMSecsSinceEpoch(), standard2012 + msecsOneHour - 1); @@ -3183,12 +3191,12 @@ void tst_QDateTime::daylightTransitions() const test = test.addMSecs(msecsOneHour); QVERIFY(test.isValid()); QCOMPARE(test.date(), QDate(2012, 10, 28)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN QCOMPARE(test.time(), QTime(3, 0, 0)); -#if defined(Q_OS_MAC) || defined(Q_OS_QNX) +#if defined(Q_OS_DARWIN) || defined(Q_OS_QNX) || defined(Q_OS_ANDROID) // Mac uses FirstOccurrence, Windows uses SecondOccurrence, Linux uses last calculation QEXPECT_FAIL("", "QDateTime doesn't properly support Daylight Transitions", Continue); #endif // Q_OS_WIN From 6af262b6d76ba5dc6d1fa7d7abea460039fea6b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Wed, 13 Jun 2018 15:52:59 +0200 Subject: [PATCH 044/123] Move androiddeployqt to qtbase androiddeploytqt is the only official way of deploying applications to the device, so it is therefore part of the "platform". It therefore needs to live in qtbase. Change-Id: I52d7c4427275aacec792b71284a0c10edaf7ab69 Reviewed-by: Frederik Gladhorn --- src/src.pro | 10 + src/tools/androiddeployqt/androiddeployqt.pro | 14 + src/tools/androiddeployqt/main.cpp | 2909 +++++++++++++++++ 3 files changed, 2933 insertions(+) create mode 100644 src/tools/androiddeployqt/androiddeployqt.pro create mode 100644 src/tools/androiddeployqt/main.cpp diff --git a/src/src.pro b/src/src.pro index 1f7c5d99c1c..1c76a2e46f0 100644 --- a/src/src.pro +++ b/src/src.pro @@ -53,6 +53,10 @@ src_tools_qdbuscpp2xml.target = sub-qdbuscpp2xml force_bootstrap: src_tools_qdbuscpp2xml.depends = src_tools_bootstrap_dbus else: src_tools_qdbuscpp2xml.depends = src_dbus +src_tools_androiddeployqt.subdir = tools/androiddeployqt +src_tools_androiddeployqt.target = sub-androiddeployqt +src_tools_androiddeployqt.depends = src_corelib + src_tools_qvkgen.subdir = tools/qvkgen src_tools_qvkgen.target = sub-qvkgen force_bootstrap: src_tools_qvkgen.depends = src_tools_bootstrap @@ -183,6 +187,12 @@ qtConfig(dbus) { src_platformsupport.depends += src_dbus src_tools_qdbusxml2cpp src_plugins.depends += src_dbus src_tools_qdbusxml2cpp src_tools_qdbuscpp2xml } + +android { + SUBDIRS += src_tools_androiddeployqt + TOOLS += src_tools_androiddeployqt +} + qtConfig(concurrent): SUBDIRS += src_concurrent qtConfig(gui) { qtConfig(harfbuzz):!qtConfig(system-harfbuzz) { diff --git a/src/tools/androiddeployqt/androiddeployqt.pro b/src/tools/androiddeployqt/androiddeployqt.pro new file mode 100644 index 00000000000..2d0f5b41d19 --- /dev/null +++ b/src/tools/androiddeployqt/androiddeployqt.pro @@ -0,0 +1,14 @@ +option(host_build) +CONFIG += console + +SOURCES += \ + main.cpp + +# Required for declarations of popen/pclose on Windows +windows: QMAKE_CXXFLAGS += -U__STRICT_ANSI__ + +DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII +DEFINES += QT_NO_FOREACH + +load(qt_app) + diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp new file mode 100644 index 00000000000..f00188396d6 --- /dev/null +++ b/src/tools/androiddeployqt/main.cpp @@ -0,0 +1,2909 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +static const bool mustReadOutputAnyway = true; // pclose seems to return the wrong error code unless we read the output + +void deleteRecursively(const QString &dirName) +{ + QDir dir(dirName); + if (!dir.exists()) + return; + + const QFileInfoList entries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &entry : entries) { + if (entry.isDir()) + deleteRecursively(entry.absoluteFilePath()); + else + QFile::remove(entry.absoluteFilePath()); + } + + QDir().rmdir(dirName); +} + +FILE *openProcess(const QString &command) +{ +#if defined(Q_OS_WIN32) + QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"'); +#else + QString processedCommand = command; +#endif + + return popen(processedCommand.toLocal8Bit().constData(), "r"); +} + +struct QtDependency +{ + QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {} + + bool operator==(const QtDependency &other) const + { + return relativePath == other.relativePath && absolutePath == other.absolutePath; + } + + QString relativePath; + QString absolutePath; +}; + +struct Options +{ + Options() + : helpRequested(false) + , verbose(false) + , timing(false) + , generateAssetsFileList(true) + , build(true) + , gradle(false) + , deploymentMechanism(Bundled) + , releasePackage(false) + , digestAlg(QLatin1String("SHA1")) + , sigAlg(QLatin1String("SHA1withRSA")) + , internalSf(false) + , sectionsOnly(false) + , protectedAuthenticationPath(false) + , jarSigner(false) + , gdbServer(Auto) + , installApk(false) + , uninstallApk(false) + {} + + enum DeploymentMechanism + { + Bundled, + Ministro + }; + + enum TriState { + Auto, + False, + True + }; + + bool helpRequested; + bool verbose; + bool timing; + bool generateAssetsFileList; + bool build; + bool gradle; + QTime timer; + + // External tools + QString sdkPath; + QString sdkBuildToolsVersion; + QString ndkPath; + QString antTool; + QString jdkPath; + + // Build paths + QString qtInstallDirectory; + QString androidSourceDirectory; + QString outputDirectory; + QString inputFileName; + QString applicationBinary; + QString rootPath; + QStringList qmlImportPaths; + + // lib c++ path + QString stdCppPath; + QString stdCppName = QStringLiteral("gnustl_shared"); + + // Build information + QString androidPlatform; + QString architecture; + QString toolchainVersion; + QString toolchainPrefix; + QString toolPrefix; + QString ndkHost; + + // Package information + DeploymentMechanism deploymentMechanism; + QString packageName; + QStringList extraLibs; + QStringList extraPlugins; + + // Signing information + bool releasePackage; + QString keyStore; + QString keyStorePassword; + QString keyStoreAlias; + QString storeType; + QString keyPass; + QString sigFile; + QString signedJar; + QString digestAlg; + QString sigAlg; + QString tsaUrl; + QString tsaCert; + bool internalSf; + bool sectionsOnly; + bool protectedAuthenticationPath; + bool jarSigner; + + // Gdbserver + TriState gdbServer; + + // Installation information + bool installApk; + bool uninstallApk; + QString installLocation; + + // Collected information + typedef QPair BundledFile; + QList bundledFiles; + QList qtDependencies; + QStringList localLibs; + QStringList localJars; + QStringList initClasses; + QStringList permissions; + QStringList features; +}; + +// Copy-pasted from qmake/library/ioutil.cpp +inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16]) +{ + for (int x = arg.length() - 1; x >= 0; --x) { + ushort c = arg.unicode()[x].unicode(); + if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7)))) + return true; + } + return false; +} + +static QString shellQuoteUnix(const QString &arg) +{ + // Chars that should be quoted (TM). This includes: + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8, + 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78 + }; // 0-32 \'"$`<>|;&(){}*?#!~[] + + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + if (hasSpecialChars(ret, iqm)) { + ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); + ret.prepend(QLatin1Char('\'')); + ret.append(QLatin1Char('\'')); + } + return ret; +} + +static QString shellQuoteWin(const QString &arg) +{ + // Chars that should be quoted (TM). This includes: + // - control chars & space + // - the shell meta chars "&()<>^| + // - the potential separators ,;= + static const uchar iqm[] = { + 0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10 + }; + + if (!arg.length()) + return QString::fromLatin1("\"\""); + + QString ret(arg); + if (hasSpecialChars(ret, iqm)) { + // Quotes are escaped and their preceding backslashes are doubled. + // It's impossible to escape anything inside a quoted string on cmd + // level, so the outer quoting must be "suspended". + ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\"")); + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + int i = ret.length(); + while (i > 0 && ret.at(i - 1) == QLatin1Char('\\')) + --i; + ret.insert(i, QLatin1Char('"')); + ret.prepend(QLatin1Char('"')); + } + return ret; +} + +static QString shellQuote(const QString &arg) +{ + if (QDir::separator() == QLatin1Char('\\')) + return shellQuoteWin(arg); + else + return shellQuoteUnix(arg); +} + + +void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir) +{ + if (options.verbose) + fprintf(stdout, "Delete missing files %s %s\n", qPrintable(srcDir.absolutePath()), qPrintable(dstDir.absolutePath())); + + const QFileInfoList srcEntries = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + const QFileInfoList dstEntries = dstDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &dst : dstEntries) { + bool found = false; + for (const QFileInfo &src : srcEntries) + if (dst.fileName() == src.fileName()) { + if (dst.isDir()) + deleteMissingFiles(options, src.absoluteFilePath(), dst.absoluteFilePath()); + found = true; + break; + } + + if (!found) { + if (options.verbose) + fprintf(stdout, "%s not found in %s, removing it.\n", qPrintable(dst.fileName()), qPrintable(srcDir.absolutePath())); + + if (dst.isDir()) + deleteRecursively(dst.absolutePath()); + else + QFile::remove(dst.absoluteFilePath()); + } + } + fflush(stdout); +} + + +Options parseOptions() +{ + Options options; + + QStringList arguments = QCoreApplication::arguments(); + for (int i=0; i= arguments.size()) { + options.helpRequested = true; + } else { + options.releasePackage = true; + options.keyStore = arguments.at(++i); + options.keyStoreAlias = arguments.at(++i); + } + } else if (argument.compare(QLatin1String("--storepass"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.keyStorePassword = arguments.at(++i); + } else if (argument.compare(QLatin1String("--storetype"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.storeType = arguments.at(++i); + } else if (argument.compare(QLatin1String("--keypass"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.keyPass = arguments.at(++i); + } else if (argument.compare(QLatin1String("--sigfile"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.sigFile = arguments.at(++i); + } else if (argument.compare(QLatin1String("--digestalg"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.digestAlg = arguments.at(++i); + } else if (argument.compare(QLatin1String("--sigalg"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.sigAlg = arguments.at(++i); + } else if (argument.compare(QLatin1String("--tsa"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.tsaUrl = arguments.at(++i); + } else if (argument.compare(QLatin1String("--tsacert"), Qt::CaseInsensitive) == 0) { + if (i + 1 == arguments.size()) + options.helpRequested = true; + else + options.tsaCert = arguments.at(++i); + } else if (argument.compare(QLatin1String("--internalsf"), Qt::CaseInsensitive) == 0) { + options.internalSf = true; + } else if (argument.compare(QLatin1String("--sectionsonly"), Qt::CaseInsensitive) == 0) { + options.sectionsOnly = true; + } else if (argument.compare(QLatin1String("--protected"), Qt::CaseInsensitive) == 0) { + options.protectedAuthenticationPath = true; + } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) { + options.jarSigner = true; + } else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) { + options.generateAssetsFileList = false; + } + } + + if (options.inputFileName.isEmpty()) + options.inputFileName = QString::fromLatin1("android-lib%1.so-deployment-settings.json").arg(QDir::current().dirName()); + + options.timing = qEnvironmentVariableIsSet("ANDROIDDEPLOYQT_TIMING_OUTPUT"); + + if (!QDir::current().mkpath(options.outputDirectory)) { + fprintf(stderr, "Invalid output directory: %s\n", qPrintable(options.outputDirectory)); + options.outputDirectory.clear(); + } else { + options.outputDirectory = QFileInfo(options.outputDirectory).canonicalFilePath(); + if (!options.outputDirectory.endsWith(QLatin1Char('/'))) + options.outputDirectory += QLatin1Char('/'); + } + + return options; +} + +void printHelp() +{// "012345678901234567890123456789012345678901234567890123456789012345678901" + fprintf(stderr, "Syntax: %s --output [options]\n" + "\n" + " Creates an Android package in the build directory and\n" + " builds it into an .apk file.\n\n" + " Optional arguments:\n" + " --input : Reads for options generated by\n" + " qmake. A default file name based on the current working\n" + " directory will be used if nothing else is specified.\n" + " --deployment : Supported deployment mechanisms:\n" + " bundled (default): Include Qt files in stand-alone package.\n" + " ministro: Use the Ministro service to manage Qt files.\n" + " --no-build: Do not build the package, it is useful to just install\n" + " a package previously built.\n" + " --install: Installs apk to device/emulator. By default this step is\n" + " not taken. If the application has previously been installed on\n" + " the device, it will be uninstalled first.\n" + " --reinstall: Installs apk to device/emulator. By default this step\n" + " is not taken. If the application has previously been installed on\n" + " the device, it will be overwritten, but its data will be left\n" + " intact.\n" + " --device [device ID]: Use specified device for deployment. Default\n" + " is the device selected by default by adb.\n" + " --android-platform : Builds against the given android\n" + " platform. By default, the highest available version will be\n" + " used.\n" + " --gradle. Use gradle instead of ant to create and install the apk.\n" + " --ant : If unspecified, ant from the PATH will be\n" + " used.\n" + " --release: Builds a package ready for release. By default, the\n" + " package will be signed with a debug key.\n" + " --sign : Signs the package with the\n" + " specified keystore, alias and store password. Also implies the\n" + " --release option.\n" + " Optional arguments for use with signing:\n" + " --storepass : Keystore password.\n" + " --storetype : Keystore type.\n" + " --keypass : Password for private key (if different\n" + " from keystore password.)\n" + " --sigfile : Name of .SF/.DSA file.\n" + " --digestalg : Name of digest algorithm. Default is\n" + " \"SHA1\".\n" + " --sigalg : Name of signature algorithm. Default is\n" + " \"SHA1withRSA\".\n" + " --tsa : Location of the Time Stamping Authority.\n" + " --tsacert : Public key certificate for TSA.\n" + " --internalsf: Include the .SF file inside the signature block.\n" + " --sectionsonly: Don't compute hash of entire manifest.\n" + " --protected: Keystore has protected authentication path.\n" + " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n" + " used if available.\n" + " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n" + " is bundled for debug pacakges.\n" + " --no-gdbserver: Prevents the gdbserver from being added to the package\n" + " By default the gdbserver is bundled for debug pacakges.\n" + " --jdk : Used to find the jarsigner tool when used\n" + " in combination with the --release argument. By default,\n" + " an attempt is made to detect the tool using the JAVA_HOME and\n" + " PATH environment variables, in that order.\n" + " --qml-import-paths: Specify additional search paths for QML\n" + " imports.\n" + " --verbose: Prints out information during processing.\n" + " --no-generated-assets-cache: Do not pregenerate the entry list for\n" + " the assets file engine.\n" + " --help: Displays this information.\n\n", + qPrintable(QCoreApplication::arguments().at(0)) + ); +} + +// Since strings compared will all start with the same letters, +// sorting by length and then alphabetically within each length +// gives the natural order. +bool quasiLexicographicalReverseLessThan(const QFileInfo &fi1, const QFileInfo &fi2) +{ + QString s1 = fi1.baseName(); + QString s2 = fi2.baseName(); + + if (s1.length() == s2.length()) + return s1 > s2; + else + return s1.length() > s2.length(); +} + +// Files which contain templates that need to be overwritten by build data should be overwritten every +// time. +bool alwaysOverwritableFile(const QString &fileName) +{ + return (fileName.endsWith(QLatin1String("/res/values/libs.xml")) + || fileName.endsWith(QLatin1String("/AndroidManifest.xml")) + || fileName.endsWith(QLatin1String("/res/values/strings.xml")) + || fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java"))); +} + +bool copyFileIfNewer(const QString &sourceFileName, + const QString &destinationFileName, + bool verbose, + bool forceOverwrite = false) +{ + if (QFile::exists(destinationFileName)) { + QFileInfo destinationFileInfo(destinationFileName); + QFileInfo sourceFileInfo(sourceFileName); + + if (!forceOverwrite + && sourceFileInfo.lastModified() <= destinationFileInfo.lastModified() + && !alwaysOverwritableFile(destinationFileName)) { + if (verbose) + fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName)); + return true; + } else { + if (!QFile(destinationFileName).remove()) { + fprintf(stderr, "Can't remove old file: %s\n", qPrintable(destinationFileName)); + return false; + } + } + } + + if (!QDir().mkpath(QFileInfo(destinationFileName).path())) { + fprintf(stderr, "Cannot make output directory for %s.\n", qPrintable(destinationFileName)); + return false; + } + + if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) { + fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName)); + return false; + } else if (verbose) { + fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName)); + fflush(stdout); + } + + return true; +} + +QString cleanPackageName(QString packageName) +{ + QRegExp legalChars(QLatin1String("[a-zA-Z0-9_\\.]")); + + for (int i = 0; i < packageName.length(); ++i) { + if (!legalChars.exactMatch(packageName.mid(i, 1))) + packageName[i] = QLatin1Char('_'); + } + + static QStringList keywords; + if (keywords.isEmpty()) { + keywords << QLatin1String("abstract") << QLatin1String("continue") << QLatin1String("for") + << QLatin1String("new") << QLatin1String("switch") << QLatin1String("assert") + << QLatin1String("default") << QLatin1String("if") << QLatin1String("package") + << QLatin1String("synchronized") << QLatin1String("boolean") << QLatin1String("do") + << QLatin1String("goto") << QLatin1String("private") << QLatin1String("this") + << QLatin1String("break") << QLatin1String("double") << QLatin1String("implements") + << QLatin1String("protected") << QLatin1String("throw") << QLatin1String("byte") + << QLatin1String("else") << QLatin1String("import") << QLatin1String("public") + << QLatin1String("throws") << QLatin1String("case") << QLatin1String("enum") + << QLatin1String("instanceof") << QLatin1String("return") << QLatin1String("transient") + << QLatin1String("catch") << QLatin1String("extends") << QLatin1String("int") + << QLatin1String("short") << QLatin1String("try") << QLatin1String("char") + << QLatin1String("final") << QLatin1String("interface") << QLatin1String("static") + << QLatin1String("void") << QLatin1String("class") << QLatin1String("finally") + << QLatin1String("long") << QLatin1String("strictfp") << QLatin1String("volatile") + << QLatin1String("const") << QLatin1String("float") << QLatin1String("native") + << QLatin1String("super") << QLatin1String("while"); + } + + // No keywords + int index = -1; + while (index < packageName.length()) { + int next = packageName.indexOf(QLatin1Char('.'), index + 1); + if (next == -1) + next = packageName.length(); + QString word = packageName.mid(index + 1, next - index - 1); + if (!word.isEmpty()) { + QChar c = word[0]; + if ((c >= QChar(QLatin1Char('0')) && c<= QChar(QLatin1Char('9'))) + || c == QLatin1Char('_')) { + packageName.insert(index + 1, QLatin1Char('a')); + index = next + 1; + continue; + } + } + if (keywords.contains(word)) { + packageName.insert(next, QLatin1String("_")); + index = next + 1; + } else { + index = next; + } + } + + return packageName; +} + +QString detectLatestAndroidPlatform(const QString &sdkPath) +{ + QDir dir(sdkPath + QLatin1String("/platforms")); + if (!dir.exists()) { + fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath())); + return QString(); + } + + QFileInfoList fileInfos = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + if (fileInfos.isEmpty()) { + fprintf(stderr, "No platforms found in %s", qPrintable(dir.absolutePath())); + return QString(); + } + + std::sort(fileInfos.begin(), fileInfos.end(), quasiLexicographicalReverseLessThan); + + QFileInfo latestPlatform = fileInfos.first(); + return latestPlatform.baseName(); +} + +QString packageNameFromAndroidManifest(const QString &androidManifestPath) +{ + QFile androidManifestXml(androidManifestPath); + if (androidManifestXml.open(QIODevice::ReadOnly)) { + QXmlStreamReader reader(&androidManifestXml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == QLatin1String("manifest")) + return cleanPackageName( + reader.attributes().value(QLatin1String("package")).toString()); + } + } + return QString(); +} + +bool readInputFile(Options *options) +{ + QFile file(options->inputFileName); + if (!file.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot read from input file: %s\n", qPrintable(options->inputFileName)); + return false; + } + + QJsonDocument jsonDocument = QJsonDocument::fromJson(file.readAll()); + if (jsonDocument.isNull()) { + fprintf(stderr, "Invalid json file: %s\n", qPrintable(options->inputFileName)); + return false; + } + + QJsonObject jsonObject = jsonDocument.object(); + + { + QJsonValue sdkPath = jsonObject.value(QLatin1String("sdk")); + if (sdkPath.isUndefined()) { + fprintf(stderr, "No SDK path in json file %s\n", qPrintable(options->inputFileName)); + return false; + } + + options->sdkPath = sdkPath.toString(); + + if (options->androidPlatform.isEmpty()) { + options->androidPlatform = detectLatestAndroidPlatform(options->sdkPath); + if (options->androidPlatform.isEmpty()) + return false; + } else { + if (!QDir(options->sdkPath + QLatin1String("/platforms/") + options->androidPlatform).exists()) { + fprintf(stderr, "Warning: Android platform '%s' does not exist in SDK.\n", + qPrintable(options->androidPlatform)); + } + } + } + + { + + const QJsonValue value = jsonObject.value(QStringLiteral("sdkBuildToolsRevision")); + if (!value.isUndefined()) + options->sdkBuildToolsVersion = value.toString(); + } + + { + const QJsonValue qtInstallDirectory = jsonObject.value(QStringLiteral("qt")); + if (qtInstallDirectory.isUndefined()) { + fprintf(stderr, "No Qt directory in json file %s\n", qPrintable(options->inputFileName)); + return false; + } + options->qtInstallDirectory = qtInstallDirectory.toString(); + } + + { + const QJsonValue androidSourcesDirectory = jsonObject.value(QStringLiteral("android-package-source-directory")); + if (!androidSourcesDirectory.isUndefined()) + options->androidSourceDirectory = androidSourcesDirectory.toString(); + } + + { + const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary")); + if (applicationBinary.isUndefined()) { + fprintf(stderr, "No application binary defined in json file.\n"); + return false; + } + options->applicationBinary = applicationBinary.toString(); + + if (!QFile::exists(options->applicationBinary)) { + fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary)); + return false; + } + } + + { + const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies")); + if (!deploymentDependencies.isUndefined()) { + QString deploymentDependenciesString = deploymentDependencies.toString(); + const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(',')); + for (const QStringRef &dependency : dependencies) { + QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency; + if (QFileInfo(path).isDir()) { + QDirIterator iterator(path, QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + if (iterator.fileInfo().isFile()) { + QString subPath = iterator.filePath(); + options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1), + subPath)); + } + } + } else { + options->qtDependencies.append(QtDependency(dependency.toString(), path)); + } + } + } + } + + + { + const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture")); + if (targetArchitecture.isUndefined()) { + fprintf(stderr, "No target architecture defined in json file.\n"); + return false; + } + options->architecture = targetArchitecture.toString(); + } + + { + const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk")); + if (ndk.isUndefined()) { + fprintf(stderr, "No NDK path defined in json file.\n"); + return false; + } + options->ndkPath = ndk.toString(); + } + + { + const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix")); + if (toolchainPrefix.isUndefined()) { + fprintf(stderr, "No toolchain prefix defined in json file.\n"); + return false; + } + options->toolchainPrefix = toolchainPrefix.toString(); + } + + { + const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix")); + if (toolPrefix.isUndefined()) { + fprintf(stderr, "Warning: No tool prefix defined in json file.\n"); + options->toolPrefix = options->toolchainPrefix; + } else { + options->toolPrefix = toolPrefix.toString(); + } + } + + { + const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version")); + if (toolchainVersion.isUndefined()) { + fprintf(stderr, "No toolchain version defined in json file.\n"); + return false; + } + options->toolchainVersion = toolchainVersion.toString(); + } + + { + const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host")); + if (ndkHost.isUndefined()) { + fprintf(stderr, "No NDK host defined in json file.\n"); + return false; + } + options->ndkHost = ndkHost.toString(); + } + + options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml")); + if (options->packageName.isEmpty()) + options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1))); + + { + const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs")); + if (!extraLibs.isUndefined()) + options->extraLibs = extraLibs.toString().split(QLatin1Char(','), QString::SkipEmptyParts); + } + + { + const QJsonValue extraPlugins = jsonObject.value(QStringLiteral("android-extra-plugins")); + if (!extraPlugins.isUndefined()) + options->extraPlugins = extraPlugins.toString().split(QLatin1Char(',')); + } + + { + const QJsonValue stdcppPath = jsonObject.value(QStringLiteral("stdcpp-path")); + if (!stdcppPath.isUndefined()) { + options->stdCppPath = stdcppPath.toString(); + auto name = QFileInfo(options->stdCppPath).baseName(); + if (!name.startsWith(QLatin1String("lib"))) { + fprintf(stderr, "Invalid STD C++ library name.\n"); + return false; + } + options->stdCppName = name.mid(3); + } + } + + { + const QJsonValue qmlRootPath = jsonObject.value(QStringLiteral("qml-root-path")); + if (!qmlRootPath.isUndefined()) + options->rootPath = qmlRootPath.toString(); + } + + { + const QJsonValue qmlImportPaths = jsonObject.value(QStringLiteral("qml-import-paths")); + if (!qmlImportPaths.isUndefined()) + options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(',')); + } + return true; +} + +bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false) +{ + const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + for (const QFileInfo &entry : entries) { + if (entry.isDir()) { + QDir dir(entry.absoluteFilePath()); + if (!destinationDirectory.mkpath(dir.dirName())) { + fprintf(stderr, "Cannot make directory %s in %s\n", qPrintable(dir.dirName()), qPrintable(destinationDirectory.path())); + return false; + } + + if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite)) + return false; + } else { + QString destination = destinationDirectory.absoluteFilePath(entry.fileName()); + if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite)) + return false; + } + } + + return true; +} + +void cleanTopFolders(const Options &options, const QDir &srcDir, const QString &dstDir) +{ + const auto dirs = srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Dirs); + for (const QFileInfo &dir : dirs) { + if (dir.fileName() != QLatin1String("libs")) + deleteMissingFiles(options, dir.absoluteFilePath(), dstDir + dir.fileName()); + } +} + +void cleanAndroidFiles(const Options &options) +{ + if (!options.androidSourceDirectory.isEmpty()) + cleanTopFolders(options, options.androidSourceDirectory, options.outputDirectory); + + cleanTopFolders(options, options.qtInstallDirectory + QLatin1String("/src/android/templates"), options.outputDirectory); +} + +bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, const QString &outDirPrefix = QString()) +{ + QDir sourceDirectory(options.qtInstallDirectory + androidTemplate); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath())); + return false; + } + + QString outDir = options.outputDirectory + outDirPrefix; + + if (!QDir::current().mkpath(outDir)) { + fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(outDir), options.verbose); +} + +bool copyGradleTemplate(const Options &options) +{ + QDir sourceDirectory(options.qtInstallDirectory + QLatin1String("/src/3rdparty/gradle")); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find template directory %s\n", qPrintable(sourceDirectory.absolutePath())); + return false; + } + + QString outDir(options.outputDirectory); + if (!QDir::current().mkpath(outDir)) { + fprintf(stderr, "Cannot create output directory %s\n", qPrintable(options.outputDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(outDir), options.verbose); +} + +bool copyAndroidTemplate(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Copying Android package template.\n"); + + if (options.gradle && !copyGradleTemplate(options)) + return false; + + if (!copyAndroidTemplate(options, QLatin1String("/src/android/templates"))) + return false; + + if (options.gradle) + return true; + + return copyAndroidTemplate(options, QLatin1String("/src/android/java")); +} + +bool copyAndroidSources(const Options &options) +{ + if (options.androidSourceDirectory.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying Android sources from project.\n"); + + QDir sourceDirectory(options.androidSourceDirectory); + if (!sourceDirectory.exists()) { + fprintf(stderr, "Cannot find android sources in %s", qPrintable(options.androidSourceDirectory)); + return false; + } + + return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true); +} + +bool copyAndroidExtraLibs(const Options &options) +{ + if (options.extraLibs.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size()); + + for (const QString &extraLib : options.extraLibs) { + QFileInfo extraLibInfo(extraLib); + if (!extraLibInfo.exists()) { + fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib)); + return false; + } + + if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) { + fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n", + qPrintable(extraLib)); + return false; + } + + QString destinationFile(options.outputDirectory + + QLatin1String("/libs/") + + options.architecture + + QLatin1Char('/') + + extraLibInfo.fileName()); + + if (!copyFileIfNewer(extraLib, destinationFile, options.verbose)) + return false; + } + + return true; +} + +QStringList allFilesInside(const QDir& current, const QDir& rootDir) +{ + QStringList result; + const auto dirs = current.entryList(QDir::Dirs|QDir::NoDotAndDotDot); + const auto files = current.entryList(QDir::Files); + result.reserve(dirs.size() + files.size()); + for (const QString &dir : dirs) { + result += allFilesInside(QDir(current.filePath(dir)), rootDir); + } + for (const QString &file : files) { + result += rootDir.relativeFilePath(current.filePath(file)); + } + return result; +} + +bool copyAndroidExtraResources(const Options &options) +{ + if (options.extraPlugins.isEmpty()) + return true; + + if (options.verbose) + fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size()); + + for (const QString &extraResource : options.extraPlugins) { + QFileInfo extraResourceInfo(extraResource); + if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) { + fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource)); + return false; + } + + QDir resourceDir(extraResource); + QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/'); + QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/'); + + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &resourceFile : files) { + QString originFile(resourceDir.filePath(resourceFile)); + QString destinationFile; + if (!resourceFile.endsWith(QLatin1String(".so"))) { + destinationFile = assetsDir + resourceFile; + } else { + destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_')); + } + + if (!copyFileIfNewer(originFile, destinationFile, options.verbose)) + return false; + } + } + + return true; +} + +bool updateFile(const QString &fileName, const QHash &replacements) +{ + QFile inputFile(fileName); + if (!inputFile.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName)); + return false; + } + + // All the files we are doing substitutes in are quite small. If this + // ever changes, this code should be updated to be more conservative. + QByteArray contents = inputFile.readAll(); + + bool hasReplacements = false; + QHash::const_iterator it; + for (it = replacements.constBegin(); it != replacements.constEnd(); ++it) { + if (it.key() == it.value()) + continue; // Nothing to actually replace + + forever { + int index = contents.indexOf(it.key().toUtf8()); + if (index >= 0) { + contents.replace(index, it.key().length(), it.value().toUtf8()); + hasReplacements = true; + } else { + break; + } + } + } + + if (hasReplacements) { + inputFile.close(); + + if (!inputFile.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Cannot open %s for writing.\n", qPrintable(fileName)); + return false; + } + + inputFile.write(contents); + } + + return true; + +} + +bool updateLibsXml(const Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- res/values/libs.xml\n"); + + QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml"); + if (!QFile::exists(fileName)) { + fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName)); + return false; + } + + QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/'); + + QString qtLibs = QLatin1String("") + options.stdCppName + QLatin1String("\n"); + QString bundledInLibs; + QString bundledInAssets; + for (const Options::BundledFile &bundledFile : options.bundledFiles) { + if (bundledFile.second.startsWith(QLatin1String("lib/"))) { + QString s = bundledFile.second.mid(sizeof("lib/lib") - 1); + s.chop(sizeof(".so") - 1); + qtLibs += QString::fromLatin1("%1\n").arg(s); + } else if (bundledFile.first.startsWith(libsPath)) { + QString s = bundledFile.first.mid(libsPath.length()); + bundledInLibs += QString::fromLatin1("%1:%2\n") + .arg(s).arg(bundledFile.second); + } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) { + QString s = bundledFile.first.mid(sizeof("assets/") - 1); + bundledInAssets += QString::fromLatin1("%1:%2\n") + .arg(s).arg(bundledFile.second); + } + } + + if (!options.extraPlugins.isEmpty()) { + for (const QString &extraRes : options.extraPlugins) { + QDir resourceDir(extraRes); + const QStringList files = allFilesInside(resourceDir, resourceDir); + for (const QString &file : files) { + QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file; + if (!file.endsWith(QLatin1String(".so"))) { + bundledInAssets += QStringLiteral("%1:%1\n") + .arg(destinationPath); + } else { + bundledInLibs += QStringLiteral("lib%1:%2\n") + .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_'))) + .arg(destinationPath); + } + } + } + } + + QHash replacements; + replacements[QLatin1String("")] = qtLibs; + + if (options.deploymentMechanism == Options::Bundled) { + replacements[QLatin1String("")] = bundledInLibs; + replacements[QLatin1String("")] = bundledInAssets; + } + + QString extraLibs; + if (!options.extraLibs.isEmpty()) { + for (const QString extraLib : options.extraLibs) { + QFileInfo extraLibInfo(extraLib); + QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1); + name.chop(sizeof(".so") - 1); + + extraLibs += QLatin1String("") + name + QLatin1String("\n"); + } + } + replacements[QLatin1String("")] = extraLibs; + + if (!updateFile(fileName, replacements)) + return false; + + return true; +} + +bool updateStringsXml(const Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- res/values/strings.xml\n"); + + QHash replacements; + replacements[QStringLiteral("")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + + QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml"); + if (!QFile::exists(fileName)) { + if (options.verbose) + fprintf(stdout, " -- Create strings.xml since it's missing.\n"); + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Can't open %s for writing.\n", qPrintable(fileName)); + return false; + } + file.write(QByteArray("") + .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1()) + .append("\n")); + return true; + } + + if (!updateFile(fileName, replacements)) + return false; + + if (options.gradle) + return true; + + // ant can't (easily) build multiple res folders, + // so we need to replace the "" placeholder + // from the main res folder + QFile stringsXml(fileName); + if (!stringsXml.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(fileName)); + return false; + } + + QXmlStreamReader reader(&stringsXml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && + reader.name() == QLatin1String("string") && + reader.attributes().hasAttribute(QLatin1String("name")) && + reader.attributes().value(QLatin1String("name")) == QLatin1String("app_name")) { + return true; + } + } + + replacements.clear(); + replacements[QStringLiteral("")] = QString::fromLatin1("%1\n") + .arg(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1)); + + if (!updateFile(fileName, replacements)) + return false; + + return true; +} + +bool updateAndroidManifest(Options &options) +{ + if (options.verbose) + fprintf(stdout, " -- AndroidManifest.xml \n"); + + QStringList localLibs = options.localLibs; + + // If .pro file overrides dependency detection, we need to see which platform plugin they picked + if (localLibs.isEmpty()) { + QString plugin; + for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { + if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so")) + || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) { + if (!plugin.isEmpty() && plugin != qtDependency.relativePath) { + fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n"); + return false; + } + + plugin = qtDependency.relativePath; + } + } + + if (plugin.isEmpty()) { + fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n"); + return false; + } + + localLibs.append(plugin); + if (options.verbose) + fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin)); + } + + bool usesGL = false; + for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) { + if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so")) + || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) { + usesGL = true; + break; + } + } + + QHash replacements; + replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1); + replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':')); + replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':')); + replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':')); + replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName); + replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")] + = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0"); + + QString permissions; + for (const QString &permission : qAsConst(options.permissions)) + permissions += QString::fromLatin1(" \n").arg(permission); + replacements[QLatin1String("")] = permissions; + + QString features; + for (const QString &feature : qAsConst(options.features)) + features += QStringLiteral(" \n").arg(feature); + if (usesGL) + features += QStringLiteral(" "); + + replacements[QLatin1String("")] = features; + + QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml"); + if (!updateFile(androidManifestPath, replacements)) + return false; + + // read the package, min & target sdk API levels from manifest file. + bool checkOldAndroidLabelString = false; + QFile androidManifestXml(androidManifestPath); + if (androidManifestXml.exists()) { + if (!androidManifestXml.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidManifestPath)); + return false; + } + + QXmlStreamReader reader(&androidManifestXml); + while (!reader.atEnd()) { + reader.readNext(); + + if (reader.isStartElement()) { + if (reader.name() == QLatin1String("manifest")) { + if (!reader.attributes().hasAttribute(QLatin1String("package"))) { + fprintf(stderr, "Invalid android manifest file: %s\n", qPrintable(androidManifestPath)); + return false; + } + options.packageName = reader.attributes().value(QLatin1String("package")).toString(); + } else if (reader.name() == QLatin1String("uses-sdk")) { + if (reader.attributes().hasAttribute(QLatin1String("android:minSdkVersion"))) + if (reader.attributes().value(QLatin1String("android:minSdkVersion")).toInt() < 16) { + fprintf(stderr, "Invalid minSdkVersion version, minSdkVersion must be >= 16\n"); + return false; + } + } else if ((reader.name() == QLatin1String("application") || + reader.name() == QLatin1String("activity")) && + reader.attributes().hasAttribute(QLatin1String("android:label")) && + reader.attributes().value(QLatin1String("android:label")) == QLatin1String("@string/app_name")) { + checkOldAndroidLabelString = true; + } + } + } + + if (reader.hasError()) { + fprintf(stderr, "Error in %s: %s\n", qPrintable(androidManifestPath), qPrintable(reader.errorString())); + return false; + } + } else { + fprintf(stderr, "No android manifest file"); + return false; + } + + if (checkOldAndroidLabelString) + updateStringsXml(options); + + return true; +} + +bool updateAndroidFiles(Options &options) +{ + if (options.verbose) + fprintf(stdout, "Updating Android package files with project settings.\n"); + + if (!updateLibsXml(options)) + return false; + + if (!updateAndroidManifest(options)) + return false; + + return true; +} + +QList findFilesRecursively(const Options &options, const QFileInfo &info, const QString &rootPath) +{ + if (!info.exists()) + return QList(); + + if (info.isDir()) { + QList ret; + + QDir dir(info.filePath()); + const QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + + for (const QString &entry : entries) { + QString s = info.absoluteFilePath() + QLatin1Char('/') + entry; + ret += findFilesRecursively(options, s, rootPath); + } + + return ret; + } else { + return QList() << QtDependency(info.absoluteFilePath().mid(rootPath.length()), info.absoluteFilePath()); + } +} + +QList findFilesRecursively(const Options &options, const QString &fileName) +{ + QFileInfo info(options.qtInstallDirectory + QLatin1Char('/') + fileName); + return findFilesRecursively(options, info, options.qtInstallDirectory + QLatin1Char('/')); +} + +bool readAndroidDependencyXml(Options *options, + const QString &moduleName, + QSet *usedDependencies, + QSet *remainingDependencies) +{ + QString androidDependencyName = options->qtInstallDirectory + QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName); + + QFile androidDependencyFile(androidDependencyName); + if (androidDependencyFile.exists()) { + if (options->verbose) + fprintf(stdout, "Reading Android dependencies for %s\n", qPrintable(moduleName)); + + if (!androidDependencyFile.open(QIODevice::ReadOnly)) { + fprintf(stderr, "Cannot open %s for reading.\n", qPrintable(androidDependencyName)); + return false; + } + + QXmlStreamReader reader(&androidDependencyFile); + while (!reader.atEnd()) { + reader.readNext(); + + if (reader.isStartElement()) { + if (reader.name() == QLatin1String("bundled")) { + if (!reader.attributes().hasAttribute(QLatin1String("file"))) { + fprintf(stderr, "Invalid android dependency file: %s\n", qPrintable(androidDependencyName)); + return false; + } + + QString file = reader.attributes().value(QLatin1String("file")).toString(); + + // Special case, since this is handled by qmlimportscanner instead + if (!options->rootPath.isEmpty() && (file == QLatin1String("qml") || file == QLatin1String("qml/"))) + continue; + + const QList fileNames = findFilesRecursively(*options, file); + for (const QtDependency &fileName : fileNames) { + if (usedDependencies->contains(fileName.absolutePath)) + continue; + + usedDependencies->insert(fileName.absolutePath); + + if (options->verbose) + fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath)); + + options->qtDependencies.append(fileName); + } + } else if (reader.name() == QLatin1String("jar")) { + int bundling = reader.attributes().value(QLatin1String("bundling")).toInt(); + QString fileName = reader.attributes().value(QLatin1String("file")).toString(); + if (bundling == (options->deploymentMechanism == Options::Bundled)) { + QtDependency dependency(fileName, options->qtInstallDirectory + QLatin1Char('/') + fileName); + if (!usedDependencies->contains(dependency.absolutePath)) { + options->qtDependencies.append(dependency); + usedDependencies->insert(dependency.absolutePath); + } + } + + if (!fileName.isEmpty()) + options->localJars.append(fileName); + + if (reader.attributes().hasAttribute(QLatin1String("initClass"))) { + options->initClasses.append(reader.attributes().value(QLatin1String("initClass")).toString()); + } + } else if (reader.name() == QLatin1String("lib")) { + QString fileName = reader.attributes().value(QLatin1String("file")).toString(); + if (reader.attributes().hasAttribute(QLatin1String("replaces"))) { + QString replaces = reader.attributes().value(QLatin1String("replaces")).toString(); + for (int i=0; ilocalLibs.size(); ++i) { + if (options->localLibs.at(i) == replaces) { + options->localLibs[i] = fileName; + break; + } + } + } else if (!fileName.isEmpty()) { + options->localLibs.append(fileName); + } + if (fileName.endsWith(QLatin1String(".so"))) { + remainingDependencies->insert(fileName); + } + } else if (reader.name() == QLatin1String("permission")) { + QString name = reader.attributes().value(QLatin1String("name")).toString(); + options->permissions.append(name); + } else if (reader.name() == QLatin1String("feature")) { + QString name = reader.attributes().value(QLatin1String("name")).toString(); + options->features.append(name); + } + } + } + + if (reader.hasError()) { + fprintf(stderr, "Error in %s: %s\n", qPrintable(androidDependencyName), qPrintable(reader.errorString())); + return false; + } + } else if (options->verbose) { + fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName)); + } + + return true; +} + +QStringList getQtLibsFromElf(const Options &options, const QString &fileName) +{ + QString readElf = options.ndkPath + + QLatin1String("/toolchains/") + + options.toolchainPrefix + + QLatin1Char('-') + + options.toolchainVersion + + QLatin1String("/prebuilt/") + + options.ndkHost + + QLatin1String("/bin/") + + options.toolPrefix + + QLatin1String("-readelf"); +#if defined(Q_OS_WIN32) + readElf += QLatin1String(".exe"); +#endif + + if (!QFile::exists(readElf)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf)); + return QStringList(); + } + + readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf)).arg(shellQuote(fileName)); + + FILE *readElfCommand = openProcess(readElf); + if (readElfCommand == 0) { + fprintf(stderr, "Cannot execute command %s", qPrintable(readElf)); + return QStringList(); + } + + QStringList ret; + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) { + QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer)); + if (line.contains("(NEEDED)") && line.contains("Shared library:") ) { + const int pos = line.lastIndexOf('[') + 1; + QString libraryName = QLatin1String("lib/") + QString::fromLatin1(line.mid(pos, line.length() - pos - 2)); + if (QFile::exists(options.qtInstallDirectory + QLatin1Char('/') + libraryName)) { + ret += libraryName; + } + + } + } + + pclose(readElfCommand); + + return ret; +} + +bool readDependenciesFromElf(Options *options, + const QString &fileName, + QSet *usedDependencies, + QSet *remainingDependencies) +{ + // Get dependencies on libraries in $QTDIR/lib + const QStringList dependencies = getQtLibsFromElf(*options, fileName); + + if (options->verbose) { + fprintf(stdout, "Reading dependencies from %s\n", qPrintable(fileName)); + for (const QString &dep : dependencies) + fprintf(stdout, " %s\n", qPrintable(dep)); + } + // Recursively add dependencies from ELF and supplementary XML information + QList dependenciesToCheck; + for (const QString &dependency : dependencies) { + if (usedDependencies->contains(dependency)) + continue; + + QString absoluteDependencyPath(options->qtInstallDirectory + QLatin1Char('/') + dependency); + usedDependencies->insert(dependency); + if (!readDependenciesFromElf(options, + absoluteDependencyPath, + usedDependencies, + remainingDependencies)) { + return false; + } + + options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath)); + if (options->verbose) + fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency)); + dependenciesToCheck.append(dependency); + } + + for (const QString &dependency : qAsConst(dependenciesToCheck)) { + QString qtBaseName = dependency.mid(sizeof("lib/lib") - 1); + qtBaseName = qtBaseName.left(qtBaseName.size() - (sizeof(".so") - 1)); + if (!readAndroidDependencyXml(options, qtBaseName, usedDependencies, remainingDependencies)) { + return false; + } + } + + return true; +} + +bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies); + +bool scanImports(Options *options, QSet *usedDependencies) +{ + if (options->verbose) + fprintf(stdout, "Scanning for QML imports.\n"); + + QString qmlImportScanner = options->qtInstallDirectory + QLatin1String("/bin/qmlimportscanner"); +#if defined(Q_OS_WIN32) + qmlImportScanner += QLatin1String(".exe"); +#endif + + if (!QFile::exists(qmlImportScanner)) { + fprintf(stderr, "qmlimportscanner not found: %s\n", qPrintable(qmlImportScanner)); + return true; + } + + QString rootPath = options->rootPath; + if (rootPath.isEmpty()) + rootPath = QFileInfo(options->inputFileName).absolutePath(); + else + rootPath = QFileInfo(rootPath).absoluteFilePath(); + + if (!rootPath.endsWith(QLatin1Char('/'))) + rootPath += QLatin1Char('/'); + + QStringList importPaths; + importPaths += shellQuote(options->qtInstallDirectory + QLatin1String("/qml")); + importPaths += rootPath; + for (const QString &qmlImportPath : qAsConst(options->qmlImportPaths)) + importPaths += shellQuote(qmlImportPath); + + qmlImportScanner += QString::fromLatin1(" -rootPath %1 -importPath %2") + .arg(shellQuote(rootPath)) + .arg(importPaths.join(QLatin1Char(' '))); + + FILE *qmlImportScannerCommand = popen(qmlImportScanner.toLocal8Bit().constData(), "r"); + if (qmlImportScannerCommand == 0) { + fprintf(stderr, "Couldn't run qmlimportscanner.\n"); + return false; + } + + QByteArray output; + char buffer[512]; + while (fgets(buffer, sizeof(buffer), qmlImportScannerCommand) != 0) + output += QByteArray(buffer, qstrlen(buffer)); + + QJsonDocument jsonDocument = QJsonDocument::fromJson(output); + if (jsonDocument.isNull()) { + fprintf(stderr, "Invalid json output from qmlimportscanner.\n"); + return false; + } + + QJsonArray jsonArray = jsonDocument.array(); + for (int i=0; iverbose) + fprintf(stdout, " -- Adding '%s' as QML dependency\n", path.toLocal8Bit().constData()); + + QFileInfo info(path); + + // The qmlimportscanner sometimes outputs paths that do not exist. + if (!info.exists()) { + if (options->verbose) + fprintf(stdout, " -- Skipping because file does not exist.\n"); + continue; + } + + QString absolutePath = info.absolutePath(); + if (!absolutePath.endsWith(QLatin1Char('/'))) + absolutePath += QLatin1Char('/'); + + if (absolutePath.startsWith(rootPath)) { + if (options->verbose) + fprintf(stdout, " -- Skipping because file is in QML root path.\n"); + continue; + } + + QString importPathOfThisImport; + for (const QString &importPath : qAsConst(importPaths)) { +#if defined(Q_OS_WIN32) + Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; +#endif + QString cleanImportPath = QDir::cleanPath(importPath); + if (info.absoluteFilePath().startsWith(cleanImportPath, caseSensitivity)) { + importPathOfThisImport = importPath; + break; + } + } + + if (importPathOfThisImport.isEmpty()) { + fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath())); + return false; + } + + QDir dir(importPathOfThisImport); + importPathOfThisImport = dir.absolutePath() + QLatin1Char('/'); + + const QList fileNames = findFilesRecursively(*options, info, importPathOfThisImport); + for (QtDependency fileName : fileNames) { + if (usedDependencies->contains(fileName.absolutePath)) + continue; + + usedDependencies->insert(fileName.absolutePath); + + if (options->verbose) + fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath)); + + // Put all imports in default import path in assets + fileName.relativePath.prepend(QLatin1String("qml/")); + options->qtDependencies.append(fileName); + + if (fileName.absolutePath.endsWith(QLatin1String(".so"))) { + QSet remainingDependencies; + if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies)) + return false; + + } + } + } + } + + return true; +} + +bool readDependencies(Options *options) +{ + if (options->verbose) + fprintf(stdout, "Detecting dependencies of application.\n"); + + // Override set in .pro file + if (!options->qtDependencies.isEmpty()) { + if (options->verbose) + fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n"); + return true; + } + + QSet usedDependencies; + QSet remainingDependencies; + + // Add dependencies of application binary first + if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies)) + return false; + + // Jam in the dependencies of the platform plugin, since the application will crash without it + if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies)) + return false; + + QString qtDir = options->qtInstallDirectory + QLatin1Char('/'); + + while (!remainingDependencies.isEmpty()) { + QSet::iterator start = remainingDependencies.begin(); + QString fileName = qtDir + *start; + remainingDependencies.erase(start); + + QStringList unmetDependencies; + if (goodToCopy(options, fileName, &unmetDependencies)) { + bool ok = readDependenciesFromElf(options, fileName, &usedDependencies, &remainingDependencies); + if (!ok) + return false; + } else { + fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", + qPrintable(fileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + } + } + + QStringList::iterator it = options->localLibs.begin(); + while (it != options->localLibs.end()) { + QStringList unmetDependencies; + if (!goodToCopy(options, qtDir + *it, &unmetDependencies)) { + fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n", + qPrintable(*it), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + it = options->localLibs.erase(it); + } else { + ++it; + } + } + + if (!options->rootPath.isEmpty() && !scanImports(options, &usedDependencies)) + return false; + + return true; +} + +bool stripFile(const Options &options, const QString &fileName) +{ + QString strip = options.ndkPath + + QLatin1String("/toolchains/") + + options.toolchainPrefix + + QLatin1Char('-') + + options.toolchainVersion + + QLatin1String("/prebuilt/") + + options.ndkHost + + QLatin1String("/bin/") + + options.toolPrefix + + QLatin1String("-strip"); +#if defined(Q_OS_WIN32) + strip += QLatin1String(".exe"); +#endif + + if (!QFile::exists(strip)) { + fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip)); + return false; + } + + strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip)).arg(shellQuote(fileName)); + + FILE *stripCommand = openProcess(strip); + if (stripCommand == 0) { + fprintf(stderr, "Cannot execute command %s", qPrintable(strip)); + return false; + } + + pclose(stripCommand); + + return true; +} + +bool stripLibraries(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Stripping libraries to minimize size.\n"); + + + QString libraryPath = options.outputDirectory + + QLatin1String("/libs/") + + options.architecture; + const QStringList libraries = QDir(libraryPath).entryList(QDir::Files); + for (const QString &library : libraries) { + if (library.endsWith(QLatin1String(".so"))) { + if (!stripFile(options, libraryPath + QLatin1Char('/') + library)) + return false; + } + } + + + return true; +} + +bool containsApplicationBinary(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Checking if application binary is in package.\n"); + + QFileInfo applicationBinary(options.applicationBinary); + QString destinationFileName = options.outputDirectory + + QLatin1String("/libs/") + + options.architecture + + QLatin1Char('/') + + applicationBinary.fileName(); + + if (!QFile::exists(destinationFileName)) { +#if defined(Q_OS_WIN32) + QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently +#else + QLatin1String makeTool("make"); +#endif + + fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n", + qPrintable(destinationFileName), + qPrintable(makeTool), + qPrintable(options.outputDirectory)); + return false; + } + + return true; +} + +FILE *runAdb(const Options &options, const QString &arguments) +{ + QString adb = options.sdkPath + QLatin1String("/platform-tools/adb"); +#if defined(Q_OS_WIN32) + adb += QLatin1String(".exe"); +#endif + + if (!QFile::exists(adb)) { + fprintf(stderr, "Cannot find adb tool: %s\n", qPrintable(adb)); + return 0; + } + QString installOption; + if (!options.installLocation.isEmpty()) + installOption = QLatin1String(" -s ") + shellQuote(options.installLocation); + + adb = QString::fromLatin1("%1%2 %3").arg(shellQuote(adb)).arg(installOption).arg(arguments); + + if (options.verbose) + fprintf(stdout, "Running command \"%s\"\n", adb.toLocal8Bit().constData()); + + FILE *adbCommand = openProcess(adb); + if (adbCommand == 0) { + fprintf(stderr, "Cannot start adb: %s\n", qPrintable(adb)); + return 0; + } + + return adbCommand; +} + +bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies) +{ + if (!file.endsWith(QLatin1String(".so"))) + return true; + + bool ret = true; + const auto libs = getQtLibsFromElf(*options, file); + for (const QString &lib : libs) { + if (!options->qtDependencies.contains(QtDependency(lib, options->qtInstallDirectory + QLatin1Char('/') + lib))) { + ret = false; + unmetDependencies->append(lib); + } + } + + return ret; +} + +bool copyQtFiles(Options *options) +{ + if (options->verbose) { + switch (options->deploymentMechanism) { + case Options::Bundled: + fprintf(stdout, "Copying %d dependencies from Qt into package.\n", options->qtDependencies.size()); + break; + case Options::Ministro: + fprintf(stdout, "Setting %d dependencies from Qt in package.\n", options->qtDependencies.size()); + break; + }; + } + + if (!options->build) + return true; + + QString libsDirectory = QLatin1String("libs/"); + + // Copy other Qt dependencies + QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/'); + QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/"); + for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) { + QString sourceFileName = qtDependency.absolutePath; + QString destinationFileName; + + if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) { + QString garbledFileName; + if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) { + garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1); + } else { + garbledFileName = QLatin1String("lib") + + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_')); + + } + destinationFileName = libDestinationDirectory + garbledFileName; + + } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) { + destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1); + } else { + destinationFileName = assetsDestinationDirectory + qtDependency.relativePath; + } + + if (!QFile::exists(sourceFileName)) { + fprintf(stderr, "Source Qt file does not exist: %s.\n", qPrintable(sourceFileName)); + return false; + } + + QStringList unmetDependencies; + if (!goodToCopy(options, sourceFileName, &unmetDependencies)) { + fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n", + qPrintable(sourceFileName), + qPrintable(unmetDependencies.join(QLatin1Char(',')))); + continue; + } + + if (options->deploymentMechanism == Options::Bundled + && !copyFileIfNewer(sourceFileName, + options->outputDirectory + QLatin1Char('/') + destinationFileName, + options->verbose)) { + return false; + } + + options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath); + } + + return true; +} + +QStringList getLibraryProjectsInOutputFolder(const Options &options) +{ + QStringList ret; + + QFile file(options.outputDirectory + QLatin1String("/project.properties")); + if (file.open(QIODevice::ReadOnly)) { + while (!file.atEnd()) { + QByteArray line = file.readLine().trimmed(); + if (line.startsWith("android.library.reference")) { + int equalSignIndex = line.indexOf('='); + if (equalSignIndex >= 0) { + QString path = QString::fromLocal8Bit(line.mid(equalSignIndex + 1)); + + QFileInfo info(options.outputDirectory + QLatin1Char('/') + path); + if (QDir::isRelativePath(path) + && info.exists() + && info.isDir() + && info.canonicalFilePath().startsWith(options.outputDirectory)) { + ret += info.canonicalFilePath(); + } + } + } + } + } + + return ret; +} + +bool createAndroidProject(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Running Android tool to create package definition.\n"); + + QString androidToolExecutable = options.sdkPath + QLatin1String("/tools/android"); +#if defined(Q_OS_WIN32) + androidToolExecutable += QLatin1String(".bat"); +#endif + + if (!QFile::exists(androidToolExecutable)) { + fprintf(stderr, "Cannot find Android tool: %s\n", qPrintable(androidToolExecutable)); + return false; + } + + QString androidTool = QString::fromLatin1("%1 update project --path %2 --target %3 --name QtApp") + .arg(shellQuote(androidToolExecutable)) + .arg(shellQuote(options.outputDirectory)) + .arg(shellQuote(options.androidPlatform)); + + if (options.verbose) + fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool)); + + FILE *androidToolCommand = openProcess(androidTool); + if (androidToolCommand == 0) { + fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool)); + return false; + } + + pclose(androidToolCommand); + + // If the project has subprojects inside the current folder, we need to also run android update on these. + const QStringList libraryProjects = getLibraryProjectsInOutputFolder(options); + for (const QString &libraryProject : libraryProjects) { + if (options.verbose) + fprintf(stdout, "Updating subproject %s\n", qPrintable(libraryProject)); + + androidTool = QString::fromLatin1("%1 update lib-project --path %2 --target %3") + .arg(shellQuote(androidToolExecutable)) + .arg(shellQuote(libraryProject)) + .arg(shellQuote(options.androidPlatform)); + + if (options.verbose) + fprintf(stdout, " -- Command: %s\n", qPrintable(androidTool)); + + FILE *androidToolCommand = popen(androidTool.toLocal8Bit().constData(), "r"); + if (androidToolCommand == 0) { + fprintf(stderr, "Cannot run command '%s'\n", qPrintable(androidTool)); + return false; + } + + pclose(androidToolCommand); + } + + return true; +} + +QString findInPath(const QString &fileName) +{ + const QString path = QString::fromLocal8Bit(qgetenv("PATH")); +#if defined(Q_OS_WIN32) + QLatin1Char separator(';'); +#else + QLatin1Char separator(':'); +#endif + + const QStringList paths = path.split(separator); + for (const QString &path : paths) { + QFileInfo fileInfo(path + QLatin1Char('/') + fileName); + if (fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable()) + return path + QLatin1Char('/') + fileName; + } + + return QString(); +} + +bool buildAntProject(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Building Android package using ant.\n"); + + QString antTool = options.antTool; + if (antTool.isEmpty()) { +#if defined(Q_OS_WIN32) + antTool = findInPath(QLatin1String("ant.bat")); +#else + antTool = findInPath(QLatin1String("ant")); +#endif + } + + if (antTool.isEmpty()) { + fprintf(stderr, "Cannot find ant in PATH. Please use --ant option to pass in the correct path.\n"); + return false; + } + + if (options.verbose) + fprintf(stdout, "Using ant: %s\n", qPrintable(antTool)); + + QString oldPath = QDir::currentPath(); + if (!QDir::setCurrent(options.outputDirectory)) { + fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory)); + return false; + } + + QString ant = QString::fromLatin1("%1 %2").arg(shellQuote(antTool)).arg(options.releasePackage ? QLatin1String(" release") : QLatin1String(" debug")); + + FILE *antCommand = openProcess(ant); + if (antCommand == 0) { + fprintf(stderr, "Cannot run ant command: %s\n.", qPrintable(ant)); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), antCommand) != 0) { + fprintf(stdout, "%s", buffer); + fflush(stdout); + } + + int errorCode = pclose(antCommand); + if (errorCode != 0) { + fprintf(stderr, "Building the android package failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- For more information, run this command with --verbose.\n"); + return false; + } + + if (!QDir::setCurrent(oldPath)) { + fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath)); + return false; + } + + return true; +} + +typedef QMap GradleProperties; + +static GradleProperties readGradleProperties(const QString &path) +{ + GradleProperties properties; + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return properties; + + const auto lines = file.readAll().split('\n'); + for (const QByteArray &line : lines) { + if (line.trimmed().startsWith('#')) + continue; + + QList prop(line.split('=')); + if (prop.size() > 1) + properties[prop.at(0).trimmed()] = prop.at(1).trimmed(); + } + file.close(); + return properties; +} + +static bool mergeGradleProperties(const QString &path, GradleProperties properties) +{ + QFile::remove(path + QLatin1Char('~')); + QFile::rename(path, path + QLatin1Char('~')); + QFile file(path); + if (!file.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) { + fprintf(stderr, "Can't open file: %s for writing\n", qPrintable(file.fileName())); + return false; + } + + QFile oldFile(path + QLatin1Char('~')); + if (oldFile.open(QIODevice::ReadOnly)) { + while (!oldFile.atEnd()) { + QByteArray line(oldFile.readLine()); + QList prop(line.split('=')); + if (prop.size() > 1) { + GradleProperties::iterator it = properties.find(prop.at(0).trimmed()); + if (it != properties.end()) { + file.write(it.key() + '=' + it.value() + '\n'); + properties.erase(it); + continue; + } + } + file.write(line); + } + oldFile.close(); + } + + for (GradleProperties::const_iterator it = properties.begin(); it != properties.end(); ++it) + file.write(it.key() + '=' + it.value() + '\n'); + + file.close(); + return true; +} + +bool buildGradleProject(const Options &options) +{ + GradleProperties localProperties; + localProperties["sdk.dir"] = options.sdkPath.toLocal8Bit(); + + if (!mergeGradleProperties(options.outputDirectory + QLatin1String("local.properties"), localProperties)) + return false; + + QString gradlePropertiesPath = options.outputDirectory + QLatin1String("gradle.properties"); + GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath); + gradleProperties["buildDir"] = "build"; + gradleProperties["qt5AndroidDir"] = (options.qtInstallDirectory + QLatin1String("/src/android/java")).toUtf8(); + gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(QLatin1Char('-')).last().toLocal8Bit(); + if (gradleProperties["androidBuildToolsVersion"].isEmpty()) + gradleProperties["androidBuildToolsVersion"] = options.sdkBuildToolsVersion.toLocal8Bit(); + + if (!mergeGradleProperties(gradlePropertiesPath, gradleProperties)) + return false; + +#if defined(Q_OS_WIN32) + QString gradlePath(options.outputDirectory + QLatin1String("gradlew.bat")); +#else + QString gradlePath(options.outputDirectory + QLatin1String("gradlew")); + { + QFile f(gradlePath); + if (!f.setPermissions(f.permissions() | QFileDevice::ExeUser)) + fprintf(stderr, "Cannot set permissions %s\n", qPrintable(gradlePath)); + } +#endif + + QString oldPath = QDir::currentPath(); + if (!QDir::setCurrent(options.outputDirectory)) { + fprintf(stderr, "Cannot current path to %s\n", qPrintable(options.outputDirectory)); + return false; + } + + QString commandLine = QString::fromLatin1("%1 --no-daemon %2").arg(shellQuote(gradlePath)).arg(options.releasePackage ? QLatin1String(" assembleRelease") : QLatin1String(" assembleDebug")); + if (options.verbose) + commandLine += QLatin1String(" --info"); + + FILE *gradleCommand = openProcess(commandLine); + if (gradleCommand == 0) { + fprintf(stderr, "Cannot run gradle command: %s\n.", qPrintable(commandLine)); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), gradleCommand) != 0) { + fprintf(stdout, "%s", buffer); + fflush(stdout); + } + + int errorCode = pclose(gradleCommand); + if (errorCode != 0) { + fprintf(stderr, "Building the android package failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- For more information, run this command with --verbose.\n"); + return false; + } + + if (!QDir::setCurrent(oldPath)) { + fprintf(stderr, "Cannot change back to old path: %s\n", qPrintable(oldPath)); + return false; + } + + return true; +} + +bool buildAndroidProject(const Options &options) +{ + return options.gradle ? buildGradleProject(options) + : buildAntProject(options); +} + +bool uninstallApk(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Uninstalling old Android package %s if present.\n", qPrintable(options.packageName)); + + + FILE *adbCommand = runAdb(options, QLatin1String(" uninstall ") + shellQuote(options.packageName)); + if (adbCommand == 0) + return false; + + if (options.verbose || mustReadOutputAnyway) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + if (options.verbose) + fprintf(stdout, "%s", buffer); + } + + int returnCode = pclose(adbCommand); + if (returnCode != 0) { + fprintf(stderr, "Warning: Uninstall failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return true; +} + +enum PackageType { + UnsignedAPK, + SignedAPK +}; + +QString apkPath(const Options &options, PackageType pt) +{ + QString path(options.outputDirectory); + if (options.gradle) + path += QLatin1String("/build/outputs/apk/") + QDir(options.outputDirectory).dirName() + QLatin1Char('-'); + else + path += QLatin1String("/bin/QtApp-"); + if (options.releasePackage) { + path += QLatin1String("release-"); + if (pt == UnsignedAPK) + path += QLatin1String("un"); + path += QLatin1String("signed.apk"); + } else { + path += QLatin1String("debug"); + if (pt == SignedAPK) + path += QLatin1String("-signed"); + path += QLatin1String(".apk"); + } + return shellQuote(path); +} + +bool installApk(const Options &options) +{ + fflush(stdout); + // Uninstall if necessary + if (options.uninstallApk) + uninstallApk(options); + + if (options.verbose) + fprintf(stdout, "Installing Android package to device.\n"); + + FILE *adbCommand = runAdb(options, + QLatin1String(" install -r ") + + apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK + : SignedAPK)); + if (adbCommand == 0) + return false; + + if (options.verbose || mustReadOutputAnyway) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), adbCommand) != 0) + if (options.verbose) + fprintf(stdout, "%s", buffer); + } + + int returnCode = pclose(adbCommand); + if (returnCode != 0) { + fprintf(stderr, "Installing to device failed!\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return true; +} + +bool copyStdCpp(Options *options) +{ + if (options->verbose) + fprintf(stdout, "Copying STL library\n"); + + QString filePath = !options->stdCppPath.isEmpty() ? options->stdCppPath + : options->ndkPath + + QLatin1String("/sources/cxx-stl/gnu-libstdc++/") + + options->toolchainVersion + + QLatin1String("/libs/") + + options->architecture + + QLatin1String("/libgnustl_shared.so"); + if (!QFile::exists(filePath)) { + fprintf(stderr, "STL library does not exist at %s\n", qPrintable(filePath)); + return false; + } + + const QString destinationDirectory = options->outputDirectory + + QLatin1String("/libs/") + options->architecture; + + if (!copyFileIfNewer(filePath, destinationDirectory + QLatin1String("/lib") + + options->stdCppName + QLatin1String(".so"), + options->verbose)) { + return false; + } + + return true; +} + +bool jarSignerSignPackage(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Signing Android package.\n"); + + QString jdkPath = options.jdkPath; + + if (jdkPath.isEmpty()) + jdkPath = QString::fromLocal8Bit(qgetenv("JAVA_HOME")); + +#if defined(Q_OS_WIN32) + QString jarSignerTool = QString::fromLatin1("jarsigner.exe"); +#else + QString jarSignerTool = QString::fromLatin1("jarsigner"); +#endif + + if (jdkPath.isEmpty() || !QFile::exists(jdkPath + QLatin1String("/bin/") + jarSignerTool)) + jarSignerTool = findInPath(jarSignerTool); + else + jarSignerTool = jdkPath + QLatin1String("/bin/") + jarSignerTool; + + if (!QFile::exists(jarSignerTool)) { + fprintf(stderr, "Cannot find jarsigner in JAVA_HOME or PATH. Please use --jdk option to pass in the correct path to JDK.\n"); + return false; + } + + jarSignerTool = QString::fromLatin1("%1 -sigalg %2 -digestalg %3 -keystore %4") + .arg(shellQuote(jarSignerTool)).arg(shellQuote(options.sigAlg)).arg(shellQuote(options.digestAlg)).arg(shellQuote(options.keyStore)); + + if (!options.keyStorePassword.isEmpty()) + jarSignerTool += QString::fromLatin1(" -storepass %1").arg(shellQuote(options.keyStorePassword)); + + if (!options.storeType.isEmpty()) + jarSignerTool += QString::fromLatin1(" -storetype %1").arg(shellQuote(options.storeType)); + + if (!options.keyPass.isEmpty()) + jarSignerTool += QString::fromLatin1(" -keypass %1").arg(shellQuote(options.keyPass)); + + if (!options.sigFile.isEmpty()) + jarSignerTool += QString::fromLatin1(" -sigfile %1").arg(shellQuote(options.sigFile)); + + if (!options.signedJar.isEmpty()) + jarSignerTool += QString::fromLatin1(" -signedjar %1").arg(shellQuote(options.signedJar)); + + if (!options.tsaUrl.isEmpty()) + jarSignerTool += QString::fromLatin1(" -tsa %1").arg(shellQuote(options.tsaUrl)); + + if (!options.tsaCert.isEmpty()) + jarSignerTool += QString::fromLatin1(" -tsacert %1").arg(shellQuote(options.tsaCert)); + + if (options.internalSf) + jarSignerTool += QLatin1String(" -internalsf"); + + if (options.sectionsOnly) + jarSignerTool += QLatin1String(" -sectionsonly"); + + if (options.protectedAuthenticationPath) + jarSignerTool += QLatin1String(" -protected"); + + jarSignerTool += QString::fromLatin1(" %1 %2") + .arg(apkPath(options, UnsignedAPK)) + .arg(shellQuote(options.keyStoreAlias)); + + FILE *jarSignerCommand = openProcess(jarSignerTool); + if (jarSignerCommand == 0) { + fprintf(stderr, "Couldn't run jarsigner.\n"); + return false; + } + + if (options.verbose) { + char buffer[512]; + while (fgets(buffer, sizeof(buffer), jarSignerCommand) != 0) + fprintf(stdout, "%s", buffer); + } + + int errorCode = pclose(jarSignerCommand); + if (errorCode != 0) { + fprintf(stderr, "jarsigner command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + + if (!QFile::exists(zipAlignTool)) { + zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + if (!QFile::exists(zipAlignTool)) { + fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool)); + return false; + } + } + + zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4") + .arg(shellQuote(zipAlignTool)) + .arg(options.verbose ? QString::fromLatin1(" -v") : QString()) + .arg(apkPath(options, UnsignedAPK)) + .arg(apkPath(options, SignedAPK)); + + FILE *zipAlignCommand = openProcess(zipAlignTool); + if (zipAlignCommand == 0) { + fprintf(stderr, "Couldn't run zipalign.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) + fprintf(stdout, "%s", buffer); + + errorCode = pclose(zipAlignCommand); + if (errorCode != 0) { + fprintf(stderr, "zipalign command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + return QFile::remove(apkPath(options, UnsignedAPK)); +} + +bool signPackage(const Options &options) +{ + QString apksignerTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/apksigner"); +#if defined(Q_OS_WIN32) + apksignerTool += QLatin1String(".bat"); +#endif + + if (options.jarSigner || !QFile::exists(apksignerTool)) + return jarSignerSignPackage(options); + + // APKs signed with apksigner must not be changed after they're signed, therefore we need to zipalign it before we sign it. + + QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + + if (!QFile::exists(zipAlignTool)) { + zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign"); +#if defined(Q_OS_WIN32) + zipAlignTool += QLatin1String(".exe"); +#endif + if (!QFile::exists(zipAlignTool)) { + fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool)); + return false; + } + } + + zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4") + .arg(shellQuote(zipAlignTool)) + .arg(options.verbose ? QString::fromLatin1(" -v") : QString()) + .arg(apkPath(options, UnsignedAPK)) + .arg(apkPath(options, SignedAPK)); + + FILE *zipAlignCommand = openProcess(zipAlignTool); + if (zipAlignCommand == 0) { + fprintf(stderr, "Couldn't run zipalign.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0) + fprintf(stdout, "%s", buffer); + + int errorCode = pclose(zipAlignCommand); + if (errorCode != 0) { + fprintf(stderr, "zipalign command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + + QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2") + .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore)); + + if (!options.keyStorePassword.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword)); + + if (!options.keyStoreAlias.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias)); + + if (!options.keyPass.isEmpty()) + apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass)); + + if (options.verbose) + apkSignerCommandLine += QLatin1String(" --verbose"); + + apkSignerCommandLine += QString::fromLatin1(" %1") + .arg(apkPath(options, SignedAPK)); + + auto apkSignerRunner = [&] { + FILE *apkSignerCommand = openProcess(apkSignerCommandLine); + if (apkSignerCommand == 0) { + fprintf(stderr, "Couldn't run apksigner.\n"); + return false; + } + + char buffer[512]; + while (fgets(buffer, sizeof(buffer), apkSignerCommand) != 0) + fprintf(stdout, "%s", buffer); + + errorCode = pclose(apkSignerCommand); + if (errorCode != 0) { + fprintf(stderr, "apksigner command failed.\n"); + if (!options.verbose) + fprintf(stderr, " -- Run with --verbose for more information.\n"); + return false; + } + return true; + }; + + // Sign the package + if (!apkSignerRunner()) + return false; + + apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2") + .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK)); + + // Verify the package and remove the unsigned apk + return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK)); +} + +bool copyGdbServer(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Copying gdbserver into package.\n"); + + QString architectureSubDirectory; + if (options.architecture == QLatin1String("arm64-v8a")) + architectureSubDirectory = QLatin1String("android-arm64"); + else if (options.architecture.startsWith(QLatin1String("arm"))) + architectureSubDirectory = QLatin1String("android-arm"); + else + architectureSubDirectory = QLatin1String("android-") + options.architecture; + + QString gdbServerBinary = options.ndkPath + + QLatin1String("/prebuilt/") + + architectureSubDirectory + + QLatin1String("/gdbserver/gdbserver"); + if (!QFile::exists(gdbServerBinary)) { + fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary)); + return false; + } + + QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture; + + if (!copyFileIfNewer(gdbServerBinary, + gdbServerTarget + QLatin1String("/gdbserver"), + options.verbose) + || !copyFileIfNewer(gdbServerBinary, + gdbServerTarget + QLatin1String("/libgdbserver.so"), + options.verbose)) { + return false; + } + + QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/"); + if (!QDir().mkpath(addedByAndroidDeployQtPath)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command")); + if (!f.open(QIODevice::WriteOnly)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + f.write("lib/libgdbserver.so --multi +"); + f.close(); + + return true; +} + +bool generateAssetsFileList(const Options &options) +{ + if (options.verbose) + fprintf(stdout, "Pregenerating entry list for assets file engine.\n"); + + QString assetsPath = options.outputDirectory + QLatin1String("/assets/"); + QString addedByAndroidDeployQtPath = assetsPath + QLatin1String("--Added-by-androiddeployqt--/"); + if (!QDir().mkpath(addedByAndroidDeployQtPath)) { + fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath)); + return false; + } + + QFile file(addedByAndroidDeployQtPath + QLatin1String("/qt_cache_pregenerated_file_list")); + if (file.open(QIODevice::WriteOnly)) { + QDirIterator dirIterator(assetsPath, + QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, + QDirIterator::Subdirectories); + + QHash directoryContents; + while (dirIterator.hasNext()) { + const QString name = dirIterator.next().mid(assetsPath.length()); + + int slashIndex = name.lastIndexOf(QLatin1Char('/')); + QString pathName = slashIndex >= 0 ? name.left(slashIndex) : QString::fromLatin1("/"); + QString fileName = slashIndex >= 0 ? name.mid(pathName.length() + 1) : name; + + if (!fileName.isEmpty() && dirIterator.fileInfo().isDir() && !fileName.endsWith(QLatin1Char('/'))) + fileName += QLatin1Char('/'); + + if (fileName.isEmpty() && !directoryContents.contains(pathName)) + directoryContents[pathName] = QStringList(); + else if (!fileName.isEmpty()) + directoryContents[pathName].append(fileName); + } + + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_5_3); + for (auto it = directoryContents.cbegin(), end = directoryContents.cend(); it != end; ++it) { + const QStringList &entryList = it.value(); + stream << it.key() << entryList.size(); + for (const QString &entry : entryList) + stream << entry; + } + } else { + fprintf(stderr, "Pregenerating entry list for assets file engine failed!\n"); + return false; + } + + return true; +} + +enum ErrorCode +{ + Success, + SyntaxErrorOrHelpRequested = 1, + CannotReadInputFile = 2, + CannotCopyAndroidTemplate = 3, + CannotReadDependencies = 4, + CannotCopyGnuStl = 5, + CannotCopyQtFiles = 6, + CannotFindApplicationBinary = 7, + CannotCopyGdbServer = 8, + CannotStripLibraries = 9, + CannotCopyAndroidExtraLibs = 10, + CannotCopyAndroidSources = 11, + CannotUpdateAndroidFiles = 12, + CannotCreateAndroidProject = 13, + CannotBuildAndroidProject = 14, + CannotSignPackage = 15, + CannotInstallApk = 16, + CannotGenerateAssetsFileList = 18, + CannotCopyAndroidExtraResources = 19 +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + Options options = parseOptions(); + if (options.helpRequested || options.outputDirectory.isEmpty()) { + printHelp(); + return SyntaxErrorOrHelpRequested; + } + + options.timer.start(); + + if (!readInputFile(&options)) + return CannotReadInputFile; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read input file\n", options.timer.elapsed()); + + fprintf(stdout, +// "012345678901234567890123456789012345678901234567890123456789012345678901" + "Generating Android Package\n" + " Input file: %s\n" + " Output directory: %s\n" + " Application binary: %s\n" + " Android build platform: %s\n" + " Install to device: %s\n", + qPrintable(options.inputFileName), + qPrintable(options.outputDirectory), + qPrintable(options.applicationBinary), + qPrintable(options.androidPlatform), + options.installApk + ? (options.installLocation.isEmpty() ? "Default device" : qPrintable(options.installLocation)) + : "No" + ); + + if (options.build) { + if (options.gradle) + cleanAndroidFiles(options); + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed()); + + if (!copyAndroidTemplate(options)) + return CannotCopyAndroidTemplate; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed()); + } + + if (!readDependencies(&options)) + return CannotReadDependencies; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed()); + + if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options)) + return CannotCopyGnuStl; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed()); + + if (!copyQtFiles(&options)) + return CannotCopyQtFiles; + + if (options.build) { + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed()); + + if (!containsApplicationBinary(options)) + return CannotFindApplicationBinary; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed()); + + bool needToCopyGdbServer = options.gdbServer == Options::True + || (options.gdbServer == Options::Auto && !options.releasePackage); + if (needToCopyGdbServer && !copyGdbServer(options)) + return CannotCopyGdbServer; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed()); + + if (!copyAndroidExtraLibs(options)) + return CannotCopyAndroidExtraLibs; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed()); + + if (!copyAndroidExtraResources(options)) + return CannotCopyAndroidExtraResources; + + if (!copyAndroidSources(options)) + return CannotCopyAndroidSources; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed()); + + if (!stripLibraries(options)) + return CannotStripLibraries; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed()); + + if (!updateAndroidFiles(options)) + return CannotUpdateAndroidFiles; + + if (options.generateAssetsFileList && !generateAssetsFileList(options)) + return CannotGenerateAssetsFileList; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Updated files\n", options.timer.elapsed()); + + if (!options.gradle && !createAndroidProject(options)) + return CannotCreateAndroidProject; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Created project\n", options.timer.elapsed()); + + if (!buildAndroidProject(options)) + return CannotBuildAndroidProject; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Built project\n", options.timer.elapsed()); + + if (!options.keyStore.isEmpty() && !signPackage(options)) + return CannotSignPackage; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Signed package\n", options.timer.elapsed()); + } + + if (options.installApk && !installApk(options)) + return CannotInstallApk; + + if (Q_UNLIKELY(options.timing)) + fprintf(stdout, "[TIMING] %d ms: Installed APK\n", options.timer.elapsed()); + + fprintf(stdout, "Android package built successfully in %.3f ms.\n", options.timer.elapsed() / 1000.); + + if (options.installApk) + fprintf(stdout, " -- It can now be run from the selected device/emulator.\n"); + + fprintf(stdout, " -- File: %s\n", qPrintable(apkPath(options, options.keyStore.isEmpty() ? UnsignedAPK + : SignedAPK))); + fflush(stdout); + return 0; +} From 60e56f1679d69b3e7217fa77a1e2d69250ac049d Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 8 Jun 2018 11:41:04 +0200 Subject: [PATCH 045/123] Replace commercial preview license with Qt License Agreement 4.0 Do allow people to build from git using the Qt License Agreement 4.0. The license agreement text is the same as in the installers, except that some Unicode characters got normalized to their ASCII variants, and things have been properly wrapped. [ChangeLog][Licensing] The commercial preview license in the git checkout has been replaced by the Qt License Agreement 4.0 text. This makes it explicit that commercial customers of The Qt Company can use the git version under commercial terms. However, support is (still) only provided for builds from released branches of Qt. Task-number: QTBUG-52222 Change-Id: I9e99b68e236a09610b798ba7a841e5a9d1ce6898 Reviewed-by: Lars Knoll --- LICENSE.PREVIEW.COMMERCIAL | 626 --------------------- LICENSE.QT-LICENSE-AGREEMENT-4.0 | 913 +++++++++++++++++++++++++++++++ configure.pri | 20 +- mkspecs/features/default_pre.prf | 2 +- 4 files changed, 926 insertions(+), 635 deletions(-) delete mode 100644 LICENSE.PREVIEW.COMMERCIAL create mode 100644 LICENSE.QT-LICENSE-AGREEMENT-4.0 diff --git a/LICENSE.PREVIEW.COMMERCIAL b/LICENSE.PREVIEW.COMMERCIAL deleted file mode 100644 index 5e5aeb6913e..00000000000 --- a/LICENSE.PREVIEW.COMMERCIAL +++ /dev/null @@ -1,626 +0,0 @@ -TECHNOLOGY PREVIEW LICENSE AGREEMENT - -For individuals and/or legal entities resident in the Americas (North -America, Central America and South America), the applicable licensing -terms are specified under the heading "Technology Preview License -Agreement: The Americas". - -For individuals and/or legal entities not resident in The Americas, the -applicable licensing terms are specified under the heading "Technology -Preview License Agreement: Rest of the World". - - -TECHNOLOGY PREVIEW LICENSE AGREEMENT: The Americas -Agreement version 2.4 - -This Technology Preview License Agreement ("Agreement")is a legal agreement -between The Qt Company USA, Inc. ("The Qt Company"), with its registered -office at 2350 Mission College Blvd., Suite 1020, Santa Clara, California -95054, U.S.A. and you (either an individual or a legal entity) ("Licensee") -for the Licensed Software (as defined below). - -1. DEFINITIONS - -"Affiliate" of a Party shall mean an entity (i) which is directly or -indirectly controlling such Party; (ii) which is under the same direct -or indirect ownership or control as such Party; or (iii) which is -directly or indirectly owned or controlled by such Party. For these -purposes, an entity shall be treated as being controlled by another if -that other entity has fifty percent (50 %) or more of the votes in such -entity, is able to direct its affairs and/or to control the composition -of its board of directors or equivalent body. - -"Applications" shall mean Licensee's software products created using the -Licensed Software which may include portions of the Licensed Software. - -"Term" shall mean the period of time six (6) months from the later of -(a) the Effective Date; or (b) the date the Licensed Software was -initially delivered to Licensee by The Qt Company. If no specific Effective -Date is set forth in the Agreement, the Effective Date shall be deemed to be -the date the Licensed Software was initially delivered to Licensee. - -"Licensed Software" shall mean the computer software, "online" or -electronic documentation, associated media and printed materials, -including the source code, example programs and the documentation -delivered by The Qt Company to Licensee in conjunction with this Agreement. - -"Party" or "Parties" shall mean Licensee and/or The Qt Company. - - -2. OWNERSHIP - -The Licensed Software is protected by copyright laws and international -copyright treaties, as well as other intellectual property laws and -treaties. The Licensed Software is licensed, not sold. - -If Licensee provides any findings, proposals, suggestions or other -feedback ("Feedback") to The Qt Company regarding the Licensed Software, -The Qt Company shall own all right, title and interest including the -intellectual property rights in and to such Feedback, excluding however any -existing patent rights of Licensee. To the extent Licensee owns or controls -any patents for such Feedback Licensee hereby grants to The Qt Company and its -Affiliates, a worldwide, perpetual, non-transferable, sublicensable, -royalty-free license to (i) use, copy and modify Feedback and to create -derivative works thereof, (ii) to make (and have made), use, import, -sell, offer for sale, lease, dispose, offer for disposal or otherwise -exploit any products or services of The Qt Company containing Feedback, and -(iii) sublicense all the foregoing rights to third party licensees and -customers of The Qt Company and/or its Affiliates. - - -3. VALIDITY OF THE AGREEMENT - -By installing, copying, or otherwise using the Licensed Software, -Licensee agrees to be bound by the terms of this Agreement. If Licensee -does not agree to the terms of this Agreement, Licensee may not install, -copy, or otherwise use the Licensed Software. Upon Licensee's acceptance -of the terms and conditions of this Agreement, The Qt Company grants Licensee -the right to use the Licensed Software in the manner provided below. - - -4. LICENSES - -4.1. Using and Copying - -The Qt Company grants to Licensee a non-exclusive, non-transferable, -time-limited license to use and copy the Licensed Software for sole purpose -of designing, developing and testing Applications, and evaluating and the -Licensed Software during the Term. - -Licensee may install copies of the Licensed Software on an unlimited -number of computers provided that (a) if an individual, only such -individual; or (b) if a legal entity only its employees; use the -Licensed Software for the authorized purposes. - -4.2 No Distribution or Modifications - -Licensee may not disclose, modify, sell, market, commercialise, -distribute, loan, rent, lease, or license the Licensed Software or any -copy of it or use the Licensed Software for any purpose that is not -expressly granted in this Section 4. Licensee may not alter or remove -any details of ownership, copyright, trademark or other property right -connected with the Licensed Software. Licensee may not distribute any -software statically or dynamically linked with the Licensed Software. - -4.3 No Technical Support - -The Qt Company has no obligation to furnish Licensee with any technical -support whatsoever. Any such support is subject to separate agreement between -the Parties. - - -5. PRE-RELEASE CODE -The Licensed Software contains pre-release code that is not at the level -of performance and compatibility of a final, generally available, -product offering. The Licensed Software may not operate correctly and -may be substantially modified prior to the first commercial product -release, if any. The Qt Company is not obligated to make this or any later -version of the Licensed Software commercially available. The License -Software is "Not for Commercial Use" and may only be used for the -purposes described in Section 4. The Licensed Software may not be used -in a live operating environment where it may be relied upon to perform -in the same manner as a commercially released product or with data that -has not been sufficiently backed up. - -6. THIRD PARTY SOFTWARE - -The Licensed Software may provide links to third party libraries or code -(collectively "Third Party Software") to implement various functions. -Third Party Software does not comprise part of the Licensed Software. In -some cases, access to Third Party Software may be included along with -the Licensed Software delivery as a convenience for development and -testing only. Such source code and libraries may be listed in the -".../src/3rdparty" source tree delivered with the Licensed Software or -documented in the Licensed Software where the Third Party Software is -used, as may be amended from time to time, do not comprise the Licensed -Software. Licensee acknowledges (1) that some part of Third Party -Software may require additional licensing of copyright and patents from -the owners of such, and (2) that distribution of any of the Licensed -Software referencing any portion of a Third Party Software may require -appropriate licensing from such third parties. - - -7. LIMITED WARRANTY AND WARRANTY DISCLAIMER - -The Licensed Software is licensed to Licensee "as is". To the maximum -extent permitted by applicable law, The Qt Company on behalf of itself and -its suppliers, disclaims all warranties and conditions, either express or -implied, including, but not limited to, implied warranties of -merchantability, fitness for a particular purpose, title and -non-infringement with regard to the Licensed Software. - - -8. LIMITATION OF LIABILITY - -If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is -held liable to Licensee, whether in contract, tort or any other legal theory, -based on the Licensed Software, The Qt Company's entire liability to Licensee -and Licensee's exclusive remedy shall be, at The Qt Company's option, either -(A) return of the price Licensee paid for the Licensed Software, or (B) -repair or replacement of the Licensed Software, provided Licensee -returns to The Qt Company all copies of the Licensed Software as originally -delivered to Licensee. The Qt Company shall not under any circumstances be -liable to Licensee based on failure of the Licensed Software if the failure -resulted from accident, abuse or misapplication, nor shall The Qt Company -under any circumstances be liable for special damages, punitive or exemplary -damages, damages for loss of profits or interruption of business or for -loss or corruption of data. Any award of damages from The Qt Company to -Licensee shall not exceed the total amount Licensee has paid to The Qt -Company in connection with this Agreement. - - -9. CONFIDENTIALITY - -Each party acknowledges that during the Term of this Agreement it shall -have access to information about the other party's business, business -methods, business plans, customers, business relations, technology, and -other information, including the terms of this Agreement, that is -confidential and of great value to the other party, and the value of -which would be significantly reduced if disclosed to third parties (the -"Confidential Information"). Accordingly, when a party (the "Receiving -Party") receives Confidential Information from another party (the -"Disclosing Party"), the Receiving Party shall, and shall obligate its -employees and agents and employees and agents of its Affiliates to: (i) -maintain the Confidential Information in strict confidence; (ii) not -disclose the Confidential Information to a third party without the -Disclosing Party's prior written approval; and (iii) not, directly or -indirectly, use the Confidential Information for any purpose other than -for exercising its rights and fulfilling its responsibilities pursuant -to this Agreement. Each party shall take reasonable measures to protect -the Confidential Information of the other party, which measures shall -not be less than the measures taken by such party to protect its own -confidential and proprietary information. - -"Confidential Information" shall not include information that (a) is or -becomes generally known to the public through no act or omission of the -Receiving Party; (b) was in the Receiving Party's lawful possession -prior to the disclosure hereunder and was not subject to limitations on -disclosure or use; (c) is developed by the Receiving Party without -access to the Confidential Information of the Disclosing Party or by -persons who have not had access to the Confidential Information of the -Disclosing Party as proven by the written records of the Receiving -Party; (d) is lawfully disclosed to the Receiving Party without -restrictions, by a third party not under an obligation of -confidentiality; or (e) the Receiving Party is legally compelled to -disclose the information, in which case the Receiving Party shall assert -the privileged and confidential nature of the information and cooperate -fully with the Disclosing Party to protect against and prevent -disclosure of any Confidential Information and to limit the scope of -disclosure and the dissemination of disclosed Confidential Information -by all legally available means. - -The obligations of the Receiving Party under this Section shall continue -during the Initial Term and for a period of five (5) years after -expiration or termination of this Agreement. To the extent that the -terms of the Non-Disclosure Agreement between The Qt Company and Licensee -conflict with the terms of this Section 9, this Section 9 shall be -controlling over the terms of the Non-Disclosure Agreement. - - -10. GENERAL PROVISIONS - -10.1 No Assignment - -Licensee shall not be entitled to assign or transfer all or any of its -rights, benefits and obligations under this Agreement without the prior -written consent of The Qt Company, which shall not be unreasonably withheld. - -10.2 Termination - -The Qt Company may terminate the Agreement at any time immediately upon -written notice by The Qt Company to Licensee if Licensee breaches this -Agreement. - -Upon termination of this Agreement, Licensee shall return to The Qt Company -all copies of Licensed Software that were supplied by The Qt Company. All -other copies of Licensed Software in the possession or control of Licensee -must be erased or destroyed. An officer of Licensee must promptly -deliver to The Qt Company a written confirmation that this has occurred. - -10.3 Surviving Sections - -Any terms and conditions that by their nature or otherwise reasonably -should survive a cancellation or termination of this Agreement shall -also be deemed to survive. Such terms and conditions include, but are -not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, -10.5, 10.6, 10.7, and 10.8 of this Agreement. - -10.4 Entire Agreement - -This Agreement constitutes the complete agreement between the parties -and supersedes all prior or contemporaneous discussions, -representations, and proposals, written or oral, with respect to the -subject matters discussed herein, with the exception of the -non-disclosure agreement executed by the parties in connection with this -Agreement ("Non-Disclosure Agreement"), if any, shall be subject to -Section 9. No modification of this Agreement shall be effective unless -contained in a writing executed by an authorized representative of each -party. No term or condition contained in Licensee's purchase order shall -apply unless expressly accepted by The Qt Company in writing. If any -provision of the Agreement is found void or unenforceable, the remainder -shall remain valid and enforceable according to its terms. If any remedy -provided is determined to have failed for its essential purpose, all -limitations of liability and exclusions of damages set forth in this -Agreement shall remain in effect. - -10.5 Export Control - -Licensee acknowledges that the Licensed Software may be subject to -export control restrictions of various countries. Licensee shall fully -comply with all applicable export license restrictions and requirements -as well as with all laws and regulations relating to the importation of -the Licensed Software and shall procure all necessary governmental -authorizations, including without limitation, all necessary licenses, -approvals, permissions or consents, where necessary for the -re-exportation of the Licensed Software., - -10.6 Governing Law and Legal Venue - -This Agreement shall be governed by and construed in accordance with the -federal laws of the United States of America and the internal laws of -the State of New York without given effect to any choice of law rule -that would result in the application of the laws of any other -jurisdiction. The United Nations Convention on Contracts for the -International Sale of Goods (CISG) shall not apply. Each Party (a) -hereby irrevocably submits itself to and consents to the jurisdiction of -the United States District Court for the Southern District of New York -(or if such court lacks jurisdiction, the state courts of the State of -New York) for the purposes of any action, claim, suit or proceeding -between the Parties in connection with any controversy, claim, or -dispute arising out of or relating to this Agreement; and (b) hereby -waives, and agrees not to assert by way of motion, as a defense or -otherwise, in any such action, claim, suit or proceeding, any claim that -is not personally subject to the jurisdiction of such court(s), that the -action, claim, suit or proceeding is brought in an inconvenient forum or -that the venue of the action, claim, suit or proceeding is improper. -Notwithstanding the foregoing, nothing in this Section 9.6 is intended -to, or shall be deemed to, constitute a submission or consent to, or -selection of, jurisdiction, forum or venue for any action for patent -infringement, whether or not such action relates to this Agreement. - -10.7 No Implied License - -There are no implied licenses or other implied rights granted under this -Agreement, and all rights, save for those expressly granted hereunder, -shall remain with The Qt Company and its licensors. In addition, no licenses -or immunities are granted to the combination of the Licensed Software with -any other software or hardware not delivered by The Qt Company under this -Agreement. - -10.8 Government End Users - -A "U.S. Government End User" shall mean any agency or entity of the -government of the United States. The following shall apply if Licensee -is a U.S. Government End User. The Licensed Software is a "commercial -item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), -consisting of "commercial computer software" and "commercial computer -software documentation," as such terms are used in 48 C.F.R. 12.212 -(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 -through 227.7202-4 (June 1995), all U.S. Government End Users acquire -the Licensed Software with only those rights set forth herein. The -Licensed Software (including related documentation) is provided to U.S. -Government End Users: (a) only as a commercial end item; and (b) only -pursuant to this Agreement. - - - - - -TECHNOLOGY PREVIEW LICENSE AGREEMENT: Rest of the World -Agreement version 2.4 - -This Technology Preview License Agreement ("Agreement") is a legal -agreement between The Qt Company Ltd ("The Qt Company"), with its registered -office at Valimotie 21,FI-00380 Helsinki, Finland and you (either an -individual or a legal entity) ("Licensee") for the Licensed Software. - -1. DEFINITIONS - -"Affiliate" of a Party shall mean an entity (i) which is directly or -indirectly controlling such Party; (ii) which is under the same direct -or indirect ownership or control as such Party; or (iii) which is -directly or indirectly owned or controlled by such Party. For these -purposes, an entity shall be treated as being controlled by another if -that other entity has fifty percent (50 %) or more of the votes in such -entity, is able to direct its affairs and/or to control the composition -of its board of directors or equivalent body. - -"Applications" shall mean Licensee's software products created using the -Licensed Software which may include portions of the Licensed Software. - -"Term" shall mean the period of time six (6) months from the later of -(a) the Effective Date; or (b) the date the Licensed Software was -initially delivered to Licensee by The Qt Company. If no specific Effective -Date is set forth in the Agreement, the Effective Date shall be deemed to be -the date the Licensed Software was initially delivered to Licensee. - -"Licensed Software" shall mean the computer software, "online" or -electronic documentation, associated media and printed materials, -including the source code, example programs and the documentation -delivered by The Qt Company to Licensee in conjunction with this Agreement. - -"Party" or "Parties" shall mean Licensee and/or The Qt Company. - - -2. OWNERSHIP - -The Licensed Software is protected by copyright laws and international -copyright treaties, as well as other intellectual property laws and -treaties. The Licensed Software is licensed, not sold. - -If Licensee provides any findings, proposals, suggestions or other -feedback ("Feedback") to The Qt Company regarding the Licensed Software, -The Qt Companyshall own all right, title and interest including the -intellectual property rights in and to such Feedback, excluding however any -existing patent rights of Licensee. To the extent Licensee owns or controls -any patents for such Feedback Licensee hereby grants to The Qt Company and -its Affiliates, a worldwide, perpetual, non-transferable, sublicensable, -royalty-free license to (i) use, copy and modify Feedback and to create -derivative works thereof, (ii) to make (and have made), use, import, -sell, offer for sale, lease, dispose, offer for disposal or otherwise -exploit any products or services of The Qt Company containing Feedback, and -(iii) sublicense all the foregoing rights to third party licensees and -customers of The Qt Company and/or its Affiliates. - -3. VALIDITY OF THE AGREEMENT - -By installing, copying, or otherwise using the Licensed Software, -Licensee agrees to be bound by the terms of this Agreement. If Licensee -does not agree to the terms of this Agreement, Licensee may not install, -copy, or otherwise use the Licensed Software. Upon Licensee's acceptance -of the terms and conditions of this Agreement, The Qt Company grants Licensee -the right to use the Licensed Software in the manner provided below. - - -4. LICENSES - -4.1. Using and Copying - -The Qt Company grants to Licensee a non-exclusive, non-transferable, -time-limited license to use and copy the Licensed Software for sole purpose -of designing, developing and testing Applications, and evaluating and the -Licensed Software during the Term. - -Licensee may install copies of the Licensed Software on an unlimited -number of computers provided that (a) if an individual, only such -individual; or (b) if a legal entity only its employees; use the -Licensed Software for the authorized purposes. - -4.2 No Distribution or Modifications - -Licensee may not disclose, modify, sell, market, commercialise, -distribute, loan, rent, lease, or license the Licensed Software or any -copy of it or use the Licensed Software for any purpose that is not -expressly granted in this Section 4. Licensee may not alter or remove -any details of ownership, copyright, trademark or other property right -connected with the Licensed Software. Licensee may not distribute any -software statically or dynamically linked with the Licensed Software. - -4.3 No Technical Support - -The Qt Company has no obligation to furnish Licensee with any technical -support whatsoever. Any such support is subject to separate agreement -between the Parties. - - -5. PRE-RELEASE CODE - -The Licensed Software contains pre-release code that is not at the level -of performance and compatibility of a final, generally available, -product offering. The Licensed Software may not operate correctly and -may be substantially modified prior to the first commercial product -release, if any. The Qt Company is not obligated to make this or any later -version of the Licensed Software commercially available. The License -Software is "Not for Commercial Use" and may only be used for the -purposes described in Section 4. The Licensed Software may not be used -in a live operating environment where it may be relied upon to perform -in the same manner as a commercially released product or with data that -has not been sufficiently backed up. - -6. THIRD PARTY SOFTWARE - -The Licensed Software may provide links to third party libraries or code -(collectively "Third Party Software") to implement various functions. -Third Party Software does not comprise part of the Licensed Software. In -some cases, access to Third Party Software may be included along with -the Licensed Software delivery as a convenience for development and -testing only. Such source code and libraries may be listed in the -".../src/3rdparty" source tree delivered with the Licensed Software or -documented in the Licensed Software where the Third Party Software is -used, as may be amended from time to time, do not comprise the Licensed -Software. Licensee acknowledges (1) that some part of Third Party -Software may require additional licensing of copyright and patents from -the owners of such, and (2) that distribution of any of the Licensed -Software referencing any portion of a Third Party Software may require -appropriate licensing from such third parties. - - -7. LIMITED WARRANTY AND WARRANTY DISCLAIMER - -The Licensed Software is licensed to Licensee "as is". To the maximum -extent permitted by applicable law, The Qt Company on behalf of itself and -its suppliers, disclaims all warranties and conditions, either express or -implied, including, but not limited to, implied warranties of -merchantability, fitness for a particular purpose, title and -non-infringement with regard to the Licensed Software. - - -8. LIMITATION OF LIABILITY - -If, The Qt Company's warranty disclaimer notwithstanding, The Qt Company is -held liable to Licensee, whether in contract, tort or any other legal theory, -based on the Licensed Software, The Qt Company's entire liability to Licensee -and Licensee's exclusive remedy shall be, at The Qt Company's option, either -(A) return of the price Licensee paid for the Licensed Software, or (B) -repair or replacement of the Licensed Software, provided Licensee -returns to The Qt Company all copies of the Licensed Software as originally -delivered to Licensee. The Qt Company shall not under any circumstances be -liable to Licensee based on failure of the Licensed Software if the failure -resulted from accident, abuse or misapplication, nor shall The Qt Company -under any circumstances be liable for special damages, punitive or exemplary -damages, damages for loss of profits or interruption of business or for -loss or corruption of data. Any award of damages from The Qt Company to -Licensee shall not exceed the total amount Licensee has paid to -The Qt Company in connection with this Agreement. - - -9. CONFIDENTIALITY - -Each party acknowledges that during the Term of this Agreement it shall -have access to information about the other party's business, business -methods, business plans, customers, business relations, technology, and -other information, including the terms of this Agreement, that is -confidential and of great value to the other party, and the value of -which would be significantly reduced if disclosed to third parties (the -"Confidential Information"). Accordingly, when a party (the "Receiving -Party") receives Confidential Information from another party (the -"Disclosing Party"), the Receiving Party shall, and shall obligate its -employees and agents and employees and agents of its Affiliates to: (i) -maintain the Confidential Information in strict confidence; (ii) not -disclose the Confidential Information to a third party without the -Disclosing Party's prior written approval; and (iii) not, directly or -indirectly, use the Confidential Information for any purpose other than -for exercising its rights and fulfilling its responsibilities pursuant -to this Agreement. Each party shall take reasonable measures to protect -the Confidential Information of the other party, which measures shall -not be less than the measures taken by such party to protect its own -confidential and proprietary information. - -"Confidential Information" shall not include information that (a) is or -becomes generally known to the public through no act or omission of the -Receiving Party; (b) was in the Receiving Party's lawful possession -prior to the disclosure hereunder and was not subject to limitations on -disclosure or use; (c) is developed by the Receiving Party without -access to the Confidential Information of the Disclosing Party or by -persons who have not had access to the Confidential Information of the -Disclosing Party as proven by the written records of the Receiving -Party; (d) is lawfully disclosed to the Receiving Party without -restrictions, by a third party not under an obligation of -confidentiality; or (e) the Receiving Party is legally compelled to -disclose the information, in which case the Receiving Party shall assert -the privileged and confidential nature of the information and cooperate -fully with the Disclosing Party to protect against and prevent -disclosure of any Confidential Information and to limit the scope of -disclosure and the dissemination of disclosed Confidential Information -by all legally available means. - -The obligations of the Receiving Party under this Section shall continue -during the Initial Term and for a period of five (5) years after -expiration or termination of this Agreement. To the extent that the -terms of the Non-Disclosure Agreement between The Qt Company and Licensee -conflict with the terms of this Section 9, this Section 9 shall be -controlling over the terms of the Non-Disclosure Agreement. - - -10. GENERAL PROVISIONS - -10.1 No Assignment - -Licensee shall not be entitled to assign or transfer all or any of its -rights, benefits and obligations under this Agreement without the prior -written consent of The Qt Company, which shall not be unreasonably withheld. - -10.2 Termination - -The Qt Company may terminate the Agreement at any time immediately upon -written notice by The Qt Company to Licensee if Licensee breaches this -Agreement. - -Upon termination of this Agreement, Licensee shall return to The Qt Company -all copies of Licensed Software that were supplied by The Qt Company. All -other copies of Licensed Software in the possession or control of Licensee -must be erased or destroyed. An officer of Licensee must promptly -deliver to The Qt Company a written confirmation that this has occurred. - -10.3 Surviving Sections - -Any terms and conditions that by their nature or otherwise reasonably -should survive a cancellation or termination of this Agreement shall -also be deemed to survive. Such terms and conditions include, but are -not limited to the following Sections: 2, 5, 6, 7, 8, 9, 10.2, 10.3, 10.4, -10.5, 10.6, 10.7, and 10.8 of this Agreement. - -10.4 Entire Agreement - -This Agreement constitutes the complete agreement between the parties -and supersedes all prior or contemporaneous discussions, -representations, and proposals, written or oral, with respect to the -subject matters discussed herein, with the exception of the -non-disclosure agreement executed by the parties in connection with this -Agreement ("Non-Disclosure Agreement"), if any, shall be subject to -Section 9. No modification of this Agreement shall be effective unless -contained in a writing executed by an authorized representative of each -party. No term or condition contained in Licensee's purchase order shall -apply unless expressly accepted by The Qt Company in writing. If any provision -of the Agreement is found void or unenforceable, the remainder shall remain -valid and enforceable according to its terms. If any remedy provided is -determined to have failed for its essential purpose, all limitations of -liability and exclusions of damages set forth in this Agreement shall -remain in effect. - -10.5 Export Control - -Licensee acknowledges that the Licensed Software may be subject to -export control restrictions of various countries. Licensee shall fully -comply with all applicable export license restrictions and requirements -as well as with all laws and regulations relating to the importation of -the Licensed Software and shall procure all necessary governmental -authorizations, including without limitation, all necessary licenses, -approvals, permissions or consents, where necessary for the -re-exportation of the Licensed Software., - -10.6 Governing Law and Legal Venue - -This Agreement shall be construed and interpreted in accordance with the laws -of Finland, excluding its choice of law provisions. Any disputes arising out -of or relating to this Agreement shall be resolved in arbitration in accordance -with the Arbitration Rules of the Finland Chamber of Commerce. The arbitration -tribunal shall consist of one (1), or if either Party so requires, of three -(3), arbitrators. The award shall be final and binding and enforceable in any -court of competent jurisdiction. The arbitration shall be held in Helsinki, -Finland and the process shall be conducted in the English language. - -10.7 No Implied License - -There are no implied licenses or other implied rights granted under this -Agreement, and all rights, save for those expressly granted hereunder, -shall remain with The Qt Company and its licensors. In addition, no licenses -or immunities are granted to the combination of the Licensed Software with -any other software or hardware not delivered by The Qt Company under this -Agreement. - -10.8 Government End Users - -A "U.S. Government End User" shall mean any agency or entity of the -government of the United States. The following shall apply if Licensee -is a U.S. Government End User. The Licensed Software is a "commercial -item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), -consisting of "commercial computer software" and "commercial computer -software documentation," as such terms are used in 48 C.F.R. 12.212 -(Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 -through 227.7202-4 (June 1995), all U.S. Government End Users acquire -the Licensed Software with only those rights set forth herein. The -Licensed Software (including related documentation) is provided to U.S. -Government End Users: (a) only as a commercial end item; and (b) only -pursuant to this Agreement. - diff --git a/LICENSE.QT-LICENSE-AGREEMENT-4.0 b/LICENSE.QT-LICENSE-AGREEMENT-4.0 new file mode 100644 index 00000000000..74bd6bb41cd --- /dev/null +++ b/LICENSE.QT-LICENSE-AGREEMENT-4.0 @@ -0,0 +1,913 @@ +QT LICENSE AGREEMENT +Agreement version 4.0 + +This License Agreement ("Agreement") is a legal agreement between The Qt +Company (as defined below) and the Licensee (as defined below) for the license +of Licensed Software (as defined below). Capitalized terms used herein are +defined in Section 1. + +WHEREAS: + +(A). Licensee wishes to use the Licensed Software for the purpose of developing +and distributing Applications and/or Devices; and + +(B). The Qt Company is willing to grant the Licensee a right to use Licensed +Software for such purpose pursuant to term and conditions of this Agreement. + +NOW, THEREFORE, THE PARTIES HEREBY AGREE AS FOLLOWS: + +1. DEFINITIONS + +"Affiliate" of a Party shall mean an entity (i) which is directly or indirectly +controlling such Party; (ii) which is under the same direct or indirect +ownership or control as such Party; or (iii) which is directly or indirectly +owned or controlled by such Party. For these purposes, an entity shall be +treated as being controlled by another if that other entity has fifty percent +(50 %) or more of the votes in such entity, is able to direct its affairs +and/or to control the composition of its board of directors or equivalent body. + +"Applications" shall mean Licensee's software products created using the +Licensed Software, which may include the Redistributables, or part +thereof. + +"Contractor(s)" shall mean third party consultants, distributors and +contractors performing services to a Party under applicable contractual +arrangement. + +"Customer(s)" shall mean Licensee's end users to whom Licensee, directly or +indirectly, distributes copies of the Redistributables. + +"Deployment Platforms" shall mean operating systems specified in the License +Certificate, in which the Redistributables can be distributed pursuant to the +terms and conditions of this Agreement. + +"Designated User(s)" shall mean the employee(s) of Licensee or Licensee's +Affiliates acting within the scope of their employment or Licensee's +Contractors acting within the scope of their services for Licensee and on +behalf of Licensee. Designated Users shall be named in the License Certificate. + +"Development License" shall mean the license needed by the Licensee for each +Designated User to use the Licensed Software under the license grant described +in Section 3.1 of this Agreement. + +"Development Platforms" shall mean those operating systems specified in the +License Certificate, in which the Licensed Software can be used under the +Development License, but not distributed in any form or used for any other +purpose. + +"Devices" shall mean hardware devices or products that 1) are manufactured +and/or distributed by the Licensee or its Affiliates or Contractors, and +(2)(i) incorporate or integrate the Redistributables or parts thereof; or (ii) +do not incorporate or integrate the Redistributables at the time of +distribution, but where, when used by a Customer, the main user interface or +substantial functionality of such device is provided by Application(s) or +otherwise depends on the Licensed Software. + +"Distribution License(s)" shall mean the license required for distribution of +Redistributables in connection with Devices pursuant to license grant described +in Section 3.3 of this Agreement. + +"Distribution License Packs" shall mean set of prepaid Distribution Licenses +for distribution of Redistributables, as defined in The Qt Company's standard +price list, quote, Purchase Order confirmation or in an appendix hereto, +as the case may be. + +"Intellectual Property Rights" shall mean patents (including utility models), +design patents, and designs (whether or not capable of registration), chip +topography rights and other like protection, copyrights, trademarks, service +marks, trade names, logos or other words or symbols and any other form of +statutory protection of any kind and applications for any of the foregoing as +well as any trade secrets. + +"License Certificate" shall mean a certificate generated by The Qt Company for +each Designated User respectively upon them downloading the licensed Software. +License Certificate will be available under respective Designated User's Qt +Account at account.qt.io and it will specify the Designated User, the +Development Platforms, Deployment Platforms and the License Term. The terms of +the License Certificate are considered part of this Agreement and shall be +updated from time to time to reflect any agreed changes to the foregoing terms +relating to Designated User's rights to the Licensed Software. + +"License Fee" shall mean the fee charged to the Licensee for rights granted +under the terms of this Agreement. + +"License Term" shall mean the agreed validity period of the Development +License of the respective Designated User, during which time the +Designated User is entitled to use the Licensed Software, as set forth in the +respective License Certificate. + +"Licensed Software" shall mean all versions of the + +(i) Qt Toolkit (including Qt Essentials, Qt Add-Ons and Value-Add modules) as +described in http://doc.qt.io/qt-5/qtmodules.html, + +(ii) Qt Creator (including Creator IDE tool) as described in +http://doc.qt.io/qtcreator/index.html, + +(iii) Qt 3D Studio as described in http://doc.qt.io/qt3dstudio/index.html, and + +as well as corresponding online or electronic documentation, associated media +and printed materials, including the source code, example programs and the +documentation, licensed to the Licensee under this Agreement. Licensed Software +does not include Third Party Software (as defined in Section 4), Open Source +Qt, or other software products of The Qt Company (for example Qt Safe Renderer +and Qt for Automation), unless such other software products of The Qt Company +are separately agreed in writing to be included in scope of the Licensed +Software. + +"Licensee" shall mean the individual or legal entity that is party to this +Agreement, as identified on the signature page hereof. + +"Licensee's Records" shall mean books and records that are likely to contain +information bearing on Licensee's compliance with this Agreement or the +payments due to The Qt Company under this Agreement, including, but not limited +to: assembly logs, sales records and distribution records. + +"Modified Software" shall have the meaning as set forth in Section 2.3. + +"Online Services" shall mean any services or access to systems made available +by The Qt Company to the Licensee over the Internet relating to the Licensed +Software or for the purpose of use by the Licensee of the Licensed Software or +Support. Use of any such Online Services is discretionary for the Licensee and +some of them may be subject to additional fees. + +"Open Source Qt" shall mean the non-commercial Qt computer software products, +licensed under the terms of the GNU Lesser General Public License, version +2.1 or later ("LGPL") or the GNU General Public License, version 2.0 or later +("GPL"). For clarity, Open Source Qt shall not be provided nor governed under +this Agreement. + +"Party" or "Parties" shall mean Licensee and/or The Qt Company. + +"Redistributables" shall mean the portions of the Licensed Software set forth +in Appendix 1, Section 1 that may be distributed pursuant to the terms of this +Agreement in object code form only, including any relevant documentation. +Where relevant, any reference to Licensed Software in this Agreement shall +include and refer also to Redistributables. + +"Renewal Term" shall mean an extension of previous License Term as agreed +between the Parties. + +"Submitted Modified Software" shall have the meaning as set forth in +Section 2.3. + +"Support" shall mean standard developer support that is provided by The Qt +Company to assist Designated Users in using the Licensed Software in +accordance with The Qt Company's standard support terms and as further +defined in Section 8 hereunder. + +"Taxes" shall have the meaning set forth in Section 10.5. + +"Term" shall have the meaning set forth in Section 12. + +"The Qt Company" shall mean: + +(i) in the event Licensee is an individual residing in the United States or a +legal entity incorporated in the United States or having its headquarters in +the United States, The Qt Company Inc., a Delaware corporation with its office +at 2350 Mission College Blvd., Suite 1020, Santa Clara, CA 95054, USA.; or + +(ii) in the event the Licensee is an individual residing outside of the United +States or a legal entity incorporated outside of the United States or having +its registered office outside of the United States, The Qt Company Ltd., a +Finnish company with its registered office at Bertel Jungin aukio D3A, 02600 +Espoo, Finland. + +"Third Party Software " shall have the meaning set forth in Section 4. + +"Updates" shall mean a release or version of the Licensed Software containing +bug fixes, error corrections and other changes that are generally made +available to users of the Licensed Software that have contracted for Support. +Updates are generally depicted as a change to the digits following the decimal +in the Licensed Software version number. The Qt Company shall make Updates +available to the Licensee under the Support. Updates shall be considered as +part of the Licensed Software hereunder. + +"Upgrades" shall mean a release or version of the Licensed Software containing +enhancements and new features and are generally depicted as a change to the +first digit of the Licensed Software version number. In the event Upgrades are +provided to the Licensee under this Agreement, they shall be considered as +part of the Licensed Software hereunder. + +2. OWNERSHIP + +2.1 Ownership of The Qt Company + +The Licensed Software is protected by copyright laws and international +copyright treaties, as well as other intellectual property laws and treaties. +The Licensed Software is licensed, not sold. + +All The Qt Company's Intellectual Property Rights are and shall remain the +exclusive property of The Qt Company or its licensors respectively. + +2.2 Ownership of Licensee + +All the Licensee's Intellectual Property Rights are and shall remain the +exclusive property of the Licensee or its licensors respectively. + +All Intellectual Property Rights to the Modified Software, Applications and +Devices shall remain with the Licensee and no rights thereto shall be granted +by the Licensee to The Qt Company under this Agreement (except as set forth in +Section 2.3 below). + +2.3 Modified Software + +Licensee may create bug-fixes, error corrections, patches or modifications to +the Licensed Software ("Modified Software"). Such Modified Software may break +the source or binary compatibility with the Licensed Software (including +without limitation through changing the application programming interfaces +("API") or by adding, changing or deleting any variable, method, or class +signature in the Licensed Software and/or any inter-process protocols, services +or standards in the Licensed Software libraries). To the extent that Licensee's +Modified Software so breaks source or binary compatibility with the Licensed +Software, Licensee acknowledges that The Qt Company's ability to provide +Support may be prevented or limited and Licensee's ability to make use of +Updates may be restricted. + +Licensee may, at its sole and absolute discretion, choose to submit Modified +Software to The Qt Company ("Submitted Modified Software") in connection with +Licensee's Support request, service request or otherwise. In the event Licensee +does so, then, Licensee hereby grants The Qt Company a sublicensable, +assignable, irrevocable, perpetual, worldwide, non-exclusive, royalty-free and +fully paid-up license, under all of Licensee's Intellectual Property Rights, to +reproduce, adapt, translate, modify, and prepare derivative works of, publicly +display, publicly perform, sublicense, make available and distribute such +Submitted Modified Software as The Qt Company sees fit at its free and absolute +discretion. + +3. LICENSES GRANTED + +3.1 Development with Licensed Software + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +personal, worldwide, non-exclusive, non-transferable license, valid for the +License Term, to use, modify and copy the Licensed Software by Designated Users +on the Development Platforms for the sole purposes of designing, developing, +demonstrating and testing Application(s) and/or Devices, and to provide thereto +related support and other related services to end-user Customers. + +Licensee may install copies of the Licensed Software on an unlimited number of +computers provided that (i) only the Designated Users may use the Licensed +Software, and (ii) all Designated Users must have a valid Development License +to use Licensed Software. + +Licensee may at any time designate another Designated User to replace a then- +current Designated User by notifying The Qt Company in writing, provided that +any Designated User may be replaced only once during any six-month period. + +Upon expiry of the initially agreed License Term, the respective License Terms +shall be automatically extended to one or more Renewal Term(s), unless and +until either Party notifies the other Party in writing that it does not wish to +continue the License Term, such notification to be provided to the other Party +no less than ninety (90) days before expiry of the respective License Term. +Unless otherwise agreed between the Parties, Renewal Term shall be of equal +length with the initial Term. + +Any such Renewal Term shall be subject to License Fees agreed between the +Parties or, if no advance agreement exists, subject to The Qt Company's +standard pricing applicable at the commencement date of any such Renewal Term. + +3.2 Distribution of Applications + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +personal, worldwide, non-exclusive, non-transferable, revocable (for cause +pursuant to this Agreement) right and license, valid for the Term, to + +(i) distribute, by itself or through its Contractors, Redistributables as +installed, incorporated or integrated into Applications for execution on the +Deployment Platforms, and + +(ii) grant sublicenses to Redistributables, as distributed hereunder, for +Customers solely for Customer's internal use and to the extent necessary in +order for the Customers to use the Applications for their respective intended +purposes. + +Right to distribute the Redistributables as part of an Application as provided +herein is not royalty-bearing but is conditional upon the Licensee having paid +the agreed Development Licenses from The Qt Company before distributing any +Redistributables to Customers. + +3.3 Distribution of Devices + +Subject to the terms of this Agreement, The Qt Company grants to Licensee a +personal, worldwide, non-exclusive, non-transferable, revocable (for cause +pursuant to this Agreement) right and license, valid for the Term, to + +(i) distribute, by itself or through one or more tiers of Contractors, +Redistributables as installed, incorporated or integrated, or intended to be +installed, incorporated or integrated into Devices for execution on the +Deployment Platforms, and + +(ii) grant sublicenses to Redistributables, as distributed hereunder, for +Customers solely for Customer's internal use and to the extent necessary in +order for the Customers to use the Devices for their respective intended +purposes. + +Right to distribute the Redistributables with Devices as provided herein is +conditional upon the Licensee having purchased and paid the appropriate amount +of Development and Distribution Licenses from The Qt Company before +distributing any Redistributables to Customers. + +3.4 Further Requirements + +The licenses granted above in this Section 3 by The Qt Company to Licensee are +conditional and subject to Licensee's compliance with the following terms: + +(i) Licensee shall not remove or alter any copyright, trademark or other +proprietary rights notice contained in any portion of the Licensed Software; + +(ii) Applications must add primary and substantial functionality to the +Licensed Software; + +(iii) Applications may not pass on functionality which in any way makes it +possible for others to create software with the Licensed Software; provided +however that Licensee may use the Licensed Software's scripting and QML ("Qt +Quick") functionality solely in order to enable scripting, themes and styles +that augment the functionality and appearance of the Application(s) without +adding primary and substantial functionality to the Application(s); + +(iv) Applications must not compete with the Licensed Software; + +(v) Licensee shall not use The Qt Company's or any of its suppliers' names, +logos, or trademarks to market Applications, except that Licensee may use +"Built with Qt" logo to indicate that Application(s) was developed using the +Licensed Software; + +(vi) Licensee shall not distribute, sublicense or disclose source code of +Licensed Software to any third party (provided however that Licensee may +appoint employee(s) of Contractors as Designated Users to use Licensed +Software pursuant to this Agreement). Such right may be available for the +Licensee subject to a separate software development kit ("SDK") license +agreement to be concluded with The Qt Company; + +(vii) Licensee shall not grant the Customers a right to (i) make copies of the +Redistributables except when and to the extent required to use the Applications +and/or Devices for their intended purpose, (ii) modify the Redistributables or +create derivative works thereof, (iii) decompile, disassemble or otherwise +reverse engineer Redistributables, or (iv) redistribute any copy or portion of +the Redistributables to any third party, except as part of the onward sale of +the Device on which the Redistributables are installed; + +(viii) Licensee shall not and shall cause that its Affiliates or Contractors +shall not a) in any way combine, incorporate or integrate Licensed Software +with, or use Licensed Software for creation of, any software created with or +incorporating Open Source Qt, or b) incorporate or integrate Applications +into a hardware device or product other than a Device, unless Licensee has +received an advance written permission from The Qt Company to do so. Absent +such written permission, any and all distribution by the Licensee during the +Term of a hardware device or product a) which incorporate or integrate any +part of Licensed Software or Open Source Qt; or b) where the main user +interface or substantial functionality is provided by software build with +Licensed Software or Open Source Qt or otherwise depends on the Licensed +Software or Open Source Qt, shall be considered as a Device distribution under +this Agreement and dependent on compliance thereof (including but not limited +to obligation to pay applicable License Fees for such distribution); + +(ix) Licensee shall cause all of its Affiliates and Contractors entitled to +make use of the licenses granted under this Agreement, to be contractually +bound to comply with the relevant terms of this Agreement and not to use the +Licensed Software beyond the terms hereof and for any purposes other than +operating within the scope of their services for Licensee. Licensee shall be +responsible for any and all actions and omissions of its Affiliates and +Contractors relating to the Licensed Software and use thereof (including but +not limited to payment of all applicable License Fees); + +(x) Except when and to the extent explicitly provided in this Section 3, +Licensee shall not transfer, publish, disclose, display or otherwise make +available the Licensed Software; + +; and + +(xi) Licensee shall not attempt or enlist a third party to conduct or attempt +to conduct any of the above. + +Above terms shall not be applicable if and to the extent they conflict with any +mandatory provisions of any applicable laws. + +Any use of Licensed Software beyond the provisions of this Agreement is +strictly prohibited and requires an additional license from The Qt Company. + +4. THIRD PARTY SOFTWARE + +The Licensed Software may provide links to third party libraries or code +(collectively "Third Party Software") to implement various functions. Third +Party Software does not comprise part of the Licensed Software. In some cases, +access to Third Party Software may be included in the Licensed Software. Such +Third Party Software will be listed in the ".../src/3rdparty" source tree +delivered with the Licensed Software or documented in the Licensed Software, as +such may be amended from time to time. Licensee acknowledges that use or +distribution of Third Party Software is in all respects subject to applicable +license terms of applicable third party right holders. + +5. PRE-RELEASE CODE + +The Licensed Software may contain pre-release code and functionality marked or +otherwise stated as "Technology Preview", "Alpha", "Beta" or similar +designation. Such pre-release code may be present in order to provide +experimental support for new platforms or preliminary versions of one or more +new functionalities. The pre-release code may not be at the level of +performance and compatibility of a final, generally available, product +offering of the Licensed Software. The pre-release parts of the Licensed +Software may not operate correctly, may contain errors and may be substantially +modified by The Qt Company prior to the first commercial product release, if +any. The Qt Company is under no obligation to make pre-release code +commercially available, or provide any Support or Updates relating thereto. The +Qt Company assumes no liability whatsoever regarding any pre-release code, but +any use thereof is exclusively at Licensee's own risk and expense. + +6. LIMITED WARRANTY AND WARRANTY DISCLAIMER + +The Qt Company hereby represents and warrants that it has the power and +authority to grant the rights and licenses granted to Licensee under this +Agreement. + +Except as set forth above, the Licensed Software is licensed to Licensee +"as is" and Licensee's exclusive remedy and The Qt Company's entire liability +for errors in the Licensed Software shall be limited, at The Qt Company's +option, to correction of the error, replacement of the Licensed Software or +return of the applicable fees paid for the defective Licensed Software for the +time period during which the License is not able to utilize the Licensed +Software under the terms of this Agreement. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE QT COMPANY ON BEHALF OF +ITSELF AND ITS LICENSORS, SUPPLIERS AND AFFILIATES, DISCLAIMS ALL OTHER +WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON- +INFRINGEMENT WITH REGARD TO THE LICENSED SOFTWARE. THE QT COMPANY DOES NOT +WARRANT THAT THE LICENSED SOFTWARE WILL SATISFY LICENSEE'S REQUIREMENTS OR THAT +IT WILL OPERATE WITHOUT DEFECT OR ERROR OR THAT THE OPERATION THEREOF WILL BE +UNINTERRUPTED. ALL USE OF AND RELIANCE ON THE LICENSED SOFTWARE IS AT THE SOLE +RISK OF AND RESPONSIBILITY OF LICENSEE. + +7. INDEMNIFICATION AND LIMITATION OF LIABILITY + +7.1 Limitation of Liability + +EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II) +BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN NO +EVENT SHALL EITHER PARTY BE LIABLE TO THE OTHER PARTY FOR ANY LOSS OF PROFIT, +LOSS OF DATA, LOSS OF BUSINESS OR GOODWILL OR ANY OTHER INDIRECT, SPECIAL, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE COST, DAMAGES OR EXPENSE OF ANY KIND, +HOWSOEVER ARISING UNDER OR IN CONNECTION WITH THIS AGREEMENT. PARTIES +SPECIFICALLY AGREE THAT LICENSEE'S OBLIGATION TO PAY LICENSE AND OTHER FEES +CORRESPONDING TO ACTUAL USAGE OF LICENSED SOFTWARE HEREUNDER SHALL BE +CONSIDERED AS A DIRECT DAMAGE. + +EXCEPT FOR (I) CASES OF GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT, AND (II) +BREACH OF CONFIDENTIALITY, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, IN +NO EVENT SHALL EITHER PARTY'S TOTAL AGGREGATE LIABILITY UNDER THIS AGREEMENT +EXCEED THE AGGREGATE LICENSE FEES PAID OR PAYABLE TO THE QT COMPANY FROM +LICENSEE DURING THE PERIOD OF TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE +EVENT RESULTING IN SUCH LIABILITY. + +THE PROVISIONS OF THIS SECTION 7 ALLOCATE THE RISKS UNDER THIS AGREEMENT +BETWEEN THE QT COMPANY AND LICENSEE AND THE PARTIES HAVE RELIED UPON THE +LIMITATIONS SET FORTH HEREIN IN DETERMINING WHETHER TO ENTER INTO THIS AGREEMENT. + +7.2 Licensee's Indemnification + +Licensee shall indemnify and hold harmless The Qt Company from and against any +claim, injury, judgment, settlement, loss or expense, including attorneys' fees +related to: (a) Licensee's misrepresentation in connection with The Qt Company +or the Licensed Software or breach of this Agreement, (b) the Application or +Device (except where such cause of liability is solely attributable to the +Licensed Software). + +8. SUPPORT, UPDATES AND ONLINE SERVICES + +Upon due payment of the agreed License Fees the Licensee will be eligible to +receive Support and Updates and to use the Online Services during the License +Term, provided, however, that in the event the License Term is longer than 36 +months, Support is provided only for the first 12 months, unless the Parties +specifically otherwise agree. + +Unless otherwise decided by The Company at its free and absolute discretion, +Upgrades will not be included in the Support but may be available subject to +additional fees. + +From time to time The Qt Company may change the Support terms, provided that +during the respective ongoing License Term the level of Support provided by The +Qt Company may not be reduced without the consent of the Licensee. + +Unless otherwise agreed, The Qt Company shall not be responsible for providing +any service or support to Customers. + +9. CONFIDENTIALITY + +Each Party acknowledges that during the Term of this Agreement each Party may +receive information about the other Party's business, business methods, +business plans, customers, business relations, technology, and other +information, including the terms of this Agreement, that is confidential and +of great value to the other Party, and the value of which would be +significantly reduced if disclosed to third parties ("Confidential +Information"). Accordingly, when a Party (the "Receiving Party") receives +Confidential Information from the other Party (the "Disclosing Party"), the +Receiving Party shall only disclose such information to employees and +Contractors on a need to know basis, and shall cause its employees and +employees of its Affiliates to: (i) maintain any and all Confidential +Information in confidence; (ii) not disclose the Confidential Information to a +third party without the Disclosing Party's prior written approval; and (iii) +not, directly or indirectly, use the Confidential Information for any purpose +other than for exercising its rights and fulfilling its responsibilities +pursuant to this Agreement. Each Party shall take reasonable measures to +protect the Confidential Information of the other Party, which measures shall +not be less than the measures taken by such Party to protect its own +confidential and proprietary information. + +Obligation of confidentiality shall not apply to information that (i) is or +becomes generally known to the public through no act or omission of the +Receiving Party; (ii) was in the Receiving Party's lawful possession prior to +the disclosure hereunder and was not subject to limitations on disclosure or +use; (iii) is developed independently by employees or Contractors of the +Receiving Party or other persons working for the Receiving Party who have not +had access to the Confidential Information of the Disclosing Party, as proven +by the written records of the Receiving Party; (iv) is lawfully disclosed to +the Receiving Party without restrictions, by a third party not under an +obligation of confidentiality; or (v) the Receiving Party is legally compelled +to disclose, in which case the Receiving Party shall notify the Disclosing +Party of such compelled disclosure and assert the privileged and confidential +nature of the information and cooperate fully with the Disclosing Party to +limit the scope of disclosure and the dissemination of disclosed Confidential +Information to the minimum extent necessary. + +The obligations under this Section 9 shall continue to remain in force for a +period of five (5) years after the last disclosure, and, with respect to trade +secrets, for so long as such trade secrets are protected under applicable trade +secret laws. + +10. FEES, DELIVERY AND PAYMENT + +10.1 License Fees + +License Fees are described in The Qt Company's standard price list, quote or +Purchase Order confirmation or in an appendix hereto, as the case may be. + +The License Fees shall not be refunded or claimed as a credit in any event or +for any reason whatsoever. + +10.2 Ordering Licenses + +Licensee may purchase Development Licenses and Distribution Licenses pursuant +to agreed pricing terms or, if no specific pricing terms have been agreed upon, +at The Qt Company's standard pricing terms applicable at the time of purchase. + +Licensee shall submit all purchase orders for Development Licenses and +Distribution Licenses to The Qt Company by email or any other method acceptable +to The Qt Company (each such order is referred to herein as a "Purchase Order") +for confirmation, whereupon the Purchase Order shall become binding between the +Parties. + +10.3 Distribution License Packs + +Unless otherwise agreed, Distribution Licenses shall be purchased by way of +Distribution License Packs. + +Upon due payment of the ordered Distribution License Pack(s), the Licensee will +have an account of Distribution Licenses available for installing, bundling or +integrating (all jointly "installing") the Redistributables with the Devices or +for otherwise distributing the Redistributables in accordance with this +Agreement. + +Each time Licensee "installs" or distributes a copy of Redistributables, then +one Distribution License is used, and Licensee's account of available +Distribution Licenses is decreased accordingly. + +Licensee may "install" copies of the Redistributables so long as Licensee has +Distribution Licenses remaining on its account. + +Redistributables will be deemed to have been "installed" into a Device when one +of the following circumstances shall have occurred: a) the Redistributables +have been loaded onto the Device and used outside of the Licensee's premises or +b) the Device has been fully tested and placed into Licensee's inventory +(or sold) for the first time (i.e., Licensee will not be required to use +(or pay for) more than one Distribution License for each individual Device, +e.g. in a situation where a Device is returned to Licensee's inventory after +delivery to a distributor or sale to a Customer). In addition, if Licensee +includes a back-up copy of the Redistributables on a CD-ROM or other storage +medium along with the product, that backup copy of the Redistributables will +not be deemed to have been "installed" and will not require an additional +Distribution License. + +10.4 Payment Terms + +License Fees and any other charges under this Agreement shall be paid by +Licensee no later than thirty (30) days from the date of the applicable invoice +from The Qt Company. + +The Qt Company will submit an invoice to Licensee after the date of this +Agreement and/or after The Qt Company receives a Purchase Order from +Licensee. + +A late payment charge of the lower of (a) one percent per month; or (b) the +interest rate stipulated by applicable law, shall be charged on any unpaid +balances that remain past due. + +The Qt Company shall have the right to suspend, terminate or withhold grants +of all rights to the Licensed Software hereunder, including but not limited to +the Developer License, Distribution License, and Support, should Licensee fail +to make payment in timely fashion. + +10.5 Taxes + +All License Fees and other charges payable hereunder are gross amounts but +exclusive of any value added tax, use tax, sales tax and other taxes, duties or +tariffs ("Taxes"). Such applicable Taxes shall be paid by Licensee, or, where +applicable, in lieu of payment of such Taxes, Licensee shall provide an +exemption certificate to The Qt Company and any applicable authority. + +11 RECORD-KEEPING AND REPORTING OBLIGATIONS; AUDIT RIGHTS + +11.1 Licensee's Record-keeping + +Licensee shall at all times maintain accurate and up-to-date written records of +Licensee's activities related to the use of Licensed Software and distribution +of Redistributables. The records shall be adequate to determine Licensee's +compliance with the provisions of this Agreement and to demonstrate the number +of Designated Users and Redistributables distributed by Licensee. The records +shall conform to good accounting practices reasonably acceptable to The Qt +Company. + +Licensee shall, within thirty (30) days from receiving The Qt Company's request +to that effect, deliver to The Qt Company a report on Licensee's usage of +Licensed Software, such report to copies of Redistributables distributed by +Licensee during that calendar quarter, and also detailing the number of +undistributed copies of Redistributables made by Licensee and remaining in its +account contain information, in sufficient detail, on (i) amount of users +working with Licensed Software, (ii) copies of Redistributables distributed by +Licensee during that calendar quarter, (iii) number of undistributed copies of +Redistributables and corresponding number of unused Distribution Licenses +remaining on Licensee's account, and (iv) any other information as The Qt +Company may reasonably require from time to time. + +11.2. The Qt Company's Audit Rights + +The Qt Company or an independent auditor acting on behalf of The Qt Company's, +may, upon at least five (5) business days' prior written notice and at its +expense, audit Licensee with respect to the use of the Redistributables, but +not more frequently than once during each 6-month period. Such audit may be +conducted by mail, electronic means or through an in-person visit to Licensee's +place of business. Any such in-person audit shall be conducted during regular +business hours at Licensee's facilities and shall not unreasonably interfere +with Licensee's business activities. The Qt Company or the independent auditor +acting on behalf of The Qt Company shall be entitled to inspect Licensee's +Records. All such Licensee's Records and use thereof shall be subject to an +obligation of confidentiality under this Agreement. + +If an audit reveals that Licensee is using the Licensed Software beyond scope +of the licenses Licensee has paid for, Licensee agrees to immediately pay The +Qt Company any amounts owed for such unauthorized use. + +In addition, in the event the audit reveals a material violation of the terms +of this Agreement (underpayment of more than 5% of License Fees shall always be +deemed a material violation for purposes of this section), then the Licensee +shall pay The Qt Company's reasonable cost of conducting such audit. + +12 TERM AND TERMINATION + +12.1 Term + +This Agreement shall enter into force upon due acceptance by both Parties and +remain in force for as long as there is any Development License(s) in force +("Term"), unless and until terminated pursuant to the terms of this Section 12. + +12.2 Termination by The Qt Company + +The Qt Company shall have the right to terminate this Agreement upon thirty +(30) days prior written notice if the Licensee is in material breach of any +obligation of this Agreement and fails to remedy such breach within such notice +period. + +12.3 Mutual Right to Terminate + +Either Party shall have the right to terminate this Agreement immediately upon +written notice in the event that the other Party becomes insolvent, files for +any form of bankruptcy, makes any assignment for the benefit of creditors, has +a receiver, administrative receiver or officer appointed over the whole or a +substantial part of its assets, ceases to conduct business, or an act +equivalent to any of the above occurs under the laws of the jurisdiction of the +other Party. + +12.4 Parties' Rights and Duties upon Termination + +Upon expiry or termination of the Agreement Licensee shall cease and shall +cause all Designated Users (including those of its Affiliates' and +Contractors') to cease using the Licensed Software and distribution of the +Redistributables under this Agreement. + +Notwithstanding the above, in the event the Agreement expires or is terminated: + +(i) as a result of The Qt Company choosing not to renew the Development +License(s) as set forth in Section 3.1, then all valid licenses possessed by +the Licensee at such date shall be extended to be valid in perpetuity under the +terms of this Agreement and Licensee is entitled to purchase additional +licenses as set forth in Section 10.2; or + +(ii) for reason other than by The Qt Company pursuant to item (i) above or +pursuant to Section 12.2, then the Licensee is entitled, for a period of six +(6) months after the effective date of termination, to continue distribution of +Devices under the Distribution Licenses paid but unused at such effective date +of termination. + +Upon any such termination the Licensee shall destroy or return to The Qt +Company all copies of the Licensed Software and all related materials and will +certify the same to The Qt Company upon its request, provided however that +Licensee may retain and exploit such copies of the Licensed Software as it may +reasonably require in providing continued support to Customers. + +Expiry or termination of this Agreement for any reason whatsoever shall not +relieve Licensee of its obligation to pay any License Fees accrued or payable +to The Qt Company prior to the effective date of termination, and Licensee +shall immediately pay to The Qt Company all such fees upon the effective date +of termination. Termination of this Agreement shall not affect any rights of +Customers to continue use of Applications and Devices (and therein incorporated +Redistributables). + +12.5 Extension in case of bankruptcy + +In the event The Qt Company is declared bankrupt under a final, non-cancellable +decision by relevant court of law, and this Agreement is not, at the date of +expiry of the Development License(s) pursuant to Section 3.1, assigned to +party, who has assumed The Qt Company's position as a legitimate licensor of +Licensed Software under this Agreement, then all valid licenses possessed by +the Licensee at such date of expiry, and which the Licensee has not notified +for expiry, shall be extended to be valid in perpetuity under the terms of +this Agreement. + +13. GOVERNING LAW AND LEGAL VENUE + +In the event this Agreement is in the name of The Qt Company Inc., a Delaware +Corporation, then: + +(i) this Agreement shall be construed and interpreted in accordance with the +laws of the State of California, USA, excluding its choice of law provisions; + +(ii) the United Nations Convention on Contracts for the International Sale of +Goods will not apply to this Agreement; and + +(iii) any dispute, claim or controversy arising out of or relating to this +Agreement or the breach, termination, enforcement, interpretation or validity +thereof, including the determination of the scope or applicability of this +Agreement to arbitrate, shall be determined by arbitration in San Francisco, +USA, before one arbitrator. The arbitration shall be administered by JAMS +pursuant to JAMS' Streamlined Arbitration Rules and Procedures. Judgment on the +Award may be entered in any court having jurisdiction. This Section shall not +preclude parties from seeking provisional remedies in aid of arbitration from a +court of appropriate jurisdiction. + +In the event this Agreement is in the name of The Qt Company Ltd., a Finnish +Company, then: + +(i) this Agreement shall be construed and interpreted in accordance with the +laws of Finland, excluding its choice of law provisions; + +(ii) the United Nations Convention on Contracts for the International Sale of +Goods will not apply to this Agreement; and + +(iii) any disputes, controversy or claim arising out of or relating to this +Agreement, or the breach, termination or validity thereof shall be shall be +finally settled by arbitration in accordance with the Arbitration Rules of +Finland Chamber of Commerce. The arbitration tribunal shall consist of one (1), +or if either Party so requires, of three (3), arbitrators. The award shall be +final and binding and enforceable in any court of competent jurisdiction. The +arbitration shall be held in Helsinki, Finland and the process shall be +conducted in the English language. This Section shall not preclude parties from +seeking provisional remedies in aid of arbitration from a court of appropriate +jurisdiction. + +14. GENERAL PROVISIONS + +14.1 No Assignment + +Except in the case of a merger or sale of substantially all of its corporate +assets, Licensee shall not be entitled to assign or transfer all or any of its +rights, benefits and obligations under this Agreement without the prior written +consent of The Qt Company, which shall not be unreasonably withheld or delayed. +The Qt Company shall be entitled to freely assign or transfer any of its +rights, benefits or obligations under this Agreement. + +14.2 No Third Party Representations + +Licensee shall make no representations or warranties concerning the Licensed +Software on behalf of The Qt Company. Any representation or warranty Licensee +makes or purports to make on The Qt Company's behalf shall be void as to The +Qt Company. + +14.3 Surviving Sections + +Any terms and conditions that by their nature or otherwise reasonably should +survive termination of this Agreement shall so be deemed to survive. + +14.4 Entire Agreement + +This Agreement, the exhibits hereto, the License Certificate and any applicable +Purchase Order constitute the complete agreement between the Parties and +supersedes all prior or contemporaneous discussions, representations, and +proposals, written or oral, with respect to the subject matters discussed +herein. + +In the event of any conflict or inconsistency between this Agreement and any +Purchase Order, the terms of this Agreement will prevail over the terms of the +Purchase Order with respect to such conflict or inconsistency. + +Parties specifically acknowledge and agree that this Agreement prevails over +any click-to-accept or similar agreements the Designated Users may need to +accept online upon download of the Licensed Software, as may be required by +The Qt Company's applicable processes relating to Licensed Software. + +14.5 Modifications + +No modification of this Agreement shall be effective unless contained in a +writing executed by an authorized representative of each Party. No term or +condition contained in Licensee's Purchase Order shall apply unless expressly +accepted by The Qt Company in writing. + +14.6 Force Majeure + +Except for the payment obligations hereunder, neither Party shall be liable to +the other for any delay or non-performance of its obligations hereunder in the +event and to the extent that such delay or non-performance is due to an event +of act of God, terrorist attack or other similar unforeseeable catastrophic +event that prevents either Party for fulfilling its obligations under this +Agreement and which such Party cannot avoid or circumvent ("Force Majeure +Event"). If the Force Majeure Event results in a delay or non-performance of a +Party for a period of three (3) months or longer, then either Party shall have +the right to terminate this Agreement with immediate effect without any +liability (except for the obligations of payment arising prior to the event of +Force Majeure) towards the other Party. + +14.7 Notices + +Any notice given by one Party to the other shall be deemed properly given and +deemed received if specifically acknowledged by the receiving Party in writing +or when successfully delivered to the recipient by hand, fax, or special +courier during normal business hours on a business day to the addresses +specified for each Party on the signature page. Each communication and document +made or delivered by one Party to the other Party pursuant to this Agreement +shall be in the English language. + +14.8 Export Control + +Licensee acknowledges that the Redistributables may be subject to export +control restrictions under the applicable laws of respective countries. +Licensee shall fully comply with all applicable export license restrictions +and requirements as well as with all laws and regulations relating to the +Redistributables and exercise of licenses hereunder and shall procure all +necessary governmental authorizations, including without limitation, all +necessary licenses, approvals, permissions or consents, where necessary for the +re-exportation of the Redistributables, Applications and/or Devices. + +14.9 No Implied License + +There are no implied licenses or other implied rights granted under this +Agreement, and all rights, save for those expressly granted hereunder, shall +remain with The Qt Company and its licensors. In addition, no licenses or +immunities are granted to the combination of the Licensed Software with any +other software or hardware not delivered by The Qt Company under this Agreement. + +14.10 Attorney Fees + +The prevailing Party in any action to enforce this Agreement shall be entitled +to recover its attorney's fees and costs in connection with such action. + +14.11 Severability + +If any provision of this Agreement shall be adjudged by any court of competent +jurisdiction to be unenforceable or invalid, that provision shall be limited or +eliminated to the minimum extent necessary so that this Agreement shall +otherwise remain in full force and effect and enforceable. + + +IN WITNESS WHEREOF, the Parties hereto, intending to be legally bound hereby, +have caused this Agreement to be executed by Licensee's authorized +representative installing the Licensed Software and accepting the terms +hereof in connection therewith. + + +Appendix 1 + +1. Parts of the Licensed Software that are permitted for distribution in +object code form only ("Redistributables") under this Agreement: + +- The Licensed Software's Qt Essentials and Qt Add-on libraries +- The Licensed Software's configuration tool ("qtconfig") +- The Licensed Software's help tool ("Qt Assistant") +- The Licensed Software's internationalization tools ("Qt Linguist", "lupdate", + "lrelease") +- The Licensed Software's QML ("Qt Quick") launcher tool ("qmlscene" or + "qmlviewer") +- The Licensed Software's installer framework + +2. Parts of the Licensed Software that are not permitted for distribution +include, but are not limited to: + +- The Licensed Software's source code and header files +- The Licensed Software's documentation +- The Licensed Software's documentation generation tool ("qdoc") +- The Licensed Software's tool for writing makefiles ("qmake") +- The Licensed Software's Meta Object Compiler ("moc") +- The Licensed Software's User Interface Compiler ("uic") +- The Licensed Software's Resource Compiler ("rcc") +- The Licensed Software's parts of the IDE tool ("Qt Creator") +- The Licensed Software's parts of the Design tools ("Qt 3D Studio" or + "Qt Quick Designer") +- The Licensed Software's Emulator diff --git a/configure.pri b/configure.pri index 0512ef01447..f1c63f575da 100644 --- a/configure.pri +++ b/configure.pri @@ -72,7 +72,7 @@ defineReplace(qtConfFunc_licenseCheck) { hasOpenSource = true else: \ hasOpenSource = false - exists($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL)|exists($$QT_SOURCE_TREE/bin/licheck*): \ + exists($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0): \ hasCommercial = true else: \ hasCommercial = false @@ -128,14 +128,18 @@ defineReplace(qtConfFunc_licenseCheck) { qtConfFatalError("This is the Qt Open Source Edition." \ "Cannot proceed with -commercial.") - exists($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL) { - logn() - logn("This is the Qt Technology Preview Edition.") + !exists($$QT_SOURCE_TREE/.release-timestamp) { + # Build from git - EditionString = "Technology Preview" - config.input.qt_edition = Preview + logn() + logn("This is the Qt Commercial Edition.") + + EditionString = "Commercial" + config.input.qt_edition = Commercial export(config.input.qt_edition) } else { + # Build from a released source package + equals(QMAKE_HOST.os, Linux) { !equals(QMAKE_HOST.arch, x86_64): \ Licheck = licheck32 @@ -194,7 +198,7 @@ defineReplace(qtConfFunc_licenseCheck) { affix = either } } else { - theLicense = $$cat($$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL, lines) + theLicense = $$cat($$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0, lines) theLicense = $$first(theLicense) showWhat = "Type '?' to view the $${theLicense}." } @@ -221,7 +225,7 @@ defineReplace(qtConfFunc_licenseCheck) { } else: equals(val, n)|equals(val, no) { return(false) } else: equals(commercial, yes):equals(val, ?) { - licenseFile = $$QT_SOURCE_TREE/LICENSE.PREVIEW.COMMERCIAL + licenseFile = $$QT_SOURCE_TREE/LICENSE.QT-LICENSE-AGREEMENT-4.0 } else: equals(commercial, no):equals(val, l) { licenseFile = $$QT_SOURCE_TREE/LICENSE.LGPL3 } else: equals(commercial, no):equals(val, g):$$gpl2Ok { diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index 07a9b1c4014..1f2f1ff2de1 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -11,7 +11,7 @@ CONFIG = \ testcase_targets import_plugins import_qpa_plugin \ $$CONFIG -!build_pass:defined(QT_EDITION, var):!equals(QT_EDITION, "OpenSource"):!equals(QT_EDITION, "Preview") { +!build_pass:!isEmpty(QT_LICHECK) { # # call license checker (but cache result for one day) # From 5a68ce07bd32eeb86ea1b0141c3a4fe20acc86a8 Mon Sep 17 00:00:00 2001 From: Jesus Fernandez Date: Tue, 19 Jun 2018 10:48:27 +0200 Subject: [PATCH 046/123] Fix function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace QDir::makepath with QDir::mkpath. Change-Id: Iec91fc332393255843bad915c1064587b5fe543d Reviewed-by: Mårten Nordheim --- qmake/doc/src/qmake-manual.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 35f24e1793f..59c161a223e 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -3611,7 +3611,7 @@ \section2 mkpath(dirPath) Creates the directory path \c dirPath. This function is a wrapper around the - QDir::makepath function. + QDir::mkpath function. \section2 requires(condition) From 22e9ff9c164d9912fcbe7987f4d39e467b0a600f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Thu, 14 Jun 2018 15:54:37 +0300 Subject: [PATCH 047/123] mkspecs: Allow specifying a CROSS_COMPILE for mac/clang targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows distinguishing between these tools and tools for the host, when cross compiling. While mac tools normally only are available on macOS, there are third party efforts to port them to other platforms. In these cases, it might be useful to use a prefix (either some sort of triplet prefix, or an absolute path) to distinguish between the host build platform compilers/tools and the ones for the cross target. The use of this variable matches the one used in a lot of other mkspecs, and shouldn't cause any issues for those who aren't setting it. Change-Id: Iaeba571d955ea79ed1249989fcc525eb1eaf1f5c Reviewed-by: Oswald Buddenhagen Reviewed-by: Morten Johan Sørvig --- mkspecs/common/clang.conf | 4 ++-- mkspecs/common/mac.conf | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf index e003b947aab..0fb84bc1b31 100644 --- a/mkspecs/common/clang.conf +++ b/mkspecs/common/clang.conf @@ -4,8 +4,8 @@ QMAKE_COMPILER = gcc clang llvm # clang pretends to be gcc -QMAKE_CC = clang -QMAKE_CXX = clang++ +QMAKE_CC = $${CROSS_COMPILE}clang +QMAKE_CXX = $${CROSS_COMPILE}clang++ QMAKE_LINK_C = $$QMAKE_CC QMAKE_LINK_C_SHLIB = $$QMAKE_CC diff --git a/mkspecs/common/mac.conf b/mkspecs/common/mac.conf index d5e559ee124..61bea952b22 100644 --- a/mkspecs/common/mac.conf +++ b/mkspecs/common/mac.conf @@ -43,9 +43,9 @@ QMAKE_WAYLAND_SCANNER = wayland-scanner QMAKE_ACTOOL = actool QMAKE_DSYMUTIL = dsymutil -QMAKE_STRIP = strip +QMAKE_STRIP = $${CROSS_COMPILE}strip QMAKE_STRIPFLAGS_LIB += -S -x -QMAKE_AR = ar cq -QMAKE_RANLIB = ranlib -s -QMAKE_NM = nm -P +QMAKE_AR = $${CROSS_COMPILE}ar cq +QMAKE_RANLIB = $${CROSS_COMPILE}ranlib -s +QMAKE_NM = $${CROSS_COMPILE}nm -P From 3f01dc199560e7d31f8941dc81e99a17d2e95cdf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 21 Jun 2018 12:35:29 +0200 Subject: [PATCH 048/123] QWindowsFontDatabase/QWindowsXPStyle: Fix compilation with g++ 8.1/MinGW Silence warnings about copying/clearing memory types which g++ considers non-trivial, for example: windows\qwindowsfontdatabase.cpp:1003:75: error: 'void* memcpy(void*, const void*, size_t)' copying an object of non-trivial type 'class QChar' from an array of 'const ushort' {aka 'const short unsigned int'} [-Werror=class-memaccess] memcpy(faceNamePtr, faceName.utf16(), sizeof(wchar_t) * nameLength); qwindowsxpstyle.cpp:946:46: error: 'void* memset(void*, int, size_t)' clearing an object of non-trivial type 'struct ThemeMapData'; use assignment or value-initialization instead [-Werror=class-memaccess] memset(&data, 0, sizeof(data)); ^ qwindowsxpstyle.cpp:1053:38: error: 'void* memset(void*, int, size_t)' clearing an object of non-trivial type 'struct ThemeMapData'; use assignment or value-initialization instead [-Werror=class-memaccess] memset(&data, 0, sizeof(data)); by introducing a cast. Task-number: QTBUG-68742 Task-number: QTQAINFRA-2095 Change-Id: I160eb5fc7b64a2bc404e1fa61d306af2662d1252 Reviewed-by: Joerg Bornemann --- .../fontdatabases/windows/qwindowsfontdatabase.cpp | 2 +- src/plugins/styles/windowsvista/qwindowsxpstyle.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index aab1ab9889e..8df8da1a38f 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1000,7 +1000,7 @@ static QChar *createFontFile(const QString &faceName) if (!faceName.isEmpty()) { const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1); faceNamePtr = new QChar[nameLength + 1]; - memcpy(faceNamePtr, faceName.utf16(), sizeof(wchar_t) * nameLength); + memcpy(static_cast(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength); faceNamePtr[nameLength] = 0; } return faceNamePtr; diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 9d2e7701919..36a8afb453c 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -943,7 +943,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa if (!isCached) { // SHORTCUT: If the part's state has no data, cache it for NOOP later if (!stateHasData) { - memset(&data, 0, sizeof(data)); + memset(static_cast(&data), 0, sizeof(data)); data.dataValid = true; alphaCache.insert(key, data); return true; @@ -1050,7 +1050,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa // Add to theme part cache if (!isCached) { - memset(&data, 0, sizeof(data)); + memset(static_cast(&data), 0, sizeof(data)); data.dataValid = true; data.partIsTransparent = partIsTransparent; data.alphaType = alphaType; From 8d99965161f72b46cdbec53b725c824206ebd3c3 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 18 Apr 2016 17:30:07 -0400 Subject: [PATCH 049/123] [Backport] Remove usage of auto_ptr in MacroExpander BUG=angleproject:1269 Task-number: QTBUG-68954 Change-Id: Ie4ebea85bc3721e79c7414dea62ca7a042b2421c Reviewed-by: Kai Koehne --- .../src/compiler/preprocessor/MacroExpander.h | 2 +- ...e-usage-of-auto_ptr-in-MacroExpander.patch | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch diff --git a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h index 3cc860d7535..dc870f626f2 100644 --- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h @@ -83,7 +83,7 @@ class MacroExpander : public Lexer Diagnostics *mDiagnostics; bool mParseDefined; - std::auto_ptr mReserveToken; + std::unique_ptr mReserveToken; std::vector mContextStack; }; diff --git a/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch new file mode 100644 index 00000000000..314a985babe --- /dev/null +++ b/src/angle/patches/0017-Remove-usage-of-auto_ptr-in-MacroExpander.patch @@ -0,0 +1,31 @@ +From 946903d23ae361ddb05d2c0f64b339eb1694311b Mon Sep 17 00:00:00 2001 +From: Corentin Wallez +Date: Mon, 18 Apr 2016 17:30:07 -0400 +Subject: [PATCH] Remove usage of auto_ptr in MacroExpander + +BUG=angleproject:1269 + +Change-Id: I1fafa102b065f6da1797e8790ec3ed498d9d8b45 +Reviewed-on: https://chromium-review.googlesource.com/339379 +Reviewed-by: Jamie Madill +Commit-Queue: Corentin Wallez +--- + src/compiler/preprocessor/MacroExpander.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compiler/preprocessor/MacroExpander.h b/src/compiler/preprocessor/MacroExpander.h +index 3cc860d75..dc870f626 100644 +--- a/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h ++++ b/src/3rdparty/angle/src/compiler/preprocessor/MacroExpander.h +@@ -83,7 +83,7 @@ class MacroExpander : public Lexer + Diagnostics *mDiagnostics; + bool mParseDefined; + +- std::auto_ptr mReserveToken; ++ std::unique_ptr mReserveToken; + std::vector mContextStack; + }; + +-- +2.15.0.windows.1 + From cd08753d3e2ac02663ba0ab588d7d926f7438475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Sun, 17 Jun 2018 11:07:37 +0200 Subject: [PATCH 050/123] =?UTF-8?q?cocoa:=20Don=E2=80=99t=20trigger=20secu?= =?UTF-8?q?rity=20dialog=20on=20drag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS 10.14+ will display an “Accessibility Access” security dialog if we generate mouse events, so don’t. Task-number: QTBUG-68830 Change-Id: If832ca3cd49ec6bdad1a8188feab884b6562e9d2 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index c88ffc76d7a..1c400a1ec97 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1941,7 +1941,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin [nativeCursor set]; // Make sure the cursor is updated correctly if the mouse does not move and window is under cursor - // by creating a fake move event + // by creating a fake move event, unless on 10.14 and later where doing so will trigger a security + // warning dialog. FIXME: Find a way to update the cursor without fake mouse events. + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) + return; + if (m_updatingDrag) return; From ca1ad3b7cbf6d2b20787661fac1dc48da2999a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 20 Jun 2018 00:30:17 +0200 Subject: [PATCH 051/123] Cocoa: Tool windows should always be resizable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Undocked dock windows have the following flags: Tool|X11BypassWindowManagerHint|WindowTitleHint| WindowSystemMenuHint|CustomizeWindowHint|WindowCloseButtonHint CustomizeWindowHint with no WindowMaximizeButtonHint means that we disable window resize in order to remove the zoom button (this is perhaps questionable, but is established behavior). That will however break dock windows: add exception for Qt::Tool. After refactoring we discover this special case, again. See previous fix in d37643c43. Change-Id: I67a09341e75b92fdb3108ea93901295c39107fe1 History-repeats: QTBUG-46882 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 72f3bc0075c..e350d7db519 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -505,7 +505,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) { const Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); const bool frameless = (flags & Qt::FramelessWindowHint) || windowIsPopupType(type); - const bool resizeable = !(flags & Qt::CustomizeWindowHint); // Remove zoom button by disabling resize + + // Remove zoom button by disabling resize for CustomizeWindowHint windows, except for + // Qt::Tool windows (e.g. dock windows) which should always be resizeable. + const bool resizeable = !(flags & Qt::CustomizeWindowHint) || (type == Qt::Tool); // Select base window type. Note that the value of NSBorderlessWindowMask is 0. NSUInteger styleMask = (frameless || !resizeable) ? NSBorderlessWindowMask : NSResizableWindowMask; From 581257bd2e320344d1ff279afc7f43bcf2870225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Wed, 20 Jun 2018 00:30:51 +0200 Subject: [PATCH 052/123] Cocoa: handle WindowMaximizeButtonHint as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I6af265d48e83fc3fc0ce86903820c2b37db05f03 Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index e350d7db519..2415e165dc6 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -522,6 +522,8 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) styleMask |= NSClosableWindowMask; if (flags & Qt::WindowMinimizeButtonHint) styleMask |= NSMiniaturizableWindowMask; + if (flags & Qt::WindowMaximizeButtonHint) + styleMask |= NSResizableWindowMask; } else { styleMask |= NSClosableWindowMask | NSTitledWindowMask; From ee3ed1a0abce55c92efc36d4e6c26e83720f9c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 20 Jun 2018 16:53:41 +0200 Subject: [PATCH 053/123] Android: Blacklist tst_qkeyevent Task-number: QTBUG-68974 Change-Id: I9178f91b44bc27a055a4bb743374a8bd1dfa5599 Reviewed-by: Frederik Gladhorn --- tests/auto/gui/kernel/qkeyevent/BLACKLIST | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/auto/gui/kernel/qkeyevent/BLACKLIST diff --git a/tests/auto/gui/kernel/qkeyevent/BLACKLIST b/tests/auto/gui/kernel/qkeyevent/BLACKLIST new file mode 100644 index 00000000000..e55a200f4d5 --- /dev/null +++ b/tests/auto/gui/kernel/qkeyevent/BLACKLIST @@ -0,0 +1,6 @@ +# QTBUG-68974 +[basicEventDelivery] +android +# QTBUG-68974 +[modifiers] +android From 06044df0e3d881bcfa2537ad1301468d49ad544c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 8 Jun 2018 12:42:58 +0200 Subject: [PATCH 054/123] Android: tst_qthread: terminate is not supported "terminate" and "terminated" both fail on Android since QThread::terminate not supported on Android. So we should skip them. Task-number: QTBUG-68596 Change-Id: Id0d1dde2cfa02bb2978e5dd16087bf8f3bf112b0 Reviewed-by: Thiago Macieira --- tests/auto/corelib/thread/qthread/tst_qthread.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp index aee243d8807..d73dcc1b6d3 100644 --- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp +++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp @@ -465,8 +465,8 @@ void tst_QThread::start() void tst_QThread::terminate() { -#if defined(Q_OS_WINRT) - QSKIP("Thread termination is not supported on WinRT."); +#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID) + QSKIP("Thread termination is not supported on WinRT or Android."); #endif Terminate_Thread thread; { @@ -531,8 +531,8 @@ void tst_QThread::finished() void tst_QThread::terminated() { -#if defined(Q_OS_WINRT) - QSKIP("Thread termination is not supported on WinRT."); +#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID) + QSKIP("Thread termination is not supported on WinRT or Android."); #endif SignalRecorder recorder; Terminate_Thread thread; From 22ec652ebfb659e8597d4986bd32c3ea82e3e075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Thu, 7 Jun 2018 17:07:09 +0200 Subject: [PATCH 055/123] QFINDTESTDATA,Android: fix 'relative to test source' When cross-compiling for Android on Windows the 'relative to test source' option could end up possibly matching with a matching folder in root ('/') because file is a Windows path and the canonicalFilePath of that path is "". Fixes tst_qxmlstream (and possibly others) on Android when Qt is compiled on Windows. Task-number: QTBUG-68596 Change-Id: I378374e41eea80f43680b3941adaa91fa604934a Reviewed-by: Jesus Fernandez Reviewed-by: Thiago Macieira Reviewed-by: Ulf Hermann --- src/testlib/qtestcase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index adf4b9e1efa..acd676833e8 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2135,8 +2135,9 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co srcdir.setFile(QFile::decodeName(builddir) + QLatin1String("/") + srcdir.filePath()); } - QString candidate = QString::fromLatin1("%1/%2").arg(srcdir.canonicalFilePath(), base); - if (QFileInfo::exists(candidate)) { + const QString canonicalPath = srcdir.canonicalFilePath(); + QString candidate = QString::fromLatin1("%1/%2").arg(canonicalPath, base); + if (!canonicalPath.isEmpty() && QFileInfo::exists(candidate)) { found = candidate; } else if (QTestLog::verboseLevel() >= 2) { From 06996e1d0e90fa89d3f18456da91d80c9a6a95f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 6 Jun 2018 14:54:41 +0200 Subject: [PATCH 056/123] Android: fix qdiriterator test ... by adding a prefix to the resource. On android there is a resource ("qpdf") which gets included in the root in all applications, included from "src/gui/painting/painting.pri". So we move the test data to a sub-folder. Task-number: QTBUG-68596 Change-Id: I67f2ed79a32c68d9a76cafba8ef23fe0da7c0fe8 Reviewed-by: Thiago Macieira --- .../corelib/io/qdiriterator/qdiriterator.qrc | 2 +- .../io/qdiriterator/tst_qdiriterator.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc index 058d4747809..af9998bdb42 100644 --- a/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc +++ b/tests/auto/corelib/io/qdiriterator/qdiriterator.qrc @@ -1,5 +1,5 @@ - + entrylist/file entrylist/directory/dummy diff --git a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp index a55989aacd3..0b125925bba 100644 --- a/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp +++ b/tests/auto/corelib/io/qdiriterator/tst_qdiriterator.cpp @@ -120,7 +120,7 @@ void tst_QDirIterator::initTestCase() { #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) QString testdata_dir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - QString resourceSourcePath = QStringLiteral(":/"); + QString resourceSourcePath = QStringLiteral(":/testdata"); QDirIterator it(resourceSourcePath, QDirIterator::Subdirectories); while (it.hasNext()) { it.next(); @@ -141,7 +141,7 @@ void tst_QDirIterator::initTestCase() testdata_dir += QStringLiteral("/entrylist"); #elif defined(BUILTIN_TESTDATA) - m_dataDir = QEXTRACTTESTDATA("/"); + m_dataDir = QEXTRACTTESTDATA("/testdata"); QVERIFY2(!m_dataDir.isNull(), qPrintable("Could not extract test data")); QString testdata_dir = m_dataDir->path(); #else @@ -399,18 +399,18 @@ void tst_QDirIterator::iterateResource_data() QTest::addColumn("nameFilters"); QTest::addColumn("entries"); - QTest::newRow("invalid") << QString::fromLatin1(":/burpaburpa") << QDirIterator::IteratorFlags(0) + QTest::newRow("invalid") << QString::fromLatin1(":/testdata/burpaburpa") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) << QStringList(); - QTest::newRow(":/") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(0) + QTest::newRow(":/testdata") << QString::fromLatin1(":/testdata/") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist").split(QLatin1String(",")); - QTest::newRow(":/entrylist") << QString::fromLatin1(":/entrylist") << QDirIterator::IteratorFlags(0) + << QString::fromLatin1(":/testdata/entrylist").split(QLatin1String(",")); + QTest::newRow(":/testdata/entrylist") << QString::fromLatin1(":/testdata/entrylist") << QDirIterator::IteratorFlags(0) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist/directory,:/entrylist/file").split(QLatin1String(",")); - QTest::newRow(":/ recursive") << QString::fromLatin1(":/") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) + << QString::fromLatin1(":/testdata/entrylist/directory,:/testdata/entrylist/file").split(QLatin1String(",")); + QTest::newRow(":/testdata recursive") << QString::fromLatin1(":/testdata") << QDirIterator::IteratorFlags(QDirIterator::Subdirectories) << QDir::Filters(QDir::NoFilter) << QStringList(QLatin1String("*")) - << QString::fromLatin1(":/entrylist,:/entrylist/directory,:/entrylist/directory/dummy,:/entrylist/file").split(QLatin1String(",")); + << QString::fromLatin1(":/testdata/entrylist,:/testdata/entrylist/directory,:/testdata/entrylist/directory/dummy,:/testdata/entrylist/file").split(QLatin1String(",")); } void tst_QDirIterator::iterateResource() From f415f50619ceedff05bcf97336cf05374130a2a7 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Wed, 13 Jun 2018 13:04:10 +0200 Subject: [PATCH 057/123] Doc: Add menu bar to Books example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add menu bar with Help->About that contains a short description of the example application. Remove redundant title string between menu and application content. Task-number: QTBUG-68652 Change-Id: I31fb386ab9c01eff86b8ed3ef274ba8cfdb0148b Reviewed-by: Topi Reiniö --- examples/sql/books/bookwindow.cpp | 26 ++++++++++++++++++++++++++ examples/sql/books/bookwindow.h | 5 +++++ examples/sql/books/bookwindow.ui | 2 +- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/examples/sql/books/bookwindow.cpp b/examples/sql/books/bookwindow.cpp index 3aac5b55b72..76f3c9da8f1 100644 --- a/examples/sql/books/bookwindow.cpp +++ b/examples/sql/books/bookwindow.cpp @@ -136,6 +136,7 @@ BookWindow::BookWindow() ); ui.bookTable->setCurrentIndex(model->index(0, 0)); + createMenuBar(); } void BookWindow::showError(const QSqlError &err) @@ -143,3 +144,28 @@ void BookWindow::showError(const QSqlError &err) QMessageBox::critical(this, "Unable to initialize Database", "Error initializing database: " + err.text()); } + +void BookWindow::createMenuBar() +{ + QAction *quitAction = new QAction(tr("&Quit"), this); + QAction *aboutAction = new QAction(tr("&About"), this); + QAction *aboutQtAction = new QAction(tr("&About Qt"), this); + + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + fileMenu->addAction(quitAction); + + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(aboutAction); + helpMenu->addAction(aboutQtAction); + + connect(quitAction, &QAction::triggered, this, &BookWindow::close); + connect(aboutAction, &QAction::triggered, this, &BookWindow::about); + connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt); +} + +void BookWindow::about() +{ + QMessageBox::about(this, tr("About Books"), + tr("

The Books example shows how to use Qt SQL classes " + "with a model/view framework.")); +} diff --git a/examples/sql/books/bookwindow.h b/examples/sql/books/bookwindow.h index 4b2be0e7291..ec6b935242f 100644 --- a/examples/sql/books/bookwindow.h +++ b/examples/sql/books/bookwindow.h @@ -63,11 +63,16 @@ class BookWindow: public QMainWindow public: BookWindow(); +private slots: + void about(); + private: void showError(const QSqlError &err); Ui::BookWindow ui; QSqlRelationalTableModel *model; int authorIdx, genreIdx; + + void createMenuBar(); }; #endif diff --git a/examples/sql/books/bookwindow.ui b/examples/sql/books/bookwindow.ui index c81a86cb2ca..ce8f9f933af 100644 --- a/examples/sql/books/bookwindow.ui +++ b/examples/sql/books/bookwindow.ui @@ -33,7 +33,7 @@ - Books + From 8bd73ad989e5850b48941c7d286181c6b394b05a Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Mon, 18 Jun 2018 13:11:18 +0200 Subject: [PATCH 058/123] Doc: Add missing full stops in briefs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-68933 Change-Id: I3f2a9f8c562f9a44bb32bddd31d75abbfe6de04d Reviewed-by: Topi Reiniö --- examples/corelib/threads/doc/src/queuedcustomtype.qdoc | 2 +- examples/corelib/threads/doc/src/semaphores.qdoc | 2 +- examples/corelib/threads/doc/src/waitconditions.qdoc | 2 +- examples/corelib/tools/doc/src/contiguouscache.qdoc | 2 +- examples/network/doc/src/blockingfortuneclient.qdoc | 2 +- examples/network/doc/src/fortuneclient.qdoc | 2 +- examples/network/doc/src/googlesuggest.qdoc | 2 +- examples/network/doc/src/http.qdoc | 2 +- examples/network/doc/src/loopback.qdoc | 2 +- examples/network/doc/src/multicastreceiver.qdoc | 2 +- examples/network/doc/src/multicastsender.qdoc | 2 +- examples/network/doc/src/network-chat.qdoc | 2 +- examples/network/doc/src/network-download.qdoc | 2 +- examples/network/doc/src/network-downloadmanager.qdoc | 2 +- examples/network/doc/src/securesocketclient.qdoc | 2 +- examples/network/doc/src/torrent.qdoc | 2 +- .../wordcount/doc/src/qtconcurrent-wordcount.qdoc | 2 +- examples/vulkan/doc/src/hellovulkancubes.qdoc | 2 +- examples/vulkan/doc/src/hellovulkantexture.qdoc | 2 +- examples/vulkan/doc/src/hellovulkantriangle.qdoc | 2 +- examples/vulkan/doc/src/hellovulkanwidget.qdoc | 2 +- examples/vulkan/doc/src/hellovulkanwindow.qdoc | 2 +- examples/widgets/doc/src/basicgraphicslayouts.qdoc | 2 +- examples/widgets/doc/src/blurpicker.qdoc | 2 +- examples/widgets/doc/src/boxes.qdoc | 2 +- examples/widgets/doc/src/chip.qdoc | 2 +- examples/widgets/doc/src/collidingmice-example.qdoc | 2 +- examples/widgets/doc/src/diagramscene.qdoc | 2 +- examples/widgets/doc/src/dragdroprobot.qdoc | 2 +- examples/widgets/doc/src/draggabletext.qdoc | 2 +- examples/widgets/doc/src/elasticnodes.qdoc | 2 +- examples/widgets/doc/src/embeddeddialogs.qdoc | 2 +- examples/widgets/doc/src/fademessage.qdoc | 2 +- examples/widgets/doc/src/findfiles.qdoc | 2 +- examples/widgets/doc/src/graphicsview-anchorlayout.qdoc | 2 +- .../widgets/doc/src/graphicsview-simpleanchorlayout.qdoc | 2 +- .../widgets/doc/src/graphicsview-weatheranchorlayout.qdoc | 2 +- examples/widgets/doc/src/padnavigator.qdoc | 2 +- .../gestures/imagegestures/doc/src/imagegestures.qdoc | 2 +- examples/widgets/tutorials/gettingstartedqt.qdoc | 2 +- examples/xml/dombookmarks/doc/src/dombookmarks.qdoc | 2 +- examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc | 2 +- .../xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc | 2 +- src/concurrent/doc/src/qtconcurrent-module.qdoc | 2 +- src/corelib/animation/qpropertyanimation.cpp | 2 +- src/corelib/global/qglobalstatic.qdoc | 2 +- src/corelib/io/qdebug.cpp | 2 +- src/corelib/itemmodels/qidentityproxymodel.cpp | 2 +- src/corelib/kernel/qobject.cpp | 2 +- src/corelib/serialization/qxmlstream.cpp | 2 +- src/corelib/thread/qsemaphore.cpp | 2 +- src/corelib/tools/qbytearraymatcher.cpp | 2 +- src/corelib/tools/qsharedpointer.cpp | 6 +++--- src/dbus/qdbusabstractinterface.cpp | 2 +- src/dbus/qdbuspendingcall.cpp | 4 ++-- src/dbus/qdbuspendingreply.cpp | 2 +- src/gui/kernel/qpixelformat.cpp | 2 +- src/gui/kernel/qrasterwindow.cpp | 2 +- src/gui/opengl/qopenglfunctions_es2.cpp | 2 +- src/gui/painting/qpagesize.cpp | 2 +- src/gui/text/qplatformfontdatabase.cpp | 2 +- src/network/access/qnetworkaccessmanager.cpp | 2 +- src/network/access/qnetworkcookiejar.cpp | 2 +- src/network/access/qnetworkreply.cpp | 2 +- src/network/doc/src/qtnetwork.qdoc | 2 +- src/network/ssl/qsslconfiguration.cpp | 2 +- src/platformheaders/nativecontexts/qeglnativecontext.qdoc | 2 +- src/platformheaders/nativecontexts/qwglnativecontext.qdoc | 2 +- src/widgets/widgets/qplaintextedit.cpp | 2 +- src/widgets/widgets/qtextedit.cpp | 2 +- 70 files changed, 73 insertions(+), 73 deletions(-) diff --git a/examples/corelib/threads/doc/src/queuedcustomtype.qdoc b/examples/corelib/threads/doc/src/queuedcustomtype.qdoc index 015007cae1a..86d59922941 100644 --- a/examples/corelib/threads/doc/src/queuedcustomtype.qdoc +++ b/examples/corelib/threads/doc/src/queuedcustomtype.qdoc @@ -28,7 +28,7 @@ /*! \example threads/queuedcustomtype \title Queued Custom Type Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Queued Custom Type example shows how to send custom types between diff --git a/examples/corelib/threads/doc/src/semaphores.qdoc b/examples/corelib/threads/doc/src/semaphores.qdoc index ccbfcdb6e26..5293e80c0e7 100644 --- a/examples/corelib/threads/doc/src/semaphores.qdoc +++ b/examples/corelib/threads/doc/src/semaphores.qdoc @@ -28,7 +28,7 @@ /*! \example threads/semaphores \title Semaphores Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Semaphores example shows how to use QSemaphore to control diff --git a/examples/corelib/threads/doc/src/waitconditions.qdoc b/examples/corelib/threads/doc/src/waitconditions.qdoc index 5a6831ede4e..cfac4603454 100644 --- a/examples/corelib/threads/doc/src/waitconditions.qdoc +++ b/examples/corelib/threads/doc/src/waitconditions.qdoc @@ -28,7 +28,7 @@ /*! \example threads/waitconditions \title Wait Conditions Example - \brief Demonstrates multi-thread programming using Qt + \brief Demonstrates multi-thread programming using Qt. \ingroup qtconcurrent-mtexamples \brief The Wait Conditions example shows how to use QWaitCondition and diff --git a/examples/corelib/tools/doc/src/contiguouscache.qdoc b/examples/corelib/tools/doc/src/contiguouscache.qdoc index c2c686b237a..0d06036cd18 100644 --- a/examples/corelib/tools/doc/src/contiguouscache.qdoc +++ b/examples/corelib/tools/doc/src/contiguouscache.qdoc @@ -34,7 +34,7 @@ isn't, users still dislike an application using excessive memory. Using QContiguousCache to manage a list, rather than loading the entire list into memory, allows the application to limit the amount - of memory it uses, regardless of the size of the data set it accesses + of memory it uses, regardless of the size of the data set it accesses. The simplest way to use QContiguousCache is to cache as items are requested. When a view requests an item at row N it is also likely to ask for items at rows near diff --git a/examples/network/doc/src/blockingfortuneclient.qdoc b/examples/network/doc/src/blockingfortuneclient.qdoc index 6719a4e0b97..ecb9a7ba62c 100644 --- a/examples/network/doc/src/blockingfortuneclient.qdoc +++ b/examples/network/doc/src/blockingfortuneclient.qdoc @@ -29,7 +29,7 @@ \example blockingfortuneclient \title Blocking Fortune Client Example \ingroup examples-network - \brief Demonstrates how to create a client for a network service + \brief Demonstrates how to create a client for a network service. \image blockingfortuneclient-example.png diff --git a/examples/network/doc/src/fortuneclient.qdoc b/examples/network/doc/src/fortuneclient.qdoc index f2ad5751251..544fa156b7a 100644 --- a/examples/network/doc/src/fortuneclient.qdoc +++ b/examples/network/doc/src/fortuneclient.qdoc @@ -29,7 +29,7 @@ \example fortuneclient \title Fortune Client Example \ingroup examples-network - \brief Demonstrates how to create a client for a network service + \brief Demonstrates how to create a client for a network service. This example uses QTcpSocket, and is intended to be run alongside the \l{fortuneserver}{Fortune Server} example or diff --git a/examples/network/doc/src/googlesuggest.qdoc b/examples/network/doc/src/googlesuggest.qdoc index 50cdb694bac..adb87f4b662 100644 --- a/examples/network/doc/src/googlesuggest.qdoc +++ b/examples/network/doc/src/googlesuggest.qdoc @@ -29,7 +29,7 @@ \example googlesuggest \title Google Suggest Example \ingroup examples-network - \brief Obtains the list of search recommendations by the Google search engine + \brief Obtains the list of search recommendations by the Google search engine. The example uses the QNetworkAccessManager to obtain the list of search recommendations by Google as the user types into a QLineEdit. diff --git a/examples/network/doc/src/http.qdoc b/examples/network/doc/src/http.qdoc index f4301e7d959..1a701873690 100644 --- a/examples/network/doc/src/http.qdoc +++ b/examples/network/doc/src/http.qdoc @@ -29,7 +29,7 @@ \example http \title HTTP Example \ingroup examples-network - \brief Demonstrates a simple HTTP client + \brief Demonstrates a simple HTTP client. This example demonstrates how a simple HTTP client can fetch files from remote hosts. diff --git a/examples/network/doc/src/loopback.qdoc b/examples/network/doc/src/loopback.qdoc index 189c4ee0da2..f97c9f9c716 100644 --- a/examples/network/doc/src/loopback.qdoc +++ b/examples/network/doc/src/loopback.qdoc @@ -29,7 +29,7 @@ \example loopback \title Loopback Example \ingroup examples-network - \brief Demonstrates the client-server communication on a local host + \brief Demonstrates the client-server communication on a local host. The example demonstrates how the clients and servers on a local host communicate with each other. diff --git a/examples/network/doc/src/multicastreceiver.qdoc b/examples/network/doc/src/multicastreceiver.qdoc index a0579d7284e..37097504365 100644 --- a/examples/network/doc/src/multicastreceiver.qdoc +++ b/examples/network/doc/src/multicastreceiver.qdoc @@ -29,7 +29,7 @@ \example multicastreceiver \title Multicast Receiver Example \ingroup examples-network - \brief Demonstrates how to receive information sent to a multicast group + \brief Demonstrates how to receive information sent to a multicast group. This example demonstrates how to receive messages sent to a multicast group \image multicastreceiver-example.png diff --git a/examples/network/doc/src/multicastsender.qdoc b/examples/network/doc/src/multicastsender.qdoc index 3adc8959baf..72558eb0624 100644 --- a/examples/network/doc/src/multicastsender.qdoc +++ b/examples/network/doc/src/multicastsender.qdoc @@ -29,7 +29,7 @@ \example multicastsender \title Multicast Sender Example \ingroup examples-network - \brief Demonstrates how to send messages to a multicast group + \brief Demonstrates how to send messages to a multicast group. This example demonstrates how to send messages to the clients of a multicast group. diff --git a/examples/network/doc/src/network-chat.qdoc b/examples/network/doc/src/network-chat.qdoc index 701dc76ec33..85edf611b6c 100644 --- a/examples/network/doc/src/network-chat.qdoc +++ b/examples/network/doc/src/network-chat.qdoc @@ -29,7 +29,7 @@ \example network-chat \title Network Chat Example \ingroup examples-network - \brief Demonstrates a stateful peer-to-peer Chat client + \brief Demonstrates a stateful peer-to-peer Chat client. This example uses broadcasting with QUdpSocket and QNetworkInterface to discover its peers. diff --git a/examples/network/doc/src/network-download.qdoc b/examples/network/doc/src/network-download.qdoc index e51da38ed82..9d171e41423 100644 --- a/examples/network/doc/src/network-download.qdoc +++ b/examples/network/doc/src/network-download.qdoc @@ -28,7 +28,7 @@ /*! \example download \title Network Download Example - \brief Demonstrates how to use networking APIs for multiple downloads + \brief Demonstrates how to use networking APIs for multiple downloads. \ingroup examples-network The Network Download example shows how to perform multiple downloads in diff --git a/examples/network/doc/src/network-downloadmanager.qdoc b/examples/network/doc/src/network-downloadmanager.qdoc index ca65b8e559f..f89ed666164 100644 --- a/examples/network/doc/src/network-downloadmanager.qdoc +++ b/examples/network/doc/src/network-downloadmanager.qdoc @@ -28,7 +28,7 @@ /*! \example downloadmanager \title Network Download Manager Example - \brief Demonstrates how to use the networking APIs for multiple downloads + \brief Demonstrates how to use the networking APIs for multiple downloads. \ingroup examples-network The Network Download example shows how to implement a queue for multiple diff --git a/examples/network/doc/src/securesocketclient.qdoc b/examples/network/doc/src/securesocketclient.qdoc index 052e6ad868f..78cfab7af42 100644 --- a/examples/network/doc/src/securesocketclient.qdoc +++ b/examples/network/doc/src/securesocketclient.qdoc @@ -29,7 +29,7 @@ \example securesocketclient \title Secure Socket Client Example \ingroup examples-network - \brief Demonstrates how to communicate over an encrypted (SSL) connection + \brief Demonstrates how to communicate over an encrypted (SSL) connection. This example uses QSslSocket to demonstrate how to communicate over an encrypted connection, deal with authenticity problems, and display security diff --git a/examples/network/doc/src/torrent.qdoc b/examples/network/doc/src/torrent.qdoc index 2ef5be8171f..8d69bee6d1a 100644 --- a/examples/network/doc/src/torrent.qdoc +++ b/examples/network/doc/src/torrent.qdoc @@ -29,7 +29,7 @@ \example torrent \title Torrent Example \ingroup examples-network - \brief Demonstrates complex TCP/IP operations + \brief Demonstrates complex TCP/IP operations. This example demonstrates some of the complex TCP/IP operations supported by the Qt Network APIs. diff --git a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc index 1b112d2966d..7486340c7b9 100644 --- a/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc +++ b/examples/qtconcurrent/wordcount/doc/src/qtconcurrent-wordcount.qdoc @@ -28,7 +28,7 @@ /*! \example wordcount \title QtConcurrent Word Count Example - \brief Demonstrates how to use the map-reduce algorithm + \brief Demonstrates how to use the map-reduce algorithm. \ingroup qtconcurrentexamples The QtConcurrent Word Count example demonstrates the use of the map-reduce diff --git a/examples/vulkan/doc/src/hellovulkancubes.qdoc b/examples/vulkan/doc/src/hellovulkancubes.qdoc index 934d2015a1a..8fa3243024d 100644 --- a/examples/vulkan/doc/src/hellovulkancubes.qdoc +++ b/examples/vulkan/doc/src/hellovulkancubes.qdoc @@ -29,7 +29,7 @@ \example hellovulkancubes \title Hello Vulkan Cubes Example \ingroup examples-vulkan - \brief Shows the basics of using QVulkanWindow + \brief Shows the basics of using QVulkanWindow. The \e{Hello Vulkan Cubes Example} shows more advanced usage of QVulkanWindow. diff --git a/examples/vulkan/doc/src/hellovulkantexture.qdoc b/examples/vulkan/doc/src/hellovulkantexture.qdoc index d0e0ca90a87..4284e4a05c4 100644 --- a/examples/vulkan/doc/src/hellovulkantexture.qdoc +++ b/examples/vulkan/doc/src/hellovulkantexture.qdoc @@ -29,7 +29,7 @@ \example hellovulkantexture \ingroup examples-vulkan \title Hello Vulkan Texture Vulkan Example - \brief Shows the basics of rendering with textures in a QVulkanWindow + \brief Shows the basics of rendering with textures in a QVulkanWindow. The \e{Hello Vulkan Texture Example} builds on \l hellovulkantriangle. Here instead of drawing a single triangle, a triangle strip is drawn in order to diff --git a/examples/vulkan/doc/src/hellovulkantriangle.qdoc b/examples/vulkan/doc/src/hellovulkantriangle.qdoc index 81af776ea1c..57793cf25ad 100644 --- a/examples/vulkan/doc/src/hellovulkantriangle.qdoc +++ b/examples/vulkan/doc/src/hellovulkantriangle.qdoc @@ -29,7 +29,7 @@ \example hellovulkantriangle \ingroup examples-vulkan \title Hello Vulkan Triangle Example - \brief Shows the basics of rendering with QVulkanWindow and the Vulkan API + \brief Shows the basics of rendering with QVulkanWindow and the Vulkan API. The \e{Hello Vulkan Triangle Example} builds on \l hellovulkanwindow. This time a full graphics pipeline is created, including a vertex and fragment diff --git a/examples/vulkan/doc/src/hellovulkanwidget.qdoc b/examples/vulkan/doc/src/hellovulkanwidget.qdoc index 7987bdeff96..b5ad43ba2aa 100644 --- a/examples/vulkan/doc/src/hellovulkanwidget.qdoc +++ b/examples/vulkan/doc/src/hellovulkanwidget.qdoc @@ -29,7 +29,7 @@ \example hellovulkanwidget \ingroup examples-vulkan \title Hello Vulkan Widget Example - \brief Shows the usage of QVulkanWindow in QWidget applications + \brief Shows the usage of QVulkanWindow in QWidget applications. The \e{Hello Vulkan Widget Example} is a variant of \l hellovulkantriangle that embeds the QVulkanWindow into a QWidget-based user interface using diff --git a/examples/vulkan/doc/src/hellovulkanwindow.qdoc b/examples/vulkan/doc/src/hellovulkanwindow.qdoc index 06cc9c1c288..a9682b7e90c 100644 --- a/examples/vulkan/doc/src/hellovulkanwindow.qdoc +++ b/examples/vulkan/doc/src/hellovulkanwindow.qdoc @@ -29,7 +29,7 @@ \example hellovulkanwindow \title Hello Vulkan Window Example \ingroup examples-vulkan - \brief Shows the basics of using QVulkanWindow + \brief Shows the basics of using QVulkanWindow. The \e{Hello Vulkan Window Example} shows the basics of using QVulkanWindow in order to display rendering with the Vulkan graphics API on systems that diff --git a/examples/widgets/doc/src/basicgraphicslayouts.qdoc b/examples/widgets/doc/src/basicgraphicslayouts.qdoc index 233b8c7c0a4..23661d0558c 100644 --- a/examples/widgets/doc/src/basicgraphicslayouts.qdoc +++ b/examples/widgets/doc/src/basicgraphicslayouts.qdoc @@ -29,7 +29,7 @@ \example graphicsview/basicgraphicslayouts \title Basic Graphics Layouts Example \ingroup examples-graphicsview-layout - \brief Demonstrates how to create basic graphics layout + \brief Demonstrates how to create basic graphics layout. The Basic Graphics Layouts example shows how to use the layout classes in QGraphicsView: QGraphicsLinearLayout and QGraphicsGridLayout. diff --git a/examples/widgets/doc/src/blurpicker.qdoc b/examples/widgets/doc/src/blurpicker.qdoc index 87f36389e7d..d4d84f72483 100644 --- a/examples/widgets/doc/src/blurpicker.qdoc +++ b/examples/widgets/doc/src/blurpicker.qdoc @@ -29,7 +29,7 @@ \example effects/blurpicker \title Blur Picker Effect Example \ingroup examples-graphicsview-graphicseffects - \brief Demonstrates how to apply graphical effects on items in the view + \brief Demonstrates how to apply graphical effects on items in the view. \image blurpickereffect-example.png diff --git a/examples/widgets/doc/src/boxes.qdoc b/examples/widgets/doc/src/boxes.qdoc index 7c9031a003a..276c6fa78d1 100644 --- a/examples/widgets/doc/src/boxes.qdoc +++ b/examples/widgets/doc/src/boxes.qdoc @@ -29,7 +29,7 @@ \example graphicsview/boxes \title Boxes \ingroup examples-graphicsview - \brief Combines advanced OpenGL rendering with the Graphics View framework + \brief Combines advanced OpenGL rendering with the Graphics View framework. \image boxes-demo.png diff --git a/examples/widgets/doc/src/chip.qdoc b/examples/widgets/doc/src/chip.qdoc index 4cef4984e3b..758b692f0e6 100644 --- a/examples/widgets/doc/src/chip.qdoc +++ b/examples/widgets/doc/src/chip.qdoc @@ -29,7 +29,7 @@ \example graphicsview/chip \title 40000 Chips \ingroup examples-graphicsview - \brief Visualizes a huge graphic view scene with 40000 chip items + \brief Visualizes a huge graphic view scene with 40000 chip items. This examples demonstrates Graphics View's powerful navigation and interaction features, allowing you to zoom and rotate each of four diff --git a/examples/widgets/doc/src/collidingmice-example.qdoc b/examples/widgets/doc/src/collidingmice-example.qdoc index 535057bb6a5..657c4162182 100644 --- a/examples/widgets/doc/src/collidingmice-example.qdoc +++ b/examples/widgets/doc/src/collidingmice-example.qdoc @@ -28,7 +28,7 @@ /*! \example graphicsview/collidingmice \title Colliding Mice Example - \brief Demonstrates how to animate items on a graphics view + \brief Demonstrates how to animate items on a graphics view. \ingroup examples-graphicsview The Colliding Mice example shows how to use the Graphics View diff --git a/examples/widgets/doc/src/diagramscene.qdoc b/examples/widgets/doc/src/diagramscene.qdoc index 1c9f4faf882..ca4876f2e8d 100644 --- a/examples/widgets/doc/src/diagramscene.qdoc +++ b/examples/widgets/doc/src/diagramscene.qdoc @@ -29,7 +29,7 @@ \example graphicsview/diagramscene \title Diagram Scene Example \ingroup examples-graphicsview - \brief Demonstrate how to use the Graphics View framework + \brief Demonstrate how to use the Graphics View framework. \image diagramscene.png diff --git a/examples/widgets/doc/src/dragdroprobot.qdoc b/examples/widgets/doc/src/dragdroprobot.qdoc index f74b898e1bd..ac138072c97 100644 --- a/examples/widgets/doc/src/dragdroprobot.qdoc +++ b/examples/widgets/doc/src/dragdroprobot.qdoc @@ -29,7 +29,7 @@ \example graphicsview/dragdroprobot \title Drag and Drop Robot Example \ingroup examples-graphicsview - \brief Demonstrates how to drag and drop items in a graphics view + \brief Demonstrates how to drag and drop items in a graphics view. The Drag and Drop Robot example shows how to implement Drag and Drop in a QGraphicsItem subclass, as well as how to animate items using Qt's diff --git a/examples/widgets/doc/src/draggabletext.qdoc b/examples/widgets/doc/src/draggabletext.qdoc index 97b2f036bde..e934119e7a2 100644 --- a/examples/widgets/doc/src/draggabletext.qdoc +++ b/examples/widgets/doc/src/draggabletext.qdoc @@ -28,7 +28,7 @@ /*! \example draganddrop/draggabletext \title Draggable Text Example - \brief Illustrates how to drag and drop text between widgets + \brief Illustrates how to drag and drop text between widgets. \brief The Draggable Text example shows how to drag and drop textual data between widgets in the same application, and between different applications. diff --git a/examples/widgets/doc/src/elasticnodes.qdoc b/examples/widgets/doc/src/elasticnodes.qdoc index 65e11951213..e78db67be21 100644 --- a/examples/widgets/doc/src/elasticnodes.qdoc +++ b/examples/widgets/doc/src/elasticnodes.qdoc @@ -29,7 +29,7 @@ \example graphicsview/elasticnodes \title Elastic Nodes Example \ingroup examples-graphicsview - \brief Demonstrates how to interact with graphical items in a scene + \brief Demonstrates how to interact with graphical items in a scene. The Elastic Nodes example shows how to implement edges between nodes in a graph, with basic interaction. You can click to drag a node around, and diff --git a/examples/widgets/doc/src/embeddeddialogs.qdoc b/examples/widgets/doc/src/embeddeddialogs.qdoc index 0775c588076..0b31e01e0cf 100644 --- a/examples/widgets/doc/src/embeddeddialogs.qdoc +++ b/examples/widgets/doc/src/embeddeddialogs.qdoc @@ -29,7 +29,7 @@ \example graphicsview/embeddeddialogs \title Embedded Dialogs \ingroup examples-graphicsview-layout - \brief Demonstrates how to embed dialogs into a graphics view + \brief Demonstrates how to embed dialogs into a graphics view. This example shows how to embed standard dialogs into Graphics View. It also shows how you can customize the diff --git a/examples/widgets/doc/src/fademessage.qdoc b/examples/widgets/doc/src/fademessage.qdoc index 4703dcda307..20359220677 100644 --- a/examples/widgets/doc/src/fademessage.qdoc +++ b/examples/widgets/doc/src/fademessage.qdoc @@ -29,7 +29,7 @@ \example effects/fademessage \title Fade Message Effect Example \ingroup examples-graphicsview-graphicseffects - \brief Demonstrates how to apply effects on items in the view + \brief Demonstrates how to apply effects on items in the view. \div { style="text-align: left"} \inlineimage fademessageeffect-example.png diff --git a/examples/widgets/doc/src/findfiles.qdoc b/examples/widgets/doc/src/findfiles.qdoc index ad39b003ae3..d7428e7d162 100644 --- a/examples/widgets/doc/src/findfiles.qdoc +++ b/examples/widgets/doc/src/findfiles.qdoc @@ -30,7 +30,7 @@ \title Find Files Example \ingroup examples-dialogs - \brief A dialog for finding files in a specified folder + \brief A dialog for finding files in a specified folder. The Find Files application allows the user to search for files in a specified directory, matching a given file name or wildcard, diff --git a/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc index bd27a0dc4f9..7933e3c956f 100644 --- a/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-anchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/anchorlayout \title Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout in a graphics view scene + \brief Demonstrates anchor layout in a graphics view scene. The Anchor Layout example demonstrates the use of the QGraphicsAnchorLayout class. diff --git a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc index fd0427fdc03..27b3f86156c 100644 --- a/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-simpleanchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/simpleanchorlayout \title Simple Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout on a graphics view scene + \brief Demonstrates anchor layout on a graphics view scene. The Simple Anchor Layout example shows the basic use of the QGraphicsAnchorLayout class. diff --git a/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc b/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc index fbdd08654d8..71ace603554 100644 --- a/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc +++ b/examples/widgets/doc/src/graphicsview-weatheranchorlayout.qdoc @@ -29,7 +29,7 @@ \example graphicsview/weatheranchorlayout \title Weather Anchor Layout Example \ingroup examples-graphicsview-layout - \brief Demonstrates anchor layout on a graphics view scene + \brief Demonstrates anchor layout on a graphics view scene. The Weather Anchor Layout example shows more complex use of the QGraphicsAnchorLayout class to create a real-world window layout. diff --git a/examples/widgets/doc/src/padnavigator.qdoc b/examples/widgets/doc/src/padnavigator.qdoc index 017532622af..e59fa3cdbef 100644 --- a/examples/widgets/doc/src/padnavigator.qdoc +++ b/examples/widgets/doc/src/padnavigator.qdoc @@ -29,7 +29,7 @@ \example graphicsview/padnavigator \title Pad Navigator Example \ingroup examples-graphicsview - \brief Demonstrates how to create animated user interface + \brief Demonstrates how to create animated user interface. The Pad Navigator Example shows how you can use Graphics View together with embedded widgets and Qt's \l{The State Machine Framework}{state machine diff --git a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc index c5911297f5f..0ab578f55c5 100644 --- a/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc +++ b/examples/widgets/gestures/imagegestures/doc/src/imagegestures.qdoc @@ -28,7 +28,7 @@ /*! \example gestures/imagegestures \title Image Gestures Example - \brief Demonstrates the use of simple gestures in a widget + \brief Demonstrates the use of simple gestures in a widget. This example shows how to enable gestures for a widget and use gesture input to perform actions. diff --git a/examples/widgets/tutorials/gettingstartedqt.qdoc b/examples/widgets/tutorials/gettingstartedqt.qdoc index 921dd7a32d4..bbe1dd1a8d0 100644 --- a/examples/widgets/tutorials/gettingstartedqt.qdoc +++ b/examples/widgets/tutorials/gettingstartedqt.qdoc @@ -28,7 +28,7 @@ /*! \example tutorials/notepad \title Getting Started Programming with Qt Widgets - \brief A tutorial for Qt Widgets based on a notepad application + \brief A tutorial for Qt Widgets based on a notepad application. In this topic, we teach basic Qt knowledge by implementing a simple Notepad application using C++ and the \l{Qt Widgets} module. The diff --git a/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc b/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc index e712ac45e99..84ac1723d54 100644 --- a/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc +++ b/examples/xml/dombookmarks/doc/src/dombookmarks.qdoc @@ -29,7 +29,7 @@ \example dombookmarks \title DOM Bookmarks Example \ingroup xml-examples - \brief Provides a reader for XML Bookmark Exchange Language files + \brief Provides a reader for XML Bookmark Exchange Language files. The DOM Bookmarks example provides a reader for XML Bookmark Exchange Language (XBEL) files that uses Qt's DOM-based XML API to read and parse the files. The SAX Bookmarks diff --git a/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc b/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc index ca5ca0adbb9..0cd89e641ed 100644 --- a/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc +++ b/examples/xml/saxbookmarks/doc/src/saxbookmarks.qdoc @@ -28,7 +28,7 @@ /*! \example saxbookmarks \title SAX Bookmarks Example - \brief Demonstrates how to read XBEL files + \brief Demonstrates how to read XBEL files. \ingroup xml-examples This example uses Qt's SAX API to read and parse the files. The DOM Bookmarks diff --git a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc index ad093c2098f..aa0ddd49910 100644 --- a/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc +++ b/examples/xml/streambookmarks/doc/src/qxmlstreambookmarks.qdoc @@ -28,7 +28,7 @@ /*! \example streambookmarks \title QXmlStream Bookmarks Example - \brief Demonstrates how to read and write to XBEL files + \brief Demonstrates how to read and write to XBEL files. \ingroup xml-examples The QXmlStream Bookmarks example provides a reader for XML Bookmark diff --git a/src/concurrent/doc/src/qtconcurrent-module.qdoc b/src/concurrent/doc/src/qtconcurrent-module.qdoc index 7f2b9b95622..9289b4bfa81 100644 --- a/src/concurrent/doc/src/qtconcurrent-module.qdoc +++ b/src/concurrent/doc/src/qtconcurrent-module.qdoc @@ -28,7 +28,7 @@ /*! \module QtConcurrent \title Qt Concurrent C++ Classes - \brief The Qt Concurrent module contains functionality to support concurrent execution of program code + \brief The Qt Concurrent module contains functionality to support concurrent execution of program code. \ingroup modules \qtvariable concurrent diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 9fd845bb93a..5ba2a1fa736 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -40,7 +40,7 @@ /*! \class QPropertyAnimation \inmodule QtCore - \brief The QPropertyAnimation class animates Qt properties + \brief The QPropertyAnimation class animates Qt properties. \since 4.6 \ingroup animation diff --git a/src/corelib/global/qglobalstatic.qdoc b/src/corelib/global/qglobalstatic.qdoc index 63cc968d1c9..e3705ee6be0 100644 --- a/src/corelib/global/qglobalstatic.qdoc +++ b/src/corelib/global/qglobalstatic.qdoc @@ -336,7 +336,7 @@ \threadsafe \inmodule QtCore \since 5.1 - \brief The QGlobalStatic class is used to implement a global static object + \brief The QGlobalStatic class is used to implement a global static object. The QGlobalStatic class is the front-end API exported when Q_GLOBAL_STATIC() is used. See the documentation for the macro for a diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 0d9a6c8749b..013d531581f 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -842,7 +842,7 @@ QDebug &QDebug::resetFormat() /*! \class QDebugStateSaver \inmodule QtCore - \brief Convenience class for custom QDebug operators + \brief Convenience class for custom QDebug operators. Saves the settings used by QDebug, and restores them upon destruction, then calls \l {QDebug::maybeSpace()}{maybeSpace()}, to separate arguments with a space if diff --git a/src/corelib/itemmodels/qidentityproxymodel.cpp b/src/corelib/itemmodels/qidentityproxymodel.cpp index e984ec194e5..c1e23dbd0c7 100644 --- a/src/corelib/itemmodels/qidentityproxymodel.cpp +++ b/src/corelib/itemmodels/qidentityproxymodel.cpp @@ -83,7 +83,7 @@ class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate \since 4.8 \class QIdentityProxyModel \inmodule QtCore - \brief The QIdentityProxyModel class proxies its source model unmodified + \brief The QIdentityProxyModel class proxies its source model unmodified. \ingroup model-view diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 8a7bb53e33b..566f75a6c3c 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -511,7 +511,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) /*! \class QSignalBlocker - \brief Exception-safe wrapper around QObject::blockSignals() + \brief Exception-safe wrapper around QObject::blockSignals(). \since 5.3 \ingroup objectmodel \inmodule QtCore diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index a92dd71df55..f18c4cc8e72 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -2265,7 +2265,7 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const \inmodule QtCore \since 4.3 \reentrant - \brief The QXmlStreamAttribute class represents a single XML attribute + \brief The QXmlStreamAttribute class represents a single XML attribute. \ingroup xml-tools diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index e91e859975e..74e0746f43c 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -503,7 +503,7 @@ bool QSemaphore::tryAcquire(int n, int timeout) /*! \class QSemaphoreReleaser - \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call + \brief The QSemaphoreReleaser class provides exception-safe deferral of a QSemaphore::release() call. \since 5.10 \ingroup thread \inmodule QtCore diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp index 96c2394dbd8..a54afc5a9db 100644 --- a/src/corelib/tools/qbytearraymatcher.cpp +++ b/src/corelib/tools/qbytearraymatcher.cpp @@ -334,7 +334,7 @@ int qFindByteArray( \class QStaticByteArrayMatcher \since 5.9 \inmodule QtCore - \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher + \brief The QStaticByteArrayMatcher class is a compile-time version of QByteArrayMatcher. \ingroup tools \ingroup string-processing diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index 22cf516b683..2d5fd2a00ef 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -46,7 +46,7 @@ /*! \class QSharedPointer \inmodule QtCore - \brief The QSharedPointer class holds a strong reference to a shared pointer + \brief The QSharedPointer class holds a strong reference to a shared pointer. \since 4.5 \reentrant @@ -315,7 +315,7 @@ /*! \class QWeakPointer \inmodule QtCore - \brief The QWeakPointer class holds a weak reference to a shared pointer + \brief The QWeakPointer class holds a weak reference to a shared pointer. \since 4.5 \reentrant @@ -373,7 +373,7 @@ /*! \class QEnableSharedFromThis \inmodule QtCore - \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer + \brief A base class that allows obtaining a QSharedPointer for an object already managed by a shared pointer. \since 5.4 You can inherit this class when you need to create a QSharedPointer diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index 7ddf68daa0a..148bd541476 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -305,7 +305,7 @@ int QDBusAbstractInterfaceBase::qt_metacall(QMetaObject::Call _c, int _id, void \inmodule QtDBus \since 4.2 - \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces + \brief The QDBusAbstractInterface class is the base class for all D-Bus interfaces in the Qt D-Bus binding, allowing access to remote interfaces. Generated-code classes also derive from QDBusAbstractInterface, all methods described here are also valid for generated-code diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index bd6eb9eca33..2a31dd950a0 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE \ingroup shared \since 4.5 - \brief The QDBusPendingCall class refers to one pending asynchronous call + \brief The QDBusPendingCall class refers to one pending asynchronous call. A QDBusPendingCall object is a reference to a method call that was sent over D-Bus without waiting for a reply. QDBusPendingCall is an @@ -91,7 +91,7 @@ QT_BEGIN_NAMESPACE \since 4.5 \brief The QDBusPendingCallWatcher class provides a convenient way for - waiting for asynchronous replies + waiting for asynchronous replies. The QDBusPendingCallWatcher provides the finished() signal that will be emitted when a reply arrives. diff --git a/src/dbus/qdbuspendingreply.cpp b/src/dbus/qdbuspendingreply.cpp index c0baa4a0056..fef6f364329 100644 --- a/src/dbus/qdbuspendingreply.cpp +++ b/src/dbus/qdbuspendingreply.cpp @@ -49,7 +49,7 @@ \inmodule QtDBus \since 4.5 - \brief The QDBusPendingReply class contains the reply to an asynchronous method call + \brief The QDBusPendingReply class contains the reply to an asynchronous method call. The QDBusPendingReply is a template class with up to 8 template parameters. Those parameters are the types that will be used to diff --git a/src/gui/kernel/qpixelformat.cpp b/src/gui/kernel/qpixelformat.cpp index c132a1418e1..c28fe7ac63c 100644 --- a/src/gui/kernel/qpixelformat.cpp +++ b/src/gui/kernel/qpixelformat.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE \inmodule QtGui \since 5.4 \brief QPixelFormat is a class for describing different pixel - layouts in graphics buffers + layouts in graphics buffers. In Qt there is a often a need to represent the layout of the pixels in a graphics buffer. Internally QPixelFormat stores everything in a 64 bit diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp index d06fee62cf6..c88654e7949 100644 --- a/src/gui/kernel/qrasterwindow.cpp +++ b/src/gui/kernel/qrasterwindow.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE \class QRasterWindow \inmodule QtGui \since 5.4 - \brief QRasterWindow is a convenience class for using QPainter on a QWindow + \brief QRasterWindow is a convenience class for using QPainter on a QWindow. QRasterWindow is a QWindow with a raster-based, non-OpenGL surface. On top of the functionality offered by QWindow, QRasterWindow adds a virtual diff --git a/src/gui/opengl/qopenglfunctions_es2.cpp b/src/gui/opengl/qopenglfunctions_es2.cpp index 59e275dce1d..dd2b3af80ba 100644 --- a/src/gui/opengl/qopenglfunctions_es2.cpp +++ b/src/gui/opengl/qopenglfunctions_es2.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE \inmodule QtGui \since 5.1 \wrapper - \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2 + \brief The QOpenGLFunctions_ES2 class provides all functions for OpenGL ES 2. This class is a wrapper for OpenGL ES 2 functions. See reference pages on \l {http://www.khronos.org/opengles/sdk/docs/man/}{khronos.org} for diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp index 9cbe6ef911e..a1c9f6e4170 100644 --- a/src/gui/painting/qpagesize.cpp +++ b/src/gui/painting/qpagesize.cpp @@ -908,7 +908,7 @@ QSize QPageSizePrivate::sizePixels(int resolution) const \class QPageSize \inmodule QtGui \since 5.3 - \brief The QPageSize class describes the size and name of a defined page size + \brief The QPageSize class describes the size and name of a defined page size. This class implements support for the set of standard page sizes as defined in the Adobe Postscript PPD Standard v4.3. It defines the standard set of diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index d89805d18e0..a911014a195 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -264,7 +264,7 @@ bool QSupportedWritingSystems::supported(QFontDatabase::WritingSystem writingSys /*! \class QSupportedWritingSystems \brief The QSupportedWritingSystems class is used when registering fonts with the internal Qt - fontdatabase + fontdatabase. \ingroup painting \inmodule QtGui diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 35e79a69f27..76850837d0b 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -166,7 +166,7 @@ static void ensureInitialized() /*! \class QNetworkAccessManager \brief The QNetworkAccessManager class allows the application to - send network requests and receive replies + send network requests and receive replies. \since 4.4 \ingroup network diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp index 2ec4acf26c1..072a7f249d9 100644 --- a/src/network/access/qnetworkcookiejar.cpp +++ b/src/network/access/qnetworkcookiejar.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE \since 4.4 \inmodule QtNetwork - \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects + \brief The QNetworkCookieJar class implements a simple jar of QNetworkCookie objects. Cookies are small bits of information that stateless protocols like HTTP use to maintain some persistent information across diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 11d8f0e3f7d..aca9cb1c084 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -61,7 +61,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() \class QNetworkReply \since 4.4 \brief The QNetworkReply class contains the data and headers for a request - sent with QNetworkAccessManager + sent with QNetworkAccessManager. \reentrant \ingroup network diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc index 7a95195da2e..517e0a72cb3 100644 --- a/src/network/doc/src/qtnetwork.qdoc +++ b/src/network/doc/src/qtnetwork.qdoc @@ -96,7 +96,7 @@ \title Qt Network C++ Classes \ingroup modules \qtvariable network - \brief Provides classes to make network programming easier and portable + \brief Provides classes to make network programming easier and portable. To include the definitions of the module's classes, use the following directive: diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index a1697c01252..46df1814966 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -59,7 +59,7 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1"; /*! \class QSslConfiguration - \brief The QSslConfiguration class holds the configuration and state of an SSL connection + \brief The QSslConfiguration class holds the configuration and state of an SSL connection. \since 4.4 \reentrant diff --git a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc index 22e763ec248..3779ea10c8b 100644 --- a/src/platformheaders/nativecontexts/qeglnativecontext.qdoc +++ b/src/platformheaders/nativecontexts/qeglnativecontext.qdoc @@ -30,7 +30,7 @@ \inmodule QtPlatformHeaders \since 5.4 - \brief A class encapsulating an EGL context and display handle + \brief A class encapsulating an EGL context and display handle. \note There is no binary compatibility guarantee for this class, meaning that an application using it is only guaranteed to work with the Qt version it was diff --git a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc index ccc5e2b1d02..20563c39065 100644 --- a/src/platformheaders/nativecontexts/qwglnativecontext.qdoc +++ b/src/platformheaders/nativecontexts/qwglnativecontext.qdoc @@ -30,7 +30,7 @@ \inmodule QtPlatformHeaders \since 5.4 - \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll) + \brief A class encapsulating a WGL context on Windows with desktop OpenGL (opengl32.dll). \note There is no binary compatibility guarantee for this class, meaning that an application using it is only guaranteed to work with the Qt diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp index 903a9349ece..a4c463fb5bb 100644 --- a/src/widgets/widgets/qplaintextedit.cpp +++ b/src/widgets/widgets/qplaintextedit.cpp @@ -109,7 +109,7 @@ public: /*! \class QPlainTextDocumentLayout \since 4.4 - \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument + \brief The QPlainTextDocumentLayout class implements a plain text layout for QTextDocument. \ingroup richtext-processing \inmodule QtWidgets diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp index 8a9a0eaf96c..5790b1e32e1 100644 --- a/src/widgets/widgets/qtextedit.cpp +++ b/src/widgets/widgets/qtextedit.cpp @@ -2049,7 +2049,7 @@ void QTextEdit::setAcceptRichText(bool accept) \inmodule QtWidgets \brief The QTextEdit::ExtraSelection structure provides a way of specifying a - character format for a given selection in a document + character format for a given selection in a document. */ /*! From 8476271eda29b5b60047af3a99b1536ace5fd8f6 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Thu, 21 Jun 2018 16:29:20 +0200 Subject: [PATCH 059/123] Doc: Fix typo in Scribble example Task-number: QTBUG-68549 Change-Id: Ib83d3297e2ebefe6f42799a14dde35411a8ec120 Reviewed-by: Jesus Fernandez --- examples/widgets/doc/src/scribble.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/widgets/doc/src/scribble.qdoc b/examples/widgets/doc/src/scribble.qdoc index 3b1f8dc895e..ca79431334f 100644 --- a/examples/widgets/doc/src/scribble.qdoc +++ b/examples/widgets/doc/src/scribble.qdoc @@ -149,7 +149,7 @@ For mouse press and mouse release events, we use the QMouseEvent::button() function to find out which button caused - the event. For mose move events, we use QMouseEvent::buttons() + the event. For mouse move events, we use QMouseEvent::buttons() to find which buttons are currently held down (as an OR-combination). If the users press the left mouse button, we store the position From c44e8b25662d096f2bffa02c057104b2a1cdf7c4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 21 Jun 2018 10:02:59 +0200 Subject: [PATCH 060/123] Windows QPA: Fix crashes when processing native events Change a0a22037cdacbf51a2db560ff902a5a341561b15 wrongly introduced a level of indirection when passing the MSG * as void * to QWindowSystemInterface::handleNativeEvent() in QWindowsContext::filterNativeEvent(). Remove the indirection. Task-number: QTBUG-67095 Change-Id: Ibc2db7ae56bca38f79bafabfabb6127d6ff8cf09 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 98a4b261fd8..1da39a05165 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1430,7 +1430,7 @@ bool QWindowsContext::filterNativeEvent(MSG *msg, LRESULT *result) bool QWindowsContext::filterNativeEvent(QWindow *window, MSG *msg, LRESULT *result) { long filterResult = 0; - if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), &msg, &filterResult)) { + if (QWindowSystemInterface::handleNativeEvent(window, nativeEventType(), msg, &filterResult)) { *result = LRESULT(filterResult); return true; } From 64286ff96a684d9dec47988bd4c93b73d1f022bd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 21 Jun 2018 11:38:50 +0200 Subject: [PATCH 061/123] QDataStream: Fix inlining of operator<<,>>() for quint32 The inline operators are referenced by the container serialization helper code above the definition, causing g++ 8.1/MinGW to complain: In file included from ..\..\include/QtCore/qdatastream.h:1, from access\qnetworkaccessdebugpipebackend.cpp:41: ..\..\include/QtCore/../../src/corelib/serialization/qdatastream.h:349:21: error: 'QDataStream& QDataStream::operator>>(quint32&)' redeclared without dllimport attribute after being referenced with dll linkage [-Werror] inline QDataStream &QDataStream::operator>>(quint32 &i) ^~~~~~~~~~~ ..\..\include/QtCore/../../src/corelib/serialization/qdatastream.h:361:21: error: 'QDataStream& QDataStream::operator<<(quint32)' redeclared without dllimport attribute after being referenced with dll linkage [-Werror] inline QDataStream &QDataStream::operator<<(quint32 i) Declare the operators to be inline to fix this. Task-number: QTBUG-68742 Task-number: QTQAINFRA-2095 Change-Id: Ifa075aff8749df5c7a56148b8b9a0e3ec1e853aa Reviewed-by: Thiago Macieira --- src/corelib/serialization/qdatastream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index 1f1b13686ce..17750223555 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -151,7 +151,7 @@ public: QDataStream &operator>>(qint16 &i); QDataStream &operator>>(quint16 &i); QDataStream &operator>>(qint32 &i); - QDataStream &operator>>(quint32 &i); + inline QDataStream &operator>>(quint32 &i); QDataStream &operator>>(qint64 &i); QDataStream &operator>>(quint64 &i); QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; } @@ -167,7 +167,7 @@ public: QDataStream &operator<<(qint16 i); QDataStream &operator<<(quint16 i); QDataStream &operator<<(qint32 i); - QDataStream &operator<<(quint32 i); + inline QDataStream &operator<<(quint32 i); QDataStream &operator<<(qint64 i); QDataStream &operator<<(quint64 i); QDataStream &operator<<(std::nullptr_t) { return *this; } From be0a6ab4c8c20f94244b13b1445a80d726df0925 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Thu, 21 Jun 2018 14:42:46 +0200 Subject: [PATCH 062/123] Doc: Improve description of QModelIndex::operator== MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List the values that are compared by the comparison operator overloads, rather than the less specific "all values". Task-number: QTBUG-68877 Change-Id: Id4df02b9019e13113fd38a598b8349293fab7915 Reviewed-by: Giuseppe D'Angelo Reviewed-by: Topi Reiniö --- src/corelib/itemmodels/qabstractitemmodel.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index d826110ec79..3a6f67521f8 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -182,8 +182,8 @@ QPersistentModelIndex::~QPersistentModelIndex() Returns \c{true} if this persistent model index is equal to the \a other persistent model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing - with another persistent model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another persistent model index. */ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const @@ -199,8 +199,8 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const Returns \c{true} if this persistent model index is smaller than the \a other persistent model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing - with another persistent model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another persistent model index. */ bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const @@ -275,13 +275,11 @@ QPersistentModelIndex::operator const QModelIndex&() const } /*! - \fn bool QPersistentModelIndex::operator==(const QModelIndex &other) const - Returns \c{true} if this persistent model index refers to the same location as the \a other model index; otherwise returns \c{false}. - All values in the persistent model index are used when comparing with - another model index. + The internal data pointer, row, column, and model values in the persistent + model index are used when comparing with another model index. */ bool QPersistentModelIndex::operator==(const QModelIndex &other) const @@ -1167,8 +1165,8 @@ void QAbstractItemModel::resetInternalData() Returns \c{true} if this model index refers to the same location as the \a other model index; otherwise returns \c{false}. - All values in the model index are used when comparing with another model - index. + The internal data pointer, row, column, and model values are used when + comparing with another model index. */ From af837f964781d61fd086b010cc79abf1462fcf11 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 19 Jun 2018 14:53:49 +0200 Subject: [PATCH 063/123] xcb: add qt.qpa.input.events logging of wheel events This is comparable to what we do on macOS, except that the scroll phase and inverted state are missing. Task-number: QTBUG-38570 Task-number: QTBUG-56075 Change-Id: I27502e1e2667317ab701f30f1fc601ae1e0591d0 Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 0302d585b5e..e6e0ee988c7 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -1040,6 +1040,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin std::swap(angleDelta.rx(), angleDelta.ry()); std::swap(rawDelta.rx(), rawDelta.ry()); } + qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta; QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); } } @@ -1065,6 +1066,7 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); + qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta; QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers); } } From 67776febd50bba009bd806365b4e94a851c31548 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 6 Jun 2018 22:30:48 +0200 Subject: [PATCH 064/123] Fix the qHash implementation for QMatrix / QTransform The order of the arguments of QHashCombine::operator() was accidentally swapped -- the first is supposed to be the accumlated value, the second the new value to combine. [ChangeLog][QtGui][QMatrix] The qHash() implementation for QMatrix has been changed. [ChangeLog][QtGui][QTransform] The qHash() implementation for QTransform has been changed. Change-Id: Iba13f76ff734a2184c96184ee0e5748c05db07fa Reviewed-by: Thiago Macieira --- src/gui/painting/qmatrix.cpp | 12 ++++++------ src/gui/painting/qtransform.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index 681490e347f..24b33243da1 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -992,12 +992,12 @@ bool QMatrix::operator==(const QMatrix &m) const uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW { QtPrivate::QHashCombine hash; - seed = hash(key.m11(), seed); - seed = hash(key.m12(), seed); - seed = hash(key.m21(), seed); - seed = hash(key.m22(), seed); - seed = hash(key.dx(), seed); - seed = hash(key.dy(), seed); + seed = hash(seed, key.m11()); + seed = hash(seed, key.m12()); + seed = hash(seed, key.m21()); + seed = hash(seed, key.m22()); + seed = hash(seed, key.dx()); + seed = hash(seed, key.dy()); return seed; } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index c5e296b2936..040d33fc2a1 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -798,15 +798,15 @@ bool QTransform::operator==(const QTransform &o) const uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW { QtPrivate::QHashCombine hash; - seed = hash(key.m11(), seed); - seed = hash(key.m12(), seed); - seed = hash(key.m21(), seed); - seed = hash(key.m22(), seed); - seed = hash(key.dx(), seed); - seed = hash(key.dy(), seed); - seed = hash(key.m13(), seed); - seed = hash(key.m23(), seed); - seed = hash(key.m33(), seed); + seed = hash(seed, key.m11()); + seed = hash(seed, key.m12()); + seed = hash(seed, key.m21()); + seed = hash(seed, key.m22()); + seed = hash(seed, key.dx()); + seed = hash(seed, key.dy()); + seed = hash(seed, key.m13()); + seed = hash(seed, key.m23()); + seed = hash(seed, key.m33()); return seed; } From f731ed9bcf7c359a3387b5bb2fb491c8ef96fae3 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 16 Jun 2018 20:58:01 +0200 Subject: [PATCH 065/123] QString: Harmonize the toFloat() and toDouble() documentation Both use QLocale::toDouble behind the scenes, so the same limitations apply. Document them for toFloat() also. Change-Id: I954362a0db203630685c034df6a921fa6447a509 Reviewed-by: Martin Smith --- src/corelib/tools/qstring.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 3787c496b24..a737d70a9c7 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -7207,21 +7207,30 @@ double QString::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. Returns 0.0 if the conversion fails. + Returns 0.0 if the conversion fails. - This function ignores leading and trailing whitespace. + If a conversion error occurs, *\a{ok} is set to \c false; otherwise + *\a{ok} is set to \c true. + + \warning The QString content may only contain valid numerical characters + which includes the plus/minus sign, the characters g and e used in scientific + notation, and the decimal point. Including the unit or additional characters + leads to a conversion error. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toFloat() + For historical reasons, this function does not handle + thousands group separators. If you need to convert such numbers, + use QLocale::toFloat(). + Example: \snippet qstring/main.cpp 71 This function ignores leading and trailing whitespace. - \sa number(), toDouble(), toInt(), QLocale::toFloat() + \sa number(), toDouble(), toInt(), QLocale::toFloat(), trimmed() */ float QString::toFloat(bool *ok) const From db3c1cb230e1f2ca9053590d72ecb22a2582c439 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 16 Jun 2018 22:19:20 +0200 Subject: [PATCH 066/123] QLocale: Remove misleading link to QString::toDouble() conversion While at it, add the comment to the toFloat() functions also. Task-number: QTBUG-55232 Change-Id: I21c06363946f35fb3d89a51e4f75be392b57c0a9 Reviewed-by: Thiago Macieira --- src/corelib/tools/qlocale.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 09b148ea9e7..04a43f74772 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1359,6 +1359,9 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const If \a ok is not 0, reports failure by setting *ok to false and success by setting *ok to true. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. + This function ignores leading and trailing whitespace. \sa toDouble(), toInt(), toString() @@ -1376,9 +1379,8 @@ float QLocale::toFloat(const QString &s, bool *ok) const If \a ok is not 0, reports failure by setting *ok to false and success by setting *ok to true. - Unlike QString::toDouble(), this function does not use - the 'C' locale if the string cannot be interpreted in this - locale. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. \snippet code/src_corelib_tools_qlocale.cpp 3 @@ -1524,6 +1526,9 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const If \a ok is not null, reports failure by setting *ok to false and success by setting *ok to true. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. + This function ignores leading and trailing whitespace. \sa toDouble(), toInt(), toString() @@ -1543,9 +1548,8 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const If \a ok is not null, reports failure by setting *ok to false and success by setting *ok to true. - Unlike QString::toDouble(), this function does not fall back to - the "C" locale if the string cannot be interpreted in this - locale. + This function does not fall back to the 'C' locale if the string + cannot be interpreted in this locale. \snippet code/src_corelib_tools_qlocale.cpp 3 From d88e0fd5126404113b49e8893bf4729537552371 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 22 Jun 2018 10:01:42 +0200 Subject: [PATCH 067/123] QtNetwork/SSL: Fix build with MinGW/g++ 8.1 x64 Fix warnings about invalid function type casts (return types conflicting with the FARPROC returned by GetProcAddress()) like: corelib\global\qoperatingsystemversion_win.cpp:100:48: error: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'RtlGetVersionFunction' {aka 'long int (*)(_OSVERSIONINFOW*)'} [-Werror=cast-function-type] by introducing nested casts. Task-number: QTBUG-68742 Task-number: QTQAINFRA-2095 Change-Id: I8ba6a74e6347dada486ca40c98aa8999957c4281 Reviewed-by: Jesus Fernandez --- src/network/ssl/qsslsocket_openssl11.cpp | 9 ++++++--- src/network/ssl/qsslsocket_opensslpre11.cpp | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/network/ssl/qsslsocket_openssl11.cpp b/src/network/ssl/qsslsocket_openssl11.cpp index 96626b6a0f6..d028f5fc009 100644 --- a/src/network/ssl/qsslsocket_openssl11.cpp +++ b/src/network/ssl/qsslsocket_openssl11.cpp @@ -125,9 +125,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); + ptrCertOpenSystemStoreW = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertOpenSystemStoreW"))); + ptrCertFindCertificateInStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertFindCertificateInStore"))); + ptrCertCloseStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertCloseStore"))); if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen } else { diff --git a/src/network/ssl/qsslsocket_opensslpre11.cpp b/src/network/ssl/qsslsocket_opensslpre11.cpp index 5782df65cc5..062e03f4e67 100644 --- a/src/network/ssl/qsslsocket_opensslpre11.cpp +++ b/src/network/ssl/qsslsocket_opensslpre11.cpp @@ -254,9 +254,12 @@ void QSslSocketPrivate::ensureCiphersAndCertsLoaded() #if defined(Q_OS_WIN) HINSTANCE hLib = LoadLibraryW(L"Crypt32"); if (hLib) { - ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW"); - ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore"); - ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore"); + ptrCertOpenSystemStoreW = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertOpenSystemStoreW"))); + ptrCertFindCertificateInStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertFindCertificateInStore"))); + ptrCertCloseStore = reinterpret_cast( + reinterpret_cast(GetProcAddress(hLib, "CertCloseStore"))); if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore) qCWarning(lcSsl, "could not resolve symbols in crypt32 library"); // should never happen } else { From 558dd7f58735716d7d1f61fb5323d807b178f0c7 Mon Sep 17 00:00:00 2001 From: Jonathan Marten Date: Thu, 21 Jun 2018 21:10:05 +0100 Subject: [PATCH 068/123] Recognize X11/XCB keysyms Undo, Redo, Find, Cancel Convert these keysyms into the corresponding Qt::Key_ enum values, so that they can be part of a QKeySequence and used by applications. Task-number: QTBUG-69062 Change-Id: I6f2e28191dd8dacd63d4bf710e1714fc5dcce75f Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index e4551b01393..3733995a0d8 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -138,6 +138,13 @@ static const unsigned int KeyTbl[] = { XKB_KEY_KP_Decimal, Qt::Key_Period, XKB_KEY_KP_Divide, Qt::Key_Slash, + // special non-XF86 function keys + + XKB_KEY_Undo, Qt::Key_Undo, + XKB_KEY_Redo, Qt::Key_Redo, + XKB_KEY_Find, Qt::Key_Find, + XKB_KEY_Cancel, Qt::Key_Cancel, + // International input method support keys // International & multi-key character composition From 4386887b104c0c4451e43f9be7e95e3f2b016433 Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 5 Apr 2018 18:00:55 +0200 Subject: [PATCH 069/123] Fix ico.json to avoid returning an empty mimetype QImageWriter::supportedMimeTypes() had an empty mimetype name in the list because the mimetype for the key "cur" was missing in this json file. Change-Id: I4eae4275cb04c4d640dbcac76cd9dc99baa4f0a7 Reviewed-by: Friedemann Kleint --- src/plugins/imageformats/ico/ico.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json index 14093ee4718..304e2f1c020 100644 --- a/src/plugins/imageformats/ico/ico.json +++ b/src/plugins/imageformats/ico/ico.json @@ -1,4 +1,4 @@ { "Keys": [ "ico", "cur" ], - "MimeTypes": [ "image/vnd.microsoft.icon" ] + "MimeTypes": [ "image/vnd.microsoft.icon", "image/vnd.microsoft.icon" ] } From c4928e99e9e571890ddfc08ff80139a1dba5fb5d Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 12 Jun 2018 14:06:20 +0200 Subject: [PATCH 070/123] Doc: Fix signal name in QTimer documentation QTimer emits timeout(), not activated(). Task-number: QTBUG-68798 Change-Id: I4fffce01d409e1fbc433e11c962c4e1921f76f2d Reviewed-by: Leena Miettinen Reviewed-by: Friedemann Kleint Reviewed-by: Oliver Wolff --- src/corelib/kernel/qtimer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index c3504943c46..3edd1f056ef 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -117,7 +117,7 @@ QT_BEGIN_NAMESPACE All timer types may time out later than expected if the system is busy or unable to provide the requested accuracy. In such a case of timeout - overrun, Qt will emit activated() only once, even if multiple timeouts have + overrun, Qt will emit timeout() only once, even if multiple timeouts have expired, and then will resume the original interval. \section1 Alternatives to QTimer From d640dbf730b392640d5497a789e95fa7d88f99fb Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 11 Apr 2018 16:53:56 +0300 Subject: [PATCH 071/123] QDBusTrayIcon: Avoid needless initialization of a global var TempFileTemplate is initialized each time an application starts. It leads to the call of QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation) which is slow and can even change permissions of the runtime directory. Use a static wrapper function to initialize this variable only when needed. Change-Id: Ib620f9b842c88103c67f8dfab200f4d39c9981ee Reviewed-by: Dmitry Shachnev Reviewed-by: Shawn Rutledge --- .../themes/genericunix/dbustray/qdbustrayicon.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp index 2153924ec8e..e81d272d4f3 100644 --- a/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp +++ b/src/platformsupport/themes/genericunix/dbustray/qdbustrayicon.cpp @@ -90,12 +90,17 @@ static QString iconTempPath() static const QString KDEItemFormat = QStringLiteral("org.kde.StatusNotifierItem-%1-%2"); static const QString KDEWatcherService = QStringLiteral("org.kde.StatusNotifierWatcher"); -static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png"); static const QString XdgNotificationService = QStringLiteral("org.freedesktop.Notifications"); static const QString XdgNotificationPath = QStringLiteral("/org/freedesktop/Notifications"); static const QString DefaultAction = QStringLiteral("default"); static int instanceCount = 0; +static inline QString tempFileTemplate() +{ + static const QString TempFileTemplate = iconTempPath() + QLatin1String("/qt-trayicon-XXXXXX.png"); + return TempFileTemplate; +} + /*! \class QDBusTrayIcon \internal @@ -206,7 +211,7 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon) if (!necessary) return nullptr; qreal dpr = qGuiApp->devicePixelRatio(); - QTemporaryFile *ret = new QTemporaryFile(TempFileTemplate, this); + QTemporaryFile *ret = new QTemporaryFile(tempFileTemplate(), this); ret->open(); icon.pixmap(QSize(22 * dpr, 22 * dpr)).save(ret); ret->close(); From 95b41777bb013e0841044a617706fab452e297cd Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Sat, 16 Jun 2018 22:20:29 +0200 Subject: [PATCH 072/123] QLocale/QString/QByteArray: Use nullptr in documentation While at it, fix some more issues in the sentences to harmonize the description between the different classes. Change-Id: Iee1c3ffe6fd71e82504bfb003d927c4db3b2a065 Reviewed-by: Martin Smith --- src/corelib/tools/qbytearray.cpp | 40 ++++++------- src/corelib/tools/qlocale.cpp | 96 ++++++++++++++++---------------- src/corelib/tools/qstring.cpp | 82 ++++++++++++++------------- 3 files changed, 110 insertions(+), 108 deletions(-) diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 7c601e13362..424420204a1 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -3671,8 +3671,8 @@ T toIntegral_helper(const char *data, bool *ok, int base) Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3697,8 +3697,8 @@ qlonglong QByteArray::toLongLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3722,8 +3722,8 @@ qulonglong QByteArray::toULongLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 36 @@ -3749,8 +3749,8 @@ int QByteArray::toInt(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3776,8 +3776,8 @@ uint QByteArray::toUInt(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 37 @@ -3804,8 +3804,8 @@ long QByteArray::toLong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3828,8 +3828,8 @@ ulong QByteArray::toULong(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3853,8 +3853,8 @@ short QByteArray::toShort(bool *ok, int base) const Returns 0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. @@ -3873,8 +3873,8 @@ ushort QByteArray::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet code/src_corelib_tools_qbytearray.cpp 38 @@ -3900,8 +3900,8 @@ double QByteArray::toDouble(bool *ok) const Returns 0.0 if the conversion fails. - If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to - false; otherwise *\a{ok} is set to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \note The conversion of the number is performed in the default C locale, irrespective of the user's locale. diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 04a43f74772..00a2c05c35a 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1247,8 +1247,8 @@ QString QLocale::scriptToString(QLocale::Script script) If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1265,8 +1265,8 @@ short QLocale::toShort(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1283,8 +1283,8 @@ ushort QLocale::toUShort(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1301,8 +1301,8 @@ int QLocale::toInt(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1319,8 +1319,8 @@ uint QLocale::toUInt(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1339,8 +1339,8 @@ qlonglong QLocale::toLongLong(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not 0, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1356,8 +1356,8 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not 0, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function does not fall back to the 'C' locale if the string cannot be interpreted in this locale. @@ -1376,8 +1376,8 @@ float QLocale::toFloat(const QString &s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not 0, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function does not fall back to the 'C' locale if the string cannot be interpreted in this locale. @@ -1402,8 +1402,8 @@ double QLocale::toDouble(const QString &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1422,8 +1422,8 @@ short QLocale::toShort(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1442,8 +1442,8 @@ ushort QLocale::toUShort(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1462,8 +1462,8 @@ int QLocale::toInt(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1482,8 +1482,8 @@ uint QLocale::toUInt(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1504,8 +1504,8 @@ qlonglong QLocale::toLongLong(const QStringRef &s, bool *ok) const If the conversion fails the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1523,8 +1523,8 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function does not fall back to the 'C' locale if the string cannot be interpreted in this locale. @@ -1545,8 +1545,8 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function does not fall back to the 'C' locale if the string cannot be interpreted in this locale. @@ -1574,8 +1574,8 @@ double QLocale::toDouble(const QStringRef &s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1594,8 +1594,8 @@ short QLocale::toShort(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1614,8 +1614,8 @@ ushort QLocale::toUShort(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1634,8 +1634,8 @@ int QLocale::toInt(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1654,8 +1654,8 @@ uint QLocale::toUInt(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1676,8 +1676,8 @@ qlonglong QLocale::toLongLong(QStringView s, bool *ok) const If the conversion fails, the function returns 0. - If \a ok is not null, failure is reported by setting *ok to false, and - success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1695,8 +1695,8 @@ qulonglong QLocale::toULongLong(QStringView s, bool *ok) const Returns the float represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. This function ignores leading and trailing whitespace. @@ -1714,8 +1714,8 @@ float QLocale::toFloat(QStringView s, bool *ok) const Returns the double represented by the localized string \a s, or 0.0 if the conversion failed. - If \a ok is not null, reports failure by setting - *ok to false and success by setting *ok to true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. Unlike QString::toDouble(), this function does not fall back to the "C" locale if the string cannot be interpreted in this diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a737d70a9c7..a83d8833cd3 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6907,8 +6907,8 @@ QString QString::vasprintf(const char *cformat, va_list ap) base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -6949,8 +6949,8 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -6993,8 +6993,8 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7024,8 +7024,8 @@ long QString::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7054,8 +7054,8 @@ ulong QString::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7083,8 +7083,8 @@ int QString::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7112,8 +7112,8 @@ uint QString::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7141,8 +7141,8 @@ short QString::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -7171,8 +7171,8 @@ ushort QString::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If a conversion error occurs, \c{*}\a{ok} is set to \c false; - otherwise \c{*}\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \snippet qstring/main.cpp 66 @@ -7209,8 +7209,8 @@ double QString::toDouble(bool *ok) const Returns 0.0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. \warning The QString content may only contain valid numerical characters which includes the plus/minus sign, the characters g and e used in scientific @@ -11590,8 +11590,8 @@ QStringRef QStringRef::trimmed() const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11615,8 +11615,8 @@ qint64 QStringRef::toLongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11642,8 +11642,8 @@ quint64 QStringRef::toULongLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11669,8 +11669,8 @@ long QStringRef::toLong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11695,8 +11695,8 @@ ulong QStringRef::toULong(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11720,8 +11720,8 @@ int QStringRef::toInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11745,8 +11745,8 @@ uint QStringRef::toUInt(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11770,8 +11770,8 @@ short QStringRef::toShort(bool *ok, int base) const base, which is 10 by default and must be between 2 and 36, or 0. Returns 0 if the conversion fails. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. If \a base is 0, the C language convention is used: If the string begins with "0x", base 16 is used; if the string begins with "0", @@ -11796,8 +11796,8 @@ ushort QStringRef::toUShort(bool *ok, int base) const Returns 0.0 if the conversion fails. - If a conversion error occurs, \c{*}\a{ok} is set to \c false; - otherwise \c{*}\a{ok} is set to \c true. + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toDouble() @@ -11819,8 +11819,10 @@ double QStringRef::toDouble(bool *ok) const /*! Returns the string converted to a \c float value. - If a conversion error occurs, *\a{ok} is set to \c false; otherwise - *\a{ok} is set to \c true. Returns 0.0 if the conversion fails. + Returns 0.0 if the conversion fails. + + If \a ok is not \c nullptr, failure is reported by setting *\a{ok} + to \c false, and success by setting *\a{ok} to \c true. The string conversion will always happen in the 'C' locale. For locale dependent conversion use QLocale::toFloat() From 9e15a93b89a46605e224666bffc62b342d4dc73b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 19 Jun 2018 15:34:14 +0200 Subject: [PATCH 073/123] Fix mouse-wheel handling for evdev devices with extended values Newer mouse devices support a so-called "free-scroll" mode, which unlocks the wheel and allows for faster scrolling. For such input devices, evdev will report an event value greater than 1, when free scrolling is active. Examples for such devices would be the Logitech G700 or MX Master series. However QEvdevMouseHandler interpreted such an event's data incorrectly and triggered wheel events for the opposite scrolling direction. This also often resulted in jittery & jumpy scrolling, when the events' values alternated between 1 and 2. Change-Id: Ibb23ed4419d647fff9b90d371d5bb4037cf2bd9b Reviewed-by: Allan Sandfeld Jensen --- .../input/evdevmouse/qevdevmousehandler.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 04372ae4d90..86a4cd0076d 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -245,18 +245,12 @@ void QEvdevMouseHandler::readMouseData() m_y += data->value; posChanged = true; } else if (data->code == ABS_WHEEL) { // vertical scroll - // data->value: 1 == up, -1 == down - if (data->value == 1) - delta.setY(120); - else - delta.setY(-120); + // data->value: positive == up, negative == down + delta.setY(120 * data->value); emit handleWheelEvent(delta); } else if (data->code == ABS_THROTTLE) { // horizontal scroll - // data->value: 1 == right, -1 == left - if (data->value == 1) - delta.setX(-120); - else - delta.setX(120); + // data->value: positive == right, negative == left + delta.setX(-120 * data->value); emit handleWheelEvent(delta); } } else if (data->type == EV_KEY && data->code == BTN_TOUCH) { From 4361c0ee846fb5574a05534186a01779a5e0bb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 18 Jun 2018 15:14:19 +0200 Subject: [PATCH 074/123] findtestdata: test 'relative to test source'-fix Before the fix is applied this test fails because QFINDTESTDATA will return "/usr/" instead of the folder with the same name in the current directory. The 'usr' folder can't be located 'next to' the application since this does not trigger the issue (QFINDTESTDATA looks for the folder next to the executable early on). So we put it in a subdirectory and change the current working directory to its parent directory. Change-Id: I627679dcb6f2f6954264e23bfc1a71de3bff7203 Reviewed-by: Jesus Fernandez --- .../selftests/findtestdata/findtestdata.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp b/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp index a775bc1ee5e..7d5857faa0b 100644 --- a/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp +++ b/tests/auto/testlib/selftests/findtestdata/findtestdata.cpp @@ -134,6 +134,30 @@ void FindTestData::paths() #endif QVERIFY(QFile(testfile_path3).remove()); +#if !defined(Q_OS_WIN) + struct ChdirOnReturn + { + ~ChdirOnReturn() { QDir::setCurrent(dir); } + QString dir; + }; + + // When cross-compiling from Windows to a *nix system the __FILE__ path's canonical path is an + // empty string, which, when used as a prefix, would cause QFINDTESTDATA to look for files in + // root ('/') when trying to look for files relative to the test source. + QString usrPath = app_path + "/temp/usr/"; + QVERIFY(QDir().mkpath(usrPath)); + { + ChdirOnReturn chdirObject{QDir::currentPath()}; + QDir::setCurrent(app_path + "/temp"); + QCOMPARE(QTest::qFindTestData("usr/", + "C:\\path\\to\\source\\source.cpp", + __LINE__, + "C:\\path\\to\\build\\").toLower(), + usrPath.toLower()); + } + QVERIFY(QDir().rmpath(usrPath)); +#endif + // Note, this is expected to generate a warning. // We can't use ignoreMessage, because the warning comes from testlib, // not via a "normal" qWarning. But it's OK, our caller (tst_selftests) From 4fa8dfee5dd31433d22fdb449c1783e256931c8f Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Fri, 15 Jun 2018 11:35:00 +0200 Subject: [PATCH 075/123] Leave m_id clear if the JNI didn't give us a time-zone QTimeZonePrivate::isValid() just checks m_id is non-empty; so we have to leave m_id clear if we don't get a valid time-zone back when we ask the JNI for one. Unfortunately, JNI gives us a "valid" default zone if it doesn't recognize the given name; so check the known names of this zone (or of zones with its offset); if the given ianaId isn't one of them, assume this is a bogus zone. Task-number: QTBUG-68842 Change-Id: I6245db18c59c4261ed5fcd4d948dd773365ce61d Reviewed-by: Thiago Macieira --- .../tools/qtimezoneprivate_android.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qtimezoneprivate_android.cpp b/src/corelib/tools/qtimezoneprivate_android.cpp index c3f8c3e0d95..b60093617fa 100644 --- a/src/corelib/tools/qtimezoneprivate_android.cpp +++ b/src/corelib/tools/qtimezoneprivate_android.cpp @@ -82,7 +82,24 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId) QJNIObjectPrivate jo_ianaId = QJNIObjectPrivate::fromString( QString::fromUtf8(ianaId) ); androidTimeZone = QJNIObjectPrivate::callStaticObjectMethod( "java.util.TimeZone", "getTimeZone", "(Ljava/lang/String;)Ljava/util/TimeZone;", static_cast(jo_ianaId.object()) ); - if (ianaId.isEmpty()) + // Painfully, JNI gives us back a default zone object if it doesn't + // recognize the name; so check for whether ianaId is a recognized name of + // the zone object we got and ignore the zone if not. + bool found = false; + // Try checking ianaId against getID(), getDisplayName(): + QJNIObjectPrivate jname = androidTimeZone.callObjectMethod("getID", "()Ljava/lang/String;"); + found = (jname.toString().toUtf8() == ianaId); + for (int style = 1; !found && style-- > 0;) { + for (int dst = 1; !found && dst-- > 0;) { + jname = androidTimeZone.callObjectMethod("getDisplayName", "(ZI;)Ljava/lang/String;", + bool(dst), style); + found = (jname.toString().toUtf8() == ianaId); + } + } + + if (!found) + m_id.clear(); + else if (ianaId.isEmpty()) m_id = systemTimeZoneId(); else m_id = ianaId; From d2c0ba3f3073322ca6c8390394c3ecf5f7593775 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 21 Jun 2018 16:54:12 +0200 Subject: [PATCH 076/123] Do not update scroll coordinates on ignorable enter events This greatly reduces how often we reset the scroll evaluators, especially with non-focused windows in KWin which sends an enter for every wheel events in that case. The update of the evaluators also has race conditions with the normal events, and thus reducing them fixes odd scrolling behavior with rapid firing mouse wheels. Task-number: QTBUG-42415 Task-number: QTBUG-68734 Change-Id: I1c14ca3352bf9c6e57e47ad3aaee1712fe6ba30b Reviewed-by: Gatis Paeglis --- src/plugins/platforms/xcb/qxcbwindow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 731b00f8fd4..c65fab449f9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2251,15 +2251,15 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in quint8 mode, quint8 detail, xcb_timestamp_t timestamp) { connection()->setTime(timestamp); -#ifdef XCB_USE_XINPUT21 - // Updates scroll valuators, as user might have done some scrolling outside our X client. - connection()->xi2UpdateScrollingDevices(); -#endif const QPoint global = QPoint(root_x, root_y); if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow()) return; +#ifdef XCB_USE_XINPUT21 + // Updates scroll valuators, as user might have done some scrolling outside our X client. + connection()->xi2UpdateScrollingDevices(); +#endif const QPoint local(event_x, event_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); From 6601939713459c418dbd2db835411529020bf20d Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 22 Jun 2018 16:22:45 +0200 Subject: [PATCH 077/123] Notepad example: Wrap clipboard functions with QT_CONFIG(clipboard) And disable menu actions for functionality that's not available. Task-number: QTBUG-68168 Change-Id: I153487860e8dda8271ae04e9cd2ad8b26a4b130f Reviewed-by: Friedemann Kleint --- examples/widgets/tutorials/notepad/notepad.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/widgets/tutorials/notepad/notepad.cpp b/examples/widgets/tutorials/notepad/notepad.cpp index 99a1a52c2bd..d0e600e8528 100644 --- a/examples/widgets/tutorials/notepad/notepad.cpp +++ b/examples/widgets/tutorials/notepad/notepad.cpp @@ -73,6 +73,17 @@ Notepad::Notepad(QWidget *parent) : { ui->setupUi(this); this->setCentralWidget(ui->textEdit); + +// Disable menu actions for unavailable features +#if !QT_CONFIG(printer) + ui->actionPrint->setEnabled(false); +#endif + +#if !QT_CONFIG(clipboard) + ui->actionCut->setEnabled(false); + ui->actionCopy->setEnabled(false); + ui->actionPaste->setEnabled(false); +#endif } Notepad::~Notepad() @@ -161,17 +172,23 @@ void Notepad::on_actionExit_triggered() void Notepad::on_actionCopy_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->copy(); +#endif } void Notepad::on_actionCut_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->cut(); +#endif } void Notepad::on_actionPaste_triggered() { +#if QT_CONFIG(clipboard) ui->textEdit->paste(); +#endif } void Notepad::on_actionUndo_triggered() From 1f9dc07a862e451f060323923d13968b757d9738 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Fri, 22 Jun 2018 13:53:08 +0200 Subject: [PATCH 078/123] Doc: Update br tag in html footer for XHTML compliance Task-number: QTBUG-68459 Change-Id: Ie7c4a4e6d49c49db5814ee9b0a36387bed74fd38 Reviewed-by: Venugopal Shivashankar --- doc/global/html-footer.qdocconf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/global/html-footer.qdocconf b/doc/global/html-footer.qdocconf index 9957e71f20a..c0122a7c4f4 100644 --- a/doc/global/html-footer.qdocconf +++ b/doc/global/html-footer.qdocconf @@ -10,10 +10,10 @@ HTML.footer = \ "

\n" \ " © 2018 The Qt Company Ltd.\n" \ " Documentation contributions included herein are the copyrights of\n" \ - " their respective owners.
" \ + " their respective owners.
" \ " The documentation provided herein is licensed under the terms of the" \ " GNU Free Documentation" \ - " License version 1.3 as published by the Free Software Foundation.
" \ + " License version 1.3 as published by the Free Software Foundation.
" \ " Qt and respective logos are trademarks of The Qt Company Ltd. " \ " in Finland and/or other countries worldwide. All other trademarks are property\n" \ " of their respective owners.

\n" \ From 0e88882fee659f8720c63e067be734e5247af90f Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 21 Jun 2018 16:50:49 +0200 Subject: [PATCH 079/123] Remove dead test - compilerwarnings A follow-up of 9d078c8f147ea875e862360b0d7480201fbbcff7 in qtqa repo. Change-Id: Ib7c1f5cf325e9ad0066aae139b0dc72bc0184b32 Reviewed-by: Jarek Kobus --- tests/auto/compilerwarnings/data/test_cpp.txt | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 tests/auto/compilerwarnings/data/test_cpp.txt diff --git a/tests/auto/compilerwarnings/data/test_cpp.txt b/tests/auto/compilerwarnings/data/test_cpp.txt deleted file mode 100644 index 6ea63f56fdd..00000000000 --- a/tests/auto/compilerwarnings/data/test_cpp.txt +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include -#include -#include -#include - -#ifndef QT_NO_GUI -#include -#endif - -#ifndef QT_NO_OPENGL -#include -#endif - -#include - -#if !defined(QT_NO_DBUS) && defined(Q_OS_UNIX) -#include -#endif - -#ifndef Q_OS_MAC -int main(int, char **) -{ - return 0; -} -#endif From 4c68e2558c8b90f301032f2e29130e6ac509dc21 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 22 Jun 2018 16:48:58 +0200 Subject: [PATCH 080/123] Fix moc warnings with no_include_pwd and shadow builds If CONFIG option no_include_pwd is set, moc does not add the build directory to its include path. The path to the generated moc_predefs.h file is by default relative though, resulting in moc warnings: Warning: Failed to resolve include "debug/moc_predefs.h" for moc file xxx myheader.h Fix this by always making the path to moc_predefs.h absolute. Task-number: QTBUG-69087 Change-Id: I8ef79c8340f9ebd6b0bba15e026d65ef3c088535 Reviewed-by: Oswald Buddenhagen --- mkspecs/features/moc.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 37194b2eb8b..5c7745e5bb6 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -57,7 +57,7 @@ defineReplace(mocCmdBase) { msvc: RET += --compiler-flavor=msvc isEmpty(MOC_PREDEF_FILE): RET += $$join(QMAKE_COMPILER_DEFINES, " -D", -D) - else: RET += --include $$shell_quote($$moc_predefs.output) + else: RET += --include $$shell_quote($$absolute_path($$moc_predefs.output, $$OUT_PWD)) RET += $$incvar $$QMAKE_MOC_OPTIONS return($$RET) From c3059391fea326b7115cf038ecdad8e820a0c2d5 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 9 May 2018 13:38:34 +0200 Subject: [PATCH 081/123] Make tests compile for Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This only enables compilation, it doesn't fix any test. Qt on Android supports process, but not TEST_HELPER_INSTALLS. See also acdd57cb for winrt. android-ndk-r10e is used to compile, see http://doc-snapshots.qt.io/qt5-5.11/androidgs.html . corelib/io/{qdir,qresourceengine} need to be fixed later. Done-with: Frederik Gladhorn Done-with: Mårten Nordheim Change-Id: I34b924c8ae5d46d6835b8f0a6606450920f4423b Reviewed-by: Thiago Macieira Reviewed-by: Frederik Gladhorn --- tests/auto/corelib/global/qlogging/qlogging.pro | 2 +- tests/auto/corelib/global/qlogging/test/test.pro | 2 +- tests/auto/corelib/io/io.pro | 5 +++++ tests/auto/corelib/io/qfile/tst_qfile.cpp | 6 ++++++ tests/auto/corelib/kernel/kernel.pro | 2 +- tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro | 2 +- tests/auto/corelib/thread/qthreadstorage/test/test.pro | 2 +- tests/auto/corelib/tools/qlocale/test/test.pro | 2 +- tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp | 2 +- tests/auto/gui/kernel/kernel.pro | 2 +- tests/auto/gui/kernel/qclipboard/test/test.pro | 2 +- tests/auto/network/access/qnetworkreply/test/test.pro | 2 +- tests/auto/network/bearer/qnetworksession/test/test.pro | 2 +- tests/auto/other/qcomplextext/android_testdata.qrc | 6 ++++++ tests/auto/other/qcomplextext/qcomplextext.pro | 4 +++- tests/auto/testlib/selftests/test/test.pro | 2 +- tests/auto/widgets/kernel/qapplication/test/test.pro | 2 +- 17 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 tests/auto/other/qcomplextext/android_testdata.qrc diff --git a/tests/auto/corelib/global/qlogging/qlogging.pro b/tests/auto/corelib/global/qlogging/qlogging.pro index bbe75297d51..3f7c0a4074d 100644 --- a/tests/auto/corelib/global/qlogging/qlogging.pro +++ b/tests/auto/corelib/global/qlogging/qlogging.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -!winrt { +!android:!winrt { test.depends = app SUBDIRS += app } diff --git a/tests/auto/corelib/global/qlogging/test/test.pro b/tests/auto/corelib/global/qlogging/test/test.pro index 7c46ae9d163..b48bf82cf9a 100644 --- a/tests/auto/corelib/global/qlogging/test/test.pro +++ b/tests/auto/corelib/global/qlogging/test/test.pro @@ -7,5 +7,5 @@ QT = core testlib SOURCES = ../tst_qlogging.cpp DEFINES += QT_MESSAGELOGCONTEXT -!winrt: TEST_HELPER_INSTALLS = ../app/app +!android:!winrt: TEST_HELPER_INSTALLS = ../app/app DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/corelib/io/io.pro b/tests/auto/corelib/io/io.pro index 5618a422036..5eab944fe4f 100644 --- a/tests/auto/corelib/io/io.pro +++ b/tests/auto/corelib/io/io.pro @@ -64,3 +64,8 @@ win32:!qtConfig(private_tests): SUBDIRS -= \ winrt: SUBDIRS -= \ qstorageinfo + +android: SUBDIRS -= \ + qprocess \ + qdir \ + qresourceengine diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index ad00e25e7d4..c2029238987 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -85,6 +85,12 @@ QT_END_NAMESPACE #include #include +#ifdef Q_OS_ANDROID +// Android introduces a braindamaged fileno macro that isn't +// compatible with the POSIX fileno or its own FILE type. +# undef fileno +#endif + #if defined(Q_OS_WIN) #include "../../../network-settings.h" #endif diff --git a/tests/auto/corelib/kernel/kernel.pro b/tests/auto/corelib/kernel/kernel.pro index b5b64973d37..09074a9e8a5 100644 --- a/tests/auto/corelib/kernel/kernel.pro +++ b/tests/auto/corelib/kernel/kernel.pro @@ -40,7 +40,7 @@ SUBDIRS=\ # This test is only applicable on Windows !win32*|winrt: SUBDIRS -= qwineventnotifier -android|uikit: SUBDIRS -= qclipboard qobject qsharedmemory qsystemsemaphore +android|uikit: SUBDIRS -= qobject qsharedmemory qsystemsemaphore !qtConfig(systemsemaphore): SUBDIRS -= \ qsystemsemaphore diff --git a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro index 75898f6adde..432c564ba11 100644 --- a/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro +++ b/tests/auto/corelib/thread/qthreadstorage/qthreadstorage.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -!winrt { +!android:!winrt { test.depends = crashonexit SUBDIRS += crashonexit } diff --git a/tests/auto/corelib/thread/qthreadstorage/test/test.pro b/tests/auto/corelib/thread/qthreadstorage/test/test.pro index 1a1fede1866..d7190f7e7be 100644 --- a/tests/auto/corelib/thread/qthreadstorage/test/test.pro +++ b/tests/auto/corelib/thread/qthreadstorage/test/test.pro @@ -5,5 +5,5 @@ CONFIG += console QT = core testlib SOURCES = ../tst_qthreadstorage.cpp -!winrt: TEST_HELPER_INSTALLS = ../crashonexit/crashonexit +!android:!winrt: TEST_HELPER_INSTALLS = ../crashonexit/crashonexit diff --git a/tests/auto/corelib/tools/qlocale/test/test.pro b/tests/auto/corelib/tools/qlocale/test/test.pro index c87e29e7647..f7243e99a7b 100644 --- a/tests/auto/corelib/tools/qlocale/test/test.pro +++ b/tests/auto/corelib/tools/qlocale/test/test.pro @@ -16,4 +16,4 @@ win32 { } } -!winrt: TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp +!android:!winrt: TEST_HELPER_INSTALLS = ../syslocaleapp/syslocaleapp diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp index cb963ceeb61..29efd8fb4ae 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp @@ -882,7 +882,7 @@ void tst_QTimeZone::icuTest() void tst_QTimeZone::tzTest() { -#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN +#if defined QT_BUILD_INTERNAL && defined Q_OS_UNIX && !defined Q_OS_DARWIN && !defined Q_OS_ANDROID // Known datetimes qint64 std = QDateTime(QDate(2012, 1, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); qint64 dst = QDateTime(QDate(2012, 6, 1), QTime(0, 0, 0), Qt::UTC).toMSecsSinceEpoch(); diff --git a/tests/auto/gui/kernel/kernel.pro b/tests/auto/gui/kernel/kernel.pro index 46786262c05..fbd3b1b3712 100644 --- a/tests/auto/gui/kernel/kernel.pro +++ b/tests/auto/gui/kernel/kernel.pro @@ -37,4 +37,4 @@ win32:!winrt:qtHaveModule(network): SUBDIRS += noqteventloop !qtConfig(opengl): SUBDIRS -= qopenglwindow -uikit: SUBDIRS -= qclipboard +android|uikit: SUBDIRS -= qclipboard diff --git a/tests/auto/gui/kernel/qclipboard/test/test.pro b/tests/auto/gui/kernel/qclipboard/test/test.pro index 59b77b11bae..84e80d62e64 100644 --- a/tests/auto/gui/kernel/qclipboard/test/test.pro +++ b/tests/auto/gui/kernel/qclipboard/test/test.pro @@ -13,6 +13,6 @@ win32 { } } -!winrt: TEST_HELPER_INSTALLS = \ +!android:!winrt: TEST_HELPER_INSTALLS = \ ../copier/copier \ ../paster/paster diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro index 1f45ac0c498..e8464e81af0 100644 --- a/tests/auto/network/access/qnetworkreply/test/test.pro +++ b/tests/auto/network/access/qnetworkreply/test/test.pro @@ -13,4 +13,4 @@ RESOURCES += ../qnetworkreply.qrc TESTDATA += ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg ../certs \ ../index.html ../smb-file.txt -!winrt: TEST_HELPER_INSTALLS = ../echo/echo +!android:!winrt: TEST_HELPER_INSTALLS = ../echo/echo diff --git a/tests/auto/network/bearer/qnetworksession/test/test.pro b/tests/auto/network/bearer/qnetworksession/test/test.pro index c95baa2b813..bfc1ec7727a 100644 --- a/tests/auto/network/bearer/qnetworksession/test/test.pro +++ b/tests/auto/network/bearer/qnetworksession/test/test.pro @@ -15,4 +15,4 @@ CONFIG(debug_and_release) { DESTDIR = .. } -!winrt: TEST_HELPER_INSTALLS = ../lackey/lackey +!android:!winrt: TEST_HELPER_INSTALLS = ../lackey/lackey diff --git a/tests/auto/other/qcomplextext/android_testdata.qrc b/tests/auto/other/qcomplextext/android_testdata.qrc new file mode 100644 index 00000000000..828176df4ae --- /dev/null +++ b/tests/auto/other/qcomplextext/android_testdata.qrc @@ -0,0 +1,6 @@ + + + data/BidiCharacterTest.txt + data/BidiTest.txt + + diff --git a/tests/auto/other/qcomplextext/qcomplextext.pro b/tests/auto/other/qcomplextext/qcomplextext.pro index d51dcb4cffc..5135b48fee7 100644 --- a/tests/auto/other/qcomplextext/qcomplextext.pro +++ b/tests/auto/other/qcomplextext/qcomplextext.pro @@ -8,5 +8,7 @@ TESTDATA += data android { RESOURCES += \ - testdata.qrc + android_testdata.qrc } + +builtin_testdata: DEFINES += BUILTIN_TESTDATA diff --git a/tests/auto/testlib/selftests/test/test.pro b/tests/auto/testlib/selftests/test/test.pro index a7487736b39..bd2366f3e8d 100644 --- a/tests/auto/testlib/selftests/test/test.pro +++ b/tests/auto/testlib/selftests/test/test.pro @@ -15,5 +15,5 @@ win32 { RESOURCES += ../selftests.qrc include(../selftests.pri) -!winrt: for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" +!android:!winrt: for(file, SUBPROGRAMS): TEST_HELPER_INSTALLS += "../$${file}/$${file}" diff --git a/tests/auto/widgets/kernel/qapplication/test/test.pro b/tests/auto/widgets/kernel/qapplication/test/test.pro index 7f75501474a..41aad02a1b0 100644 --- a/tests/auto/widgets/kernel/qapplication/test/test.pro +++ b/tests/auto/widgets/kernel/qapplication/test/test.pro @@ -9,7 +9,7 @@ TARGET = ../tst_qapplication TESTDATA = ../test/test.pro ../tmp/README -!winrt { +!android:!winrt { SUBPROGRAMS = desktopsettingsaware modal win32:SUBPROGRAMS += wincmdline From 372b5504fd766470dc9fddd05b07adfc99b7faa3 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Mon, 25 Jun 2018 08:56:54 +0200 Subject: [PATCH 082/123] Do not build SPDY support if SSL is disabled QSpdyProtocolHandler requires the features http and ssl. This fixes the moc warning src/network/access/qspdyprotocolhandler_p.h:0: Note: No relevant classes found. No output generated. for the -no-ssl build. Change-Id: I915751e98fc67e8601a8da8c5d18b11304bc0390 Reviewed-by: Timur Pocheptsov Reviewed-by: Peter Hartmann --- src/network/access/access.pri | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 1d6a04a4240..a129beda15c 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -84,8 +84,7 @@ qtConfig(http) { access/qhttpnetworkrequest.cpp \ access/qhttpprotocolhandler.cpp \ access/qhttpthreaddelegate.cpp \ - access/qnetworkreplyhttpimpl.cpp \ - access/qspdyprotocolhandler.cpp + access/qnetworkreplyhttpimpl.cpp HEADERS += \ access/qabstractprotocolhandler_p.h \ @@ -99,6 +98,12 @@ qtConfig(http) { access/qhttpnetworkrequest_p.h \ access/qhttpprotocolhandler_p.h \ access/qhttpthreaddelegate_p.h \ - access/qnetworkreplyhttpimpl_p.h \ - access/qspdyprotocolhandler_p.h + access/qnetworkreplyhttpimpl_p.h + + qtConfig(ssl) { + SOURCES += \ + access/qspdyprotocolhandler.cpp + HEADERS += \ + access/qspdyprotocolhandler_p.h + } } From 8e075dac8f08039957fc89d48042c8810d6ae63b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 20 Jun 2018 14:19:21 +0200 Subject: [PATCH 083/123] syncqt: make it possible to declare particular headers being private following the same mechanism as qpa headers, one can specify a list of regexes in the @private_headers variable in sync.profile. Change-Id: I5de0284e639ad283561f54dba7dda8c6437b23f8 Reviewed-by: Johan Helsing Reviewed-by: Joerg Bornemann --- bin/syncqt.pl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 78fe0663b5f..8890b317700 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -84,7 +84,7 @@ $INPUT_RECORD_SEPARATOR = "\r\n" if ($^O eq "msys"); # will be defined based on the modules sync.profile our (%modules, %moduleheaders, @allmoduleheadersprivate, %classnames, %deprecatedheaders); -our @qpa_headers = (); +our (@qpa_headers, @private_headers); # will be derived from sync.profile our %reverse_classnames = (); @@ -659,6 +659,8 @@ sub loadSyncProfile { $reverse_classnames{$cn} = $fn; } } + + push @private_headers, qr/_p(ch)?\.h$/; } sub basePrettify { @@ -701,6 +703,15 @@ sub isQpaHeader return 0; } +sub isPrivateHeader +{ + my ($header) = @_; + foreach my $private_header (@private_headers) { + return 1 if ($header =~ $private_header); + } + return 0; +} + sub globosort($$) { my ($a, $b) = @_; if ($a =~ /^q(.*)global\.h$/) { @@ -1021,7 +1032,7 @@ foreach my $lib (@modules_to_sync) { if(isQpaHeader($public_header)) { $public_header = 0; $qpa_header = 1; - } elsif ($allheadersprivate || $thisprivate || $public_header =~ /_p(ch)?\.h$/) { + } elsif ($allheadersprivate || $thisprivate || isPrivateHeader($public_header)) { $public_header = 0; } From 7c34e0a7b48572be1f9e3fb45911a13b01798e37 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 8 Jun 2018 21:18:11 +0200 Subject: [PATCH 084/123] qmake: escape colons and hashmarks in dependency paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit these characters can appear in file names, but are meta characters in dependency context. they have different semantics in make commands, so this required some reshuffling in the windows generator (which just treated dependencies and commands the same way). we don't actually escape colons for nmake, because it has magic treatment of drive letters anyway (and colons cannot appear elsewhere). also, if a target's filename gets quoted, batch rules will blow up. therefore, "funny" file names are really only supported as inputs - which is just enough to make resource embedding work. Task-number: QTBUG-22863 Task-number: QTBUG-68635 Change-Id: I473b0bf47d045298fd2ae481a29de603a3c1be30 Reviewed-by: Mårten Nordheim Reviewed-by: Joerg Bornemann --- qmake/generators/makefile.cpp | 13 +++++++++++++ qmake/generators/makefile.h | 4 ++-- qmake/generators/projectgenerator.h | 3 +++ qmake/generators/win32/mingw_make.cpp | 3 +-- qmake/generators/win32/mingw_make.h | 4 ++-- qmake/generators/win32/winmakefile.cpp | 12 ++++++++++++ qmake/generators/win32/winmakefile.h | 4 +++- 7 files changed, 36 insertions(+), 7 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index dda323535d6..580df85c1eb 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2823,6 +2823,19 @@ MakefileGenerator::escapeFilePaths(const ProStringList &paths) const return ret; } +QString +MakefileGenerator::escapeDependencyPath(const QString &path) const +{ + QString ret = path; + if (!ret.isEmpty()) { + // Unix make semantics, to be inherited by unix and mingw generators. + static const QRegExp criticalChars(QStringLiteral("([\t :#])")); + ret.replace(criticalChars, QStringLiteral("\\\\1")); + debug_msg(2, "escapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData()); + } + return ret; +} + ProString MakefileGenerator::escapeDependencyPath(const ProString &path) const { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 6341a141b97..f32bec650e7 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -130,11 +130,11 @@ protected: QMakeProject *project; //escape - virtual QString escapeFilePath(const QString &path) const { return path; } + virtual QString escapeFilePath(const QString &path) const = 0; ProString escapeFilePath(const ProString &path) const; QStringList escapeFilePaths(const QStringList &paths) const; ProStringList escapeFilePaths(const ProStringList &paths) const; - virtual QString escapeDependencyPath(const QString &path) const { return escapeFilePath(path); } + virtual QString escapeDependencyPath(const QString &path) const; ProString escapeDependencyPath(const ProString &path) const; QStringList escapeDependencyPaths(const QStringList &paths) const; ProStringList escapeDependencyPaths(const ProStringList &paths) const; diff --git a/qmake/generators/projectgenerator.h b/qmake/generators/projectgenerator.h index 587c4150553..89c66f1ec8e 100644 --- a/qmake/generators/projectgenerator.h +++ b/qmake/generators/projectgenerator.h @@ -42,6 +42,9 @@ class ProjectGenerator : public MakefileGenerator protected: virtual void init(); virtual bool writeMakefile(QTextStream &); + + virtual QString escapeFilePath(const QString &path) const { Q_ASSERT(false); return QString(); } + public: ProjectGenerator(); ~ProjectGenerator(); diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 6140debf055..6fcfe963800 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -46,8 +46,7 @@ QString MingwMakefileGenerator::escapeDependencyPath(const QString &path) const { QString ret = path; ret.replace('\\', "/"); // ### this shouldn't be here - ret.replace(' ', QLatin1String("\\ ")); - return ret; + return MakefileGenerator::escapeDependencyPath(ret); } QString MingwMakefileGenerator::getManifestFileForRcFile() const diff --git a/qmake/generators/win32/mingw_make.h b/qmake/generators/win32/mingw_make.h index ab9e5a9961e..6f041cfd4a2 100644 --- a/qmake/generators/win32/mingw_make.h +++ b/qmake/generators/win32/mingw_make.h @@ -39,8 +39,8 @@ public: MingwMakefileGenerator(); ~MingwMakefileGenerator(); protected: - QString escapeDependencyPath(const QString &path) const; - ProString escapeDependencyPath(const ProString &path) const { return MakefileGenerator::escapeDependencyPath(path); } + using MakefileGenerator::escapeDependencyPath; + virtual QString escapeDependencyPath(const QString &path) const; virtual ProString fixLibFlag(const ProString &lib); virtual QString getManifestFileForRcFile() const; bool writeMakefile(QTextStream &); diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 75bb5d236df..bca27b7044a 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -773,6 +773,18 @@ QString Win32MakefileGenerator::escapeFilePath(const QString &path) const return ret; } +QString Win32MakefileGenerator::escapeDependencyPath(const QString &path) const +{ + QString ret = path; + if (!ret.isEmpty()) { + static const QRegExp criticalChars(QStringLiteral("([\t #])")); + if (ret.contains(criticalChars)) + ret = "\"" + ret + "\""; + debug_msg(2, "EscapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData()); + } + return ret; +} + QString Win32MakefileGenerator::cQuoted(const QString &str) { QString ret = str; diff --git a/qmake/generators/win32/winmakefile.h b/qmake/generators/win32/winmakefile.h index 4d5ee9812b7..b85a6b67df2 100644 --- a/qmake/generators/win32/winmakefile.h +++ b/qmake/generators/win32/winmakefile.h @@ -47,8 +47,10 @@ protected: virtual void writeObjectsPart(QTextStream &t); virtual void writeImplicitRulesPart(QTextStream &t); virtual void writeBuildRulesPart(QTextStream &); + using MakefileGenerator::escapeFilePath; virtual QString escapeFilePath(const QString &path) const; - ProString escapeFilePath(const ProString &path) const { return MakefileGenerator::escapeFilePath(path); } + using MakefileGenerator::escapeDependencyPath; + virtual QString escapeDependencyPath(const QString &path) const; virtual void writeRcFilePart(QTextStream &t); From e21d1d38564dde337ab60636e28bfe8d5b6e67df Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 22 Jun 2018 09:57:55 +0200 Subject: [PATCH 085/123] QtCore/QtNetwork/QTestlib: Fix build with MinGW/g++ 8.1 x64 Fix warnings about invalid function type casts (return types conflicting with the FARPROC returned by GetProcAddress()) like: corelib\global\qoperatingsystemversion_win.cpp:100:48: error: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'RtlGetVersionFunction' {aka 'long int (*)(_OSVERSIONINFOW*)'} [-Werror=cast-function-type] io\qlockfile_win.cpp:158:85: error: cast between incompatible function types from 'FARPROC' {aka 'long long int (*)()'} to 'GetModuleFileNameExFunc' {aka 'long unsigned int (*)(void*, HINSTANCE__*, wchar_t*, long unsigned int)'} [-Werror=cast-function-type] by introducing nested casts. Task-number: QTBUG-68742 Task-number: QTQAINFRA-2095 Change-Id: I3a5d2ea901bf5dc35963c589d61cf3dc7393377a Reviewed-by: Timur Pocheptsov --- src/corelib/global/qoperatingsystemversion_win.cpp | 2 +- src/corelib/io/qlockfile_win.cpp | 5 ++--- src/network/kernel/qauthenticator.cpp | 4 ++-- src/testlib/qtestcase.cpp | 6 ++++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/corelib/global/qoperatingsystemversion_win.cpp b/src/corelib/global/qoperatingsystemversion_win.cpp index f3662ae1f90..7659fb25502 100644 --- a/src/corelib/global/qoperatingsystemversion_win.cpp +++ b/src/corelib/global/qoperatingsystemversion_win.cpp @@ -97,7 +97,7 @@ static inline OSVERSIONINFOEX determineWinOsVersion() // because linking to it at load time will not pass the Windows App Certification Kit // https://msdn.microsoft.com/en-us/library/windows/hardware/ff561910.aspx RtlGetVersionFunction pRtlGetVersion = reinterpret_cast( - GetProcAddressA(ntdll, "RtlGetVersion")); + reinterpret_cast(GetProcAddressA(ntdll, "RtlGetVersion"))); if (Q_UNLIKELY(!pRtlGetVersion)) return result; diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 6b8028460cd..277f8d42309 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -153,9 +153,8 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) HMODULE hPsapi = LoadLibraryA("psapi"); if (!hPsapi) return QString(); - - GetModuleFileNameExFunc qGetModuleFileNameEx - = (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW"); + GetModuleFileNameExFunc qGetModuleFileNameEx = reinterpret_cast( + reinterpret_cast(GetProcAddress(hPsapi, "GetModuleFileNameExW"))); if (!qGetModuleFileNameEx) { FreeLibrary(hPsapi); return QString(); diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index a3ccf13e82f..c995e3fef2f 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -1454,8 +1454,8 @@ static bool q_NTLM_SSPI_library_load() securityDLLHandle = LoadLibrary(L"secur32.dll"); if (securityDLLHandle != NULL) { INIT_SECURITY_INTERFACE pInitSecurityInterface = - (INIT_SECURITY_INTERFACE)GetProcAddress(securityDLLHandle, - "InitSecurityInterfaceW"); + reinterpret_cast( + reinterpret_cast(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW"))); if (pInitSecurityInterface != NULL) pSecurityFunctionTable = pInitSecurityInterface(); } diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index acd676833e8..f5668c274e2 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1603,8 +1603,10 @@ DebugSymbolResolver::DebugSymbolResolver(HANDLE process) bool success = false; m_dbgHelpLib = LoadLibraryW(L"dbghelp.dll"); if (m_dbgHelpLib) { - SymInitializeType symInitialize = (SymInitializeType)(GetProcAddress(m_dbgHelpLib, "SymInitialize")); - m_symFromAddr = (SymFromAddrType)(GetProcAddress(m_dbgHelpLib, "SymFromAddr")); + SymInitializeType symInitialize = reinterpret_cast( + reinterpret_cast(GetProcAddress(m_dbgHelpLib, "SymInitialize"))); + m_symFromAddr = reinterpret_cast( + reinterpret_cast(GetProcAddress(m_dbgHelpLib, "SymFromAddr"))); success = symInitialize && m_symFromAddr && symInitialize(process, NULL, TRUE); } if (!success) From c5307203f5c0b0e588cc93e70764c090dd4c2ce0 Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Wed, 10 Jun 2015 16:56:27 +0300 Subject: [PATCH 086/123] Fix interaction with the menu bar on touchscreens Ignore synthesized mouse move events whithout the left mouse button pressed. We receive such mouse move event on touch before the mouse press event, it causes the menu to show and then the subsequent mouse press event closes the menu. Also don't propagate mouse events after closing a popup to another popup, because they may close the latter one. Change-Id: I50a2d9b57da63d33ffe416161a09f1696d65c88f Reviewed-by: Friedemann Kleint Reviewed-by: Shawn Rutledge --- src/widgets/widgets/qmenubar.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 4758f64c8c9..7c4dd896a4a 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1209,8 +1209,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) void QMenuBar::mouseMoveEvent(QMouseEvent *e) { Q_D(QMenuBar); - if (!(e->buttons() & Qt::LeftButton)) + if (!(e->buttons() & Qt::LeftButton)) { d->mouseDown = false; + // We receive mouse move and mouse press on touch. + // Mouse move will open the menu and mouse press + // will close it, so ignore mouse move. + if (e->source() != Qt::MouseEventNotSynthesized) + return; + } + bool popupState = d->popupState || d->mouseDown; QAction *action = d->actionAt(e->pos()); if ((action && d->isVisible(action)) || !popupState) From 1049d3f9db2b9bbdf5438b9f53849b82a2286848 Mon Sep 17 00:00:00 2001 From: Kari Oikarinen Date: Tue, 27 Mar 2018 16:19:07 +0300 Subject: [PATCH 087/123] tst_QTimer: Replace unconditional qWait()s with QSignalSpy Where possible. Sometimes the replacement is QTRY_COMPARE instead. Also don't use QTestEventLoop directly when it can also be replaced with QSignalSpy use. Remove the TimerHelper class, since its uses can be done with QSignalSpy (and a lambda when remainingTime is checked). Although checking static single-shot timers still needs a target object, so use a stripped down version in those tests. remainingTimeDuringActivation() was not actually testing the repeating case, but single-shot case twice, so fix that. In the repeating case the remaining time is exactly 20 ms on my machine, but QEMU emulation seems to be slow enough for time to advance before the lambda is executed, so relax the conditions. Task-number: QTBUG-63992 Change-Id: Iae92ff7862a13d36e695eec63b54403ec872f2b4 Reviewed-by: Sami Nurmenniemi Reviewed-by: Frederik Gladhorn Reviewed-by: Gatis Paeglis --- .../auto/corelib/kernel/qtimer/tst_qtimer.cpp | 265 ++++++++---------- 1 file changed, 112 insertions(+), 153 deletions(-) diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp index 2c6d9ea7c07..5b2d77a02c7 100644 --- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp +++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp @@ -77,102 +77,65 @@ private slots: void postedEventsShouldNotStarveTimers(); }; -class TimerHelper : public QObject -{ - Q_OBJECT -public: - TimerHelper() : QObject(), count(0), remainingTime(-1) - { - } - - int count; - int remainingTime; - -public slots: - void timeout(); - void fetchRemainingTime(); -}; - -void TimerHelper::timeout() -{ - ++count; -} - -void TimerHelper::fetchRemainingTime() -{ - QTimer *timer = static_cast(sender()); - remainingTime = timer->remainingTime(); -} - void tst_QTimer::zeroTimer() { - TimerHelper helper; QTimer timer; timer.setInterval(0); - timer.start(); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); + timer.start(); QCoreApplication::processEvents(); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); } void tst_QTimer::singleShotTimeout() { - TimerHelper helper; QTimer timer; timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(100); + QVERIFY(timeoutSpy.wait(500)); + QCOMPARE(timeoutSpy.count(), 1); QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); } #define TIMEOUT_TIMEOUT 200 void tst_QTimer::timeout() { - TimerHelper helper; QTimer timer; - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(100); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); - QTRY_VERIFY_WITH_TIMEOUT(helper.count > 0, TIMEOUT_TIMEOUT); - int oldCount = helper.count; + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > 0, TIMEOUT_TIMEOUT); + int oldCount = timeoutSpy.count(); - QTRY_VERIFY_WITH_TIMEOUT(helper.count > oldCount, TIMEOUT_TIMEOUT); + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > oldCount, TIMEOUT_TIMEOUT); } void tst_QTimer::remainingTime() { - TimerHelper helper; QTimer timer; - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.setTimerType(Qt::PreciseTimer); timer.start(200); - QCOMPARE(helper.count, 0); - + QCOMPARE(timeoutSpy.count(), 0); QTest::qWait(50); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); int remainingTime = timer.remainingTime(); QVERIFY2(qAbs(remainingTime - 150) < 50, qPrintable(QString::number(remainingTime))); - // wait for the timer to actually fire now - connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(helper.count, 1); + QVERIFY(timeoutSpy.wait()); + QCOMPARE(timeoutSpy.count(), 1); // the timer is still active, so it should have a non-zero remaining time remainingTime = timer.remainingTime(); @@ -182,7 +145,7 @@ void tst_QTimer::remainingTime() void tst_QTimer::remainingTimeDuringActivation_data() { QTest::addColumn("singleShot"); - QTest::newRow("repeating") << true; + QTest::newRow("repeating") << false; QTest::newRow("single-shot") << true; } @@ -190,29 +153,31 @@ void tst_QTimer::remainingTimeDuringActivation() { QFETCH(bool, singleShot); - TimerHelper helper; QTimer timer; - - const int timeout = 20; // 20 ms is short enough and should not round down to 0 in any timer mode - - connect(&timer, SIGNAL(timeout()), &helper, SLOT(fetchRemainingTime())); - connect(&timer, SIGNAL(timeout()), &QTestEventLoop::instance(), SLOT(exitLoop())); - timer.start(timeout); timer.setSingleShot(singleShot); - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); + int remainingTime = 0; // not the expected value in either case + connect(&timer, &QTimer::timeout, + [&]() { + remainingTime = timer.remainingTime(); + }); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); + const int timeout = 20; // 20 ms is short enough and should not round down to 0 in any timer mode + timer.start(timeout); + + QVERIFY(timeoutSpy.wait()); if (singleShot) - QCOMPARE(helper.remainingTime, -1); // timer not running + QCOMPARE(remainingTime, -1); // timer not running else - QCOMPARE(helper.remainingTime, timeout); + QVERIFY2(remainingTime <= timeout && remainingTime > 0, + qPrintable(QString::number(remainingTime))); if (!singleShot) { // do it again - see QTBUG-46940 - helper.remainingTime = -1; - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(helper.remainingTime, timeout); + remainingTime = -1; + QVERIFY(timeoutSpy.wait()); + QVERIFY2(remainingTime <= timeout && remainingTime > 0, + qPrintable(QString::number(remainingTime))); } } @@ -233,47 +198,44 @@ void tst_QTimer::basic_chrono() #else // duplicates zeroTimer, singleShotTimeout, interval and remainingTime using namespace std::chrono; - TimerHelper helper; QTimer timer; + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.setInterval(to_ms(nanoseconds(0))); timer.start(); QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(0)); QCOMPARE(timer.remainingTimeAsDuration().count(), milliseconds::rep(0)); - connect(&timer, SIGNAL(timeout()), &helper, SLOT(timeout())); - QCoreApplication::processEvents(); - QCOMPARE(helper.count, 1); + QCOMPARE(timeoutSpy.count(), 1); - helper.count = 0; + timeoutSpy.clear(); timer.start(milliseconds(100)); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); - QTest::qWait(TIMEOUT_TIMEOUT); - QVERIFY(helper.count > 0); - int oldCount = helper.count; + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QVERIFY(timeoutSpy.count() > 0); + int oldCount = timeoutSpy.count(); - QTest::qWait(TIMEOUT_TIMEOUT); - QVERIFY(helper.count > oldCount); + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QVERIFY(timeoutSpy.count() > oldCount); - helper.count = 0; + timeoutSpy.clear(); timer.start(to_ms(microseconds(200000))); QCOMPARE(timer.intervalAsDuration().count(), milliseconds::rep(200)); QTest::qWait(50); - QCOMPARE(helper.count, 0); + QCOMPARE(timeoutSpy.count(), 0); milliseconds rt = timer.remainingTimeAsDuration(); QVERIFY2(qAbs(rt.count() - 150) < 50, qPrintable(QString::number(rt.count()))); - helper.count = 0; + timeoutSpy.clear(); timer.setSingleShot(true); timer.start(milliseconds(100)); + QVERIFY(timeoutSpy.wait(TIMEOUT_TIMEOUT)); + QCOMPARE(timeoutSpy.count(), 1); QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - helper.count = 0; + QCOMPARE(timeoutSpy.count(), 1); #endif } @@ -448,47 +410,40 @@ signals: void tst_QTimer::recurringTimer_data() { QTest::addColumn("interval"); - QTest::newRow("zero timer") << 0; - QTest::newRow("non-zero timer") << 1; + QTest::addColumn("recurse"); + // make sure that eventloop recursion doesn't affect timer recurrence + QTest::newRow("zero timer, don't recurse") << 0 << false; + QTest::newRow("zero timer, recurse") << 0 << true; + QTest::newRow("non-zero timer, don't recurse") << 1 << false; + QTest::newRow("non-zero timer, recurse") << 1 << true; } void tst_QTimer::recurringTimer() { const int target = 5; QFETCH(int, interval); + QFETCH(bool, recurse); - { - RecurringTimerObject object(target); - QObject::connect(&object, SIGNAL(done()), &QTestEventLoop::instance(), SLOT(exitLoop())); - (void) object.startTimer(interval); - QTestEventLoop::instance().enterLoop(5); + RecurringTimerObject object(target); + object.recurse = recurse; + QSignalSpy doneSpy(&object, &RecurringTimerObject::done); - QCOMPARE(object.times, target); - } + (void) object.startTimer(interval); + QVERIFY(doneSpy.wait()); - { - // make sure that eventloop recursion doesn't effect timer recurrance - RecurringTimerObject object(target); - object.recurse = true; - - QObject::connect(&object, SIGNAL(done()), &QTestEventLoop::instance(), SLOT(exitLoop())); - (void) object.startTimer(interval); - QTestEventLoop::instance().enterLoop(5); - - QCOMPARE(object.times, target); - } + QCOMPARE(object.times, target); } void tst_QTimer::deleteLaterOnQTimer() { QTimer *timer = new QTimer; connect(timer, SIGNAL(timeout()), timer, SLOT(deleteLater())); - connect(timer, SIGNAL(destroyed()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QSignalSpy destroyedSpy(timer, &QObject::destroyed); timer->setInterval(1); timer->setSingleShot(true); timer->start(); QPointer pointer = timer; - QTestEventLoop::instance().enterLoop(5); + QVERIFY(destroyedSpy.wait()); QVERIFY(pointer.isNull()); } @@ -690,23 +645,34 @@ void tst_QTimer::cancelLongTimer() QVERIFY(!timer.isActive()); } +class TimeoutCounter : public QObject +{ + Q_OBJECT +public slots: + void timeout() { ++count; }; +public: + int count = 0; +}; + void tst_QTimer::singleShotStaticFunctionZeroTimeout() { - TimerHelper helper; + { + TimeoutCounter counter; - QTimer::singleShot(0, &helper, SLOT(timeout())); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QTimer::singleShot(0, &counter, SLOT(timeout())); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } - TimerHelper nhelper; + { + TimeoutCounter counter; - QTimer::singleShot(0, &nhelper, &TimerHelper::timeout); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); + QTimer::singleShot(0, &counter, &TimeoutCounter::timeout); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } } class RecursOnTimeoutAndStopTimerTimer : public QObject @@ -807,8 +773,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(e.exec(), 0); QTimer::singleShot(0, &c1, CountedStruct(&count, &t1)); - QTest::qWait(500); - QCOMPARE(count, 2); + QTRY_COMPARE(count, 2); t1.quit(); t1.wait(); @@ -833,12 +798,11 @@ void tst_QTimer::singleShotToFunctors() QObject c3; QTimer::singleShot(500, &c3, CountedStruct(&count)); } - QTest::qWait(800); + QTest::qWait(800); // Wait until the singleshot timer would have timed out QCOMPARE(count, 2); QTimer::singleShot(0, [&count] { ++count; }); - QCoreApplication::processEvents(); - QCOMPARE(count, 3); + QTRY_COMPARE(count, 3); QObject context; QThread thread; @@ -849,8 +813,7 @@ void tst_QTimer::singleShotToFunctors() QCOMPARE(e.exec(), 0); QTimer::singleShot(0, &context, [&count, &thread] { ++count; QCOMPARE(QThread::currentThread(), &thread); }); - QTest::qWait(500); - QCOMPARE(count, 4); + QTRY_COMPARE(count, 4); thread.quit(); thread.wait(); @@ -861,8 +824,7 @@ void tst_QTimer::singleShotToFunctors() MoveOnly(int *c) : CountedStruct(c) {} }; QTimer::singleShot(0, MoveOnly(&count)); - QCoreApplication::processEvents(); - QCOMPARE(count, 5); + QTRY_COMPARE(count, 5); _e.reset(); _t = nullptr; @@ -875,26 +837,27 @@ void tst_QTimer::singleShot_chrono() #else // duplicates singleShotStaticFunctionZeroTimeout and singleShotToFunctors using namespace std::chrono; - TimerHelper helper; + { + TimeoutCounter counter; - QTimer::singleShot(hours(0), &helper, SLOT(timeout())); - QTest::qWait(500); - QCOMPARE(helper.count, 1); - QTest::qWait(500); - QCOMPARE(helper.count, 1); + QTimer::singleShot(hours(0), &counter, SLOT(timeout())); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } - TimerHelper nhelper; + { + TimeoutCounter counter; - QTimer::singleShot(seconds(0), &nhelper, &TimerHelper::timeout); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); - QCoreApplication::processEvents(); - QCOMPARE(nhelper.count, 1); + QTimer::singleShot(hours(0), &counter, &TimeoutCounter::timeout); + QTRY_COMPARE(counter.count, 1); + QTest::qWait(500); + QCOMPARE(counter.count, 1); + } int count = 0; QTimer::singleShot(to_ms(microseconds(0)), CountedStruct(&count)); - QCoreApplication::processEvents(); - QCOMPARE(count, 1); + QTRY_COMPARE(count, 1); _e.reset(new QEventLoop); QTimer::singleShot(0, &StaticEventLoop::quitEventLoop); @@ -902,12 +865,10 @@ void tst_QTimer::singleShot_chrono() QObject c3; QTimer::singleShot(milliseconds(500), &c3, CountedStruct(&count)); - QTest::qWait(800); - QCOMPARE(count, 2); + QTRY_COMPARE(count, 2); QTimer::singleShot(0, [&count] { ++count; }); - QCoreApplication::processEvents(); - QCOMPARE(count, 3); + QTRY_COMPARE(count, 3); _e.reset(); #endif @@ -985,16 +946,14 @@ public slots: void tst_QTimer::postedEventsShouldNotStarveTimers() { - TimerHelper timerHelper; QTimer timer; - connect(&timer, SIGNAL(timeout()), &timerHelper, SLOT(timeout())); timer.setInterval(0); timer.setSingleShot(false); + QSignalSpy timeoutSpy(&timer, &QTimer::timeout); timer.start(); SlotRepeater slotRepeater; slotRepeater.repeatThisSlot(); - QTest::qWait(100); - QVERIFY(timerHelper.count > 5); + QTRY_VERIFY_WITH_TIMEOUT(timeoutSpy.count() > 5, 100); } struct DummyFunctor { From 4d326555ab60e9f19dddaabc34bbabc2a3ebb514 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Fri, 22 Jun 2018 16:27:19 +0200 Subject: [PATCH 088/123] Doc: Add Hello GLES3 example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-67109 Change-Id: I55135264a63b78502b300de723a25b3f363af58b Reviewed-by: Topi Reiniö --- .../doc/images/hellogles3-example.png | Bin 0 -> 61792 bytes .../opengl/hellogles3/doc/src/hellogles3.qdoc | 46 ++++++++++++++++++ examples/opengl/hellogles3/glwindow.cpp | 3 +- examples/opengl/hellogles3/qtlogo.png | Bin 5402 -> 2318 bytes 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 examples/opengl/hellogles3/doc/images/hellogles3-example.png create mode 100644 examples/opengl/hellogles3/doc/src/hellogles3.qdoc diff --git a/examples/opengl/hellogles3/doc/images/hellogles3-example.png b/examples/opengl/hellogles3/doc/images/hellogles3-example.png new file mode 100644 index 0000000000000000000000000000000000000000..e089b9470a1cfaddeed99ccef6f6493ee58d288b GIT binary patch literal 61792 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 z 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

1O-|JvErC2L1!(kovD*@-x>X zX%*j6*{0uZU7#STt?+%>`PrNVi;kCICFd{IQ6%_@e@XtGbIowVKK++NpPfU!ivudT z2Ul@J1@|O~tX29i+|gv0w|CUT^P}@{uj7?tt;-Tjs)%V32FlaM)h1EF)zs&X;$4gq zf5=RByg?W??g~yD;SX6$Li#EMF)h_-(Kc3uCQcXQ8_tnG6wdig)I%I&xSYVFR26CS z_^inxs}h20GAnTgA(!^Q6q81COH*&nxU-Qx0ic)ypq}VbA{Z^m`Y#iS=Q!cu7B|xr zC`upk)SvDf&G-wK-ODRVmpZtes^%#0yd+ELFBp9km#O#r?91DzIJ|%?p?`)ezB(21 z(xwhxzeu5NT766GFAPE@*Mqrsb#?#J{%MLi=F{@~ literal 0 HcmV?d00001 diff --git a/examples/opengl/hellogles3/doc/src/hellogles3.qdoc b/examples/opengl/hellogles3/doc/src/hellogles3.qdoc new file mode 100644 index 00000000000..fbe071f1439 --- /dev/null +++ b/examples/opengl/hellogles3/doc/src/hellogles3.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example hellogles3 + \title Hello GLES3 Example + \ingroup examples-widgets-opengl + + \brief The Hello GLES3 example demonstrates easy, cross-platform usage of + OpenGL ES 3.0 functions via QOpenGLExtraFunctions in an application that + works identically on desktop platforms with OpenGL 3.3 and mobile/embedded + devices with OpenGL ES 3.0. + + The code is always the same, with the exception of two places: + \list + \li The OpenGL context creation has to have a sufficiently high version + number for the features that are in use. + \li The shader code's version directive is different. + \endlist + + \image hellogles3-example.png +*/ diff --git a/examples/opengl/hellogles3/glwindow.cpp b/examples/opengl/hellogles3/glwindow.cpp index 13cbc41ce86..9458b748101 100644 --- a/examples/opengl/hellogles3/glwindow.cpp +++ b/examples/opengl/hellogles3/glwindow.cpp @@ -243,7 +243,8 @@ void GLWindow::initializeGL() f->glEnableVertexAttribArray(0); f->glEnableVertexAttribArray(1); f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0); - f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast(3 * sizeof(GLfloat))); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); m_vbo->release(); f->glEnable(GL_DEPTH_TEST); diff --git a/examples/opengl/hellogles3/qtlogo.png b/examples/opengl/hellogles3/qtlogo.png index 868fcea860b77bcdf5b22e59950dc3fbbc280492..9cb2e01d3895ed7d1a81e91ed5393b474d041671 100644 GIT binary patch literal 2318 zcmaJ>dpuO@8eX|f#fT_jcUg^4VXlUm#Uy4%jcq0kNe5-jEKJO-F&8s*bBV6fFFVmG z9PLWG$k{e>E89s#x$LewDZA03AMNNOcV|sIwf{Js^{utO?|XmG^Stl(zVBLx{COKp zjBJbm05IWfWbx5?z3!QZLEk@#p_Rt9tZAR!{b3v?K~Mj}Jm0N~-NkqLw`uo8@bqr_4M?oG`N94Hnsa9gQd zB3H(Qqs1E&<#0eEFHo2mBczLPp6fsl4TK6vV5I=mNMfZ5NW;K=(uL5q&P>38pCHN@ z2JX+Gg1P=66OqFp74PaSBvHtq8y!!g(#bRzCy-1exe|yj1QOkuM1j!Tg$RDWaHu!A zC=%kcd_Ma^cMM##QYnK71hra?S5xqaJPPH~=>#H~Kqfn*2xmotR4LFnOBJ@W3M^P5 zl#69bF(L(Zih>A4rDWjHNdG*7MD|5is`#8HG+_jdKt>?piMk`r0=eA(50yy1pcP6! z{59VHDXa)gkii5#tUy$9AzHXdTb(Nz#FWDVB_a<*kl5KQ`bQ&5L=lb1Kqga{H7cG8 zuI37aVyVu&<`a+0g*Z}$QXmz=92NtID&fUq5k#ZV$aFG`NF_48NhG!_jn1NZ(_Dx& zsuzn+_HmizvJjz40!x*%T+vr9>6=_#OGsp>XBI3M$HO8YIU)f+9UT&XGZrTMn|hzQ zqHo5+^!X;2fCfX*75Fa&pEaRfq+5PzUv%^31AwJy*UQoNo-@?o0|17J9F|w0=E-2l zuGj#0k>{SukjjdImX=#jb9fiA!8xP#D;KV+J`Nu>OQj5(TBO=fr$O2k>3&m8;eD3S z??EYRxlOJ)^XAbc&}W{XnQcm`$w+L?KjUK_eJHPZ^roiz!pF|0y5h>PKN#Gyk-=S0 z-_<;)_o>^uMFw6;IqU_vCG&x=W8o3LeU{zSOW_iAQD^4%_fm`Q`DUrZoH=GkhOYnz zZ)-3>1SL-|$tojL9}LoRfSa)%xAo<4Ew(Ob;7uBJe4-#|s|oCD+rJ1pXufc0Ln_hw zx=CtsNXMHx?8x!50wB8e;ZS^QR_Wykcc*|;Q7(O^&v%rzPcNQ)Rg)cm#cP|9tvfln-kpP(&Lg`I5UunF!vwi zzYl43O%5vA200Woj)Kg}=Uv}pDwO2q^7`B^Mf0-1y?|mTp)c|cDFi(b?#yqlW@^?;lJE^Nd;rf%2bf%g@Y!PRS73JTteD%<|*~-6U zt+3xd;YT8NecBWA8EH`Ni~Os1P3s-BjNU#d%;cBTZUNd1Em3oB-C-#-XpRAjLt8r% zaEdc-x0WXJj>>$ojSWQer4G-J_#IzRpIMUsw#h(c6j}YYX%dAP^6h&pL$MvVRrIc$ zB&*gZ-vdd+g>Br$L15-8+782!%@}I-B|38DgyXg{=CAraQB@o33Ul7wN(}V9XJ=+? zxej=CF!SWnxWz{fLs1Kgzgvk*GX+A%fA@`$5d>8iaIdQk=hv@pX@BpYHjxzC%L{Wp zH?D24?|N|{9O&U&Qp#DE9tL?AS3p{-tJTA@`*XKu-8=&r@95|?1)TcoPFYo7EM8`P z*O}j6(EZjR!@`W?SY?=fEj;oc+7vz6Q`PD6OT&R|caAt~zO?XAp-=4Qq<9HrogH5-i>{WlCN4iVDk0Ig9Y`m%jui}QscgFW{Z zMXx0m69O77JB4ifaVRu}d%aTrt!PY`c#tfW?YB>OsAsTS;5n}@V8gv* zjjvs+TS*bd?KXCf-p3|(wa-kEcT>g~2Evs*#h%WDQNcLNM~Gm23SvsXla3xZacurg zy~&*?V)L+_j#dBpt-K?6x2f-uEuvIr^5nZ6Bec1e<<>#bYu6~o{fT?jy+YnZk1FOD z$L81+_YPXy(Ydc{#mY9IdH>{Nn`gG$!V3qj9~+hE%-|8~~{PIT4i$ZM( z(U#3+r8Wdh;DikU1MqD&k-c8cVAyzbV0J`g?=!Fh27~qQoMHx`e_;UNuz9Q!@9>oW E0+|Y_$p8QV literal 5402 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 Date: Thu, 14 Jun 2018 13:48:37 +0200 Subject: [PATCH 089/123] Kludge round Android's ignorance of some esoteric time-zone transitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skip a few tests that Android's time-zone information doesn't suffice to get right. Task-number: QTBUG-68835 Change-Id: Ibf8d213c96b29d74fc478a0ede686ae52b5200fb Reviewed-by: Mårten Nordheim Reviewed-by: Thiago Macieira --- tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp index 4e77ff9461c..10856a4d574 100644 --- a/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp +++ b/tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp @@ -2661,14 +2661,20 @@ void tst_QDateTime::zoneAtTime_data() ADDROW("summer70:EST", "America/New_York", summer70, -4 * 3600); } +#ifdef Q_OS_ANDROID // QTBUG-68835; gets offset 0 for the affected tests. +# define NONANDROIDROW(name, zone, date, offset) +#else +# define NONANDROIDROW(name, zone, date, offset) ADDROW(name, zone, date, offset) +#endif + #ifndef Q_OS_WIN // Bracket a few noteworthy transitions: ADDROW("before:ACWST", "Australia/Eucla", QDate(1974, 10, 26), 31500); // 8:45 - ADDROW("after:ACWST", "Australia/Eucla", QDate(1974, 10, 27), 35100); // 9:45 - ADDROW("before:NPT", "Asia/Kathmandu", QDate(1985, 12, 31), 19800); // 5:30 + NONANDROIDROW("after:ACWST", "Australia/Eucla", QDate(1974, 10, 27), 35100); // 9:45 + NONANDROIDROW("before:NPT", "Asia/Kathmandu", QDate(1985, 12, 31), 19800); // 5:30 ADDROW("after:NPT", "Asia/Kathmandu", QDate(1986, 1, 1), 20700); // 5:45 // The two that have skipped a day (each): - ADDROW("before:LINT", "Pacific/Kiritimati", QDate(1994, 12, 30), -36000); + NONANDROIDROW("before:LINT", "Pacific/Kiritimati", QDate(1994, 12, 30), -36000); ADDROW("after:LINT", "Pacific/Kiritimati", QDate(1995, 1, 2), 14 * 3600); ADDROW("after:WST", "Pacific/Apia", QDate(2011, 12, 31), 14 * 3600); #endif // MS lacks ACWST, NPT; doesn't grok date-line crossings; and Windows 7 lacks LINT. From afa2d38a89e07dad292c82c6d739d7a17bce4111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Thu, 21 Jun 2018 14:33:23 +0200 Subject: [PATCH 090/123] Android: Blacklist tst_qframe::testPainting It causes most of the fails seen on Android. Task-number: QTBUG-69064 Change-Id: I2f97fea41ee78e7962b8c34ed996bbe4bcb88732 Reviewed-by: Jesus Fernandez --- tests/auto/widgets/widgets/qframe/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/widgets/widgets/qframe/BLACKLIST diff --git a/tests/auto/widgets/widgets/qframe/BLACKLIST b/tests/auto/widgets/widgets/qframe/BLACKLIST new file mode 100644 index 00000000000..3a28dd12392 --- /dev/null +++ b/tests/auto/widgets/widgets/qframe/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-69064 +[testPainting] +android From 531f950226a84bdf439c09c2acf4c327586d27c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Fri, 22 Jun 2018 16:07:52 +0200 Subject: [PATCH 091/123] Android: Blacklist a few cases in tst_qgroupbox Task-number: QTBUG-69084 Task-number: QTBUG-69083 Change-Id: Icf218795f81f01a559094cf2088f53a9fd597c24 Reviewed-by: Jesus Fernandez --- tests/auto/widgets/widgets/qgroupbox/BLACKLIST | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/auto/widgets/widgets/qgroupbox/BLACKLIST diff --git a/tests/auto/widgets/widgets/qgroupbox/BLACKLIST b/tests/auto/widgets/widgets/qgroupbox/BLACKLIST new file mode 100644 index 00000000000..62ba05797ef --- /dev/null +++ b/tests/auto/widgets/widgets/qgroupbox/BLACKLIST @@ -0,0 +1,13 @@ +# QTBUG-69083 +[clicked:hit nothing, checkable] +android +[clicked:hit frame, checkable] +android +[clicked:hit nothing, checkable, but unchecked] +android +[clicked:hit frame, checkable, but unchecked] +android + +# QTBUG-69084 +[task_QTBUG_15519_propagateMouseEvents] +android From 6934be03fef97ca1e1c0051b19f98523a907f520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 25 Jun 2018 15:32:45 +0200 Subject: [PATCH 092/123] Android: Blacklist various cases in tst_QLineEdit Task-number: QTBUG-69111 Task-number: QTBUG-69112 Task-number: QTBUG-69113 Task-number: QTBUG-69114 Task-number: QTBUG-69115 Task-number: QTBUG-69116 Task-number: QTBUG-69118 Task-number: QTBUG-69119 Change-Id: I424cb472e97bd427e800ee230e0e57d763d1b8a6 Reviewed-by: Jesus Fernandez --- .../auto/widgets/widgets/qlineedit/BLACKLIST | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/auto/widgets/widgets/qlineedit/BLACKLIST diff --git a/tests/auto/widgets/widgets/qlineedit/BLACKLIST b/tests/auto/widgets/widgets/qlineedit/BLACKLIST new file mode 100644 index 00000000000..537c81413e4 --- /dev/null +++ b/tests/auto/widgets/widgets/qlineedit/BLACKLIST @@ -0,0 +1,31 @@ +# QTBUG-69111 +[undo_keypressevents:Inserts,moving,selection, delete and undo] +android + +# QTBUG-69112 +[inlineCompletion] +android + +# QTBUG-69116 +[leftKeyOnSelectedText] +android + +# QTBUG-69113 +[textMargin] +android + +# QTBUG-69119 +[task174640_editingFinished] +android + +# QTBUG-69118 +[task210502_caseInsensitiveInlineCompletion] +android + +# QTBUG-69114 +[QTBUG697_paletteCurrentColorGroup] +android + +# QTBUG-69115 +[testQuickSelectionWithMouse] +android From a7730793becc55cb535cd4c262b418f93405a81e Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Thu, 14 Jun 2018 00:53:30 +0200 Subject: [PATCH 093/123] wayland-scanner.prf: Remove special-casing for generated headers Generated headers can now be installed using inject_headers and private_headers instead. Change-Id: I51d98e2e05d12aa9f6ab09f8ccb12b81a0c0cd6f Reviewed-by: Oswald Buddenhagen --- mkspecs/features/wayland-scanner.prf | 75 +++++----------------------- 1 file changed, 12 insertions(+), 63 deletions(-) diff --git a/mkspecs/features/wayland-scanner.prf b/mkspecs/features/wayland-scanner.prf index 4b8e2ef76e0..f1e78b0914f 100644 --- a/mkspecs/features/wayland-scanner.prf +++ b/mkspecs/features/wayland-scanner.prf @@ -14,61 +14,10 @@ isEmpty(QMAKE_WAYLAND_SCANNER):error("QMAKE_WAYLAND_SCANNER not defined for this mkspec") -defineReplace(waylandScannerHeaderFiles) { - side = $$1 - path = $$2 - isEqual(side, "server"): \ - sources_list = $$WAYLANDSERVERSOURCES $$WAYLANDSERVERSOURCES_SYSTEM - else: \ - sources_list = $$WAYLANDCLIENTSOURCES $$WAYLANDCLIENTSOURCES_SYSTEM - wayland_header_files_for_side = - for(file, sources_list) { - basenameFile = $$basename(file) - basenameFile ~= s,\\.xml$,, - wayland_header_files_for_side += $$path/wayland-$$basenameFile-$$side-protocol$${first(QMAKE_EXT_H)} - isEqual(side, "server"): \ - wayland_header_files_for_side += $$path/qwayland-server-$$basenameFile$${first(QMAKE_EXT_H)} - else: \ - wayland_header_files_for_side += $$path/qwayland-$$basenameFile$${first(QMAKE_EXT_H)} - } - return($$wayland_header_files_for_side) -} - -# 1) if we are a module, we need to create the headers in our private inc dir in qtbase -# 2) if also qt_install_headers is set, we need to generate INSTALLS rules in addition -# 3) if we are not a module, we just generate the headers in the current directory -!isEmpty(MODULE) { - header_dest = $$MODULE_BASE_OUTDIR/include/$$MODULE_INCNAME/$$VERSION/$$MODULE_INCNAME/private - - header_files_client = $$waylandScannerHeaderFiles(client, $$header_dest) - !isEmpty(header_files_client) { - qt_install_headers { - wayland_generated_client_headers.files = $$header_files_client - wayland_generated_client_headers.path = $$private_headers.path - wayland_generated_client_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_client_headers - } - WAYLAND_CLIENT_HEADER_DEST = $$header_dest/ - WAYLAND_CLIENT_INCLUDE_DIR = $$MODULE_INCNAME/private - } - - header_files_server = $$waylandScannerHeaderFiles(server, $$header_dest) - !isEmpty(header_files_server) { - qt_install_headers { - wayland_generated_server_headers.files = $$header_files_server - wayland_generated_server_headers.path = $$private_headers.path - wayland_generated_server_headers.CONFIG = no_check_exist - INSTALLS += wayland_generated_server_headers - } - WAYLAND_SERVER_HEADER_DEST = $$header_dest/ - WAYLAND_SERVER_INCLUDE_DIR = $$MODULE_INCNAME/private - } -} - wayland_server_header.name = wayland ${QMAKE_FILE_BASE} wayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM wayland_server_header.variable_out = HEADERS -wayland_server_header.output = $${WAYLAND_SERVER_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} +wayland_server_header.output = wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} wayland_server_header.commands = $$QMAKE_WAYLAND_SCANNER server-header < ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:wayland_server_header.commands = @echo Wayland server header ${QMAKE_FILE_IN} && $$wayland_server_header.commands QMAKE_EXTRA_COMPILERS += wayland_server_header @@ -76,7 +25,7 @@ QMAKE_EXTRA_COMPILERS += wayland_server_header wayland_client_header.name = wayland ${QMAKE_FILE_BASE} wayland_client_header.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM wayland_client_header.variable_out = HEADERS -wayland_client_header.output = $${WAYLAND_CLIENT_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} +wayland_client_header.output = wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} wayland_client_header.commands = $$QMAKE_WAYLAND_SCANNER client-header < ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:wayland_client_header.commands = @echo Wayland client header ${QMAKE_FILE_IN} && $$wayland_client_header.commands QMAKE_EXTRA_COMPILERS += wayland_client_header @@ -94,35 +43,35 @@ qtPrepareTool(QMAKE_QTWAYLANDSCANNER, qtwaylandscanner) qtwayland_client_header.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_client_header.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_header.variable_out = HEADERS -qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_CLIENT_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} -qtwayland_client_header.output = $${WAYLAND_CLIENT_HEADER_DEST}qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} $$WAYLAND_CLIENT_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} +qtwayland_client_header.output = qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:qtwayland_client_header.commands = @echo QtWayland client header ${QMAKE_FILE_IN} && $$qtwayland_client_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_header qtwayland_client_code.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_client_code.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_code.variable_out = SOURCES -qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_CLIENT_HEADER_DEST}qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_client_code.output = qwayland-${QMAKE_FILE_BASE}.cpp -qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} $$WAYLAND_CLIENT_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:qtwayland_client_code.commands = @echo QtWayland client code ${QMAKE_FILE_IN} && $$qtwayland_client_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_code qtwayland_server_header.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_header.variable_out = HEADERS -qtwayland_server_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_SERVER_HEADER_DEST}wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} -qtwayland_server_header.output = $${WAYLAND_SERVER_HEADER_DEST}qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} $$WAYLAND_SERVER_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_server_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} +qtwayland_server_header.output = qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:qtwayland_server_header.commands = @echo QtWayland server header ${QMAKE_FILE_IN} && $$qtwayland_server_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_header qtwayland_server_code.name = qtwayland ${QMAKE_FILE_BASE} qtwayland_server_code.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_code.variable_out = SOURCES -qtwayland_server_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE $${WAYLAND_SERVER_HEADER_DEST}qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} +qtwayland_server_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_server_code.output = qwayland-server-${QMAKE_FILE_BASE}.cpp -qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} $$WAYLAND_SERVER_INCLUDE_DIR > ${QMAKE_FILE_OUT} +qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} silent:qtwayland_server_code.commands = @echo QtWayland server code ${QMAKE_FILE_IN} && $$qtwayland_server_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_code From 6f53c2bc967641ef16d681e7cec0db200e4da244 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Tue, 26 Jun 2018 13:19:23 +0200 Subject: [PATCH 094/123] Doc: Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-69093 Change-Id: Ica63482251b2a614a17a996fac9bcc16b96c200f Reviewed-by: Topi Reiniö --- src/gui/kernel/qwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 9abe04810b3..55fe75d2204 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2861,7 +2861,7 @@ void QWindow::setVulkanInstance(QVulkanInstance *instance) } /*! - \return the associrated Vulkan instance or \c null if there is none. + \return the associated Vulkan instance or \c null if there is none. */ QVulkanInstance *QWindow::vulkanInstance() const { From a8a0dffd1f78d27c04cfd1e20563e9ddda4a135c Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 22 Jun 2018 10:05:23 +0200 Subject: [PATCH 095/123] Windows QPA/GL: Fix build with MinGW/g++ 8.1 x64 Fix warnings about invalid function type casts (return types conflicting with the PROC returned by wglGetProcAddress()) like: qwindowsglcontext.cpp:1250:138: error: cast between incompatible function types from 'PROC' {aka 'long long int (*)()'} to 'GLenum (*)()' {aka 'unsigned int (*)()'} [-Werror=cast-function-type] m_getGraphicsResetStatus = (GLenum (APIENTRY *)()) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"); by introducing nested casts. Task-number: QTBUG-68742 Task-number: QTQAINFRA-2095 Change-Id: I7c51836f2b9f7e2a6fa17c5108d59b23c42fb99d Reviewed-by: Ville Voutilainen --- .../platforms/windows/qwindowsglcontext.cpp | 40 ++++++++++++------- .../platforms/windows/qwindowsglcontext.h | 6 ++- .../windows/qwindowsopengltester.cpp | 28 ++++++++----- 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index e9c52e2c02b..cc8174051aa 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -153,9 +153,11 @@ QT_BEGIN_NAMESPACE QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; -FARPROC QWindowsOpengl32DLL::resolve(const char *name) +QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name) { - return m_lib ? ::GetProcAddress(m_lib, name) : nullptr; + return m_lib + ? reinterpret_cast(::GetProcAddress(m_lib, name)) + : nullptr; } bool QWindowsOpengl32DLL::init(bool softwareRendering) @@ -977,12 +979,18 @@ QOpenGLStaticContext::QOpenGLStaticContext() : extensionNames(QOpenGLStaticContext::getGlString(GL_EXTENSIONS)), extensions(0), defaultFormat(QWindowsOpenGLContextFormat::current()), - wglGetPixelFormatAttribIVARB((WglGetPixelFormatAttribIVARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")), - wglChoosePixelFormatARB((WglChoosePixelFormatARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")), - wglCreateContextAttribsARB((WglCreateContextAttribsARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")), - wglSwapInternalExt((WglSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")), - wglGetSwapInternalExt((WglGetSwapInternalExt)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")), - wglGetExtensionsStringARB((WglGetExtensionsStringARB)QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")) + wglGetPixelFormatAttribIVARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetPixelFormatAttribivARB")))), + wglChoosePixelFormatARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglChoosePixelFormatARB")))), + wglCreateContextAttribsARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglCreateContextAttribsARB")))), + wglSwapInternalExt(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglSwapIntervalEXT")))), + wglGetSwapInternalExt(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetSwapIntervalEXT")))), + wglGetExtensionsStringARB(reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("wglGetExtensionsStringARB")))) { if (extensionNames.startsWith(SAMPLE_BUFFER_EXTENSION " ") || extensionNames.indexOf(" " SAMPLE_BUFFER_EXTENSION " ") != -1) @@ -1231,7 +1239,8 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); } else { typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); - glGetStringi_t glGetStringi = (glGetStringi_t) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"); + glGetStringi_t glGetStringi = reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); if (glGetStringi) { GLint n = 0; QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n); @@ -1244,8 +1253,10 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) } } } - if (hasRobustness) - m_getGraphicsResetStatus = (GLenum (APIENTRY *)()) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"); + if (hasRobustness) { + m_getGraphicsResetStatus = reinterpret_cast( + reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"))); + } QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext); return true; @@ -1369,16 +1380,17 @@ QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName) // Even though we use QFunctionPointer, it does not mean the function can be called. // It will need to be cast to the proper function type with the correct calling // convention. QFunctionPointer is nothing more than a glorified void* here. - PROC procAddress = QOpenGLStaticContext::opengl32.wglGetProcAddress(procName); + QFunctionPointer procAddress = reinterpret_cast(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); // We support AllGLFunctionsQueryable, which means this function must be able to // return a function pointer even for functions that are in GL.h and exported // normally from opengl32.dll. wglGetProcAddress() is not guaranteed to work for such // functions, however in QT_OPENGL_DYNAMIC builds QOpenGLFunctions will just blindly // call into here for _any_ OpenGL function. - if (!procAddress || procAddress == reinterpret_cast(0x1) || procAddress == reinterpret_cast(0x2) - || procAddress == reinterpret_cast(0x3) || procAddress == reinterpret_cast(-1)) + if (procAddress == nullptr || reinterpret_cast(procAddress) < 4u + || procAddress == reinterpret_cast(-1)) { procAddress = QOpenGLStaticContext::opengl32.resolve(procName); + } if (QWindowsContext::verbose > 1) qCDebug(lcQpaGl) << __FUNCTION__ << procName << QOpenGLStaticContext::opengl32.wglGetCurrentContext() << "returns" << procAddress; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 2d5b94af0e4..87c3723c268 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -122,7 +122,7 @@ struct QWindowsOpengl32DLL void (APIENTRY * glGetIntegerv)(GLenum pname, GLint* params); const GLubyte * (APIENTRY * glGetString)(GLenum name); - FARPROC resolve(const char *name); + QFunctionPointer resolve(const char *name); private: HMODULE m_lib; bool m_nonOpengl32; @@ -217,6 +217,8 @@ public: void *nativeContext() const override { return m_renderingContext; } private: + typedef GLenum (APIENTRY *GlGetGraphicsResetStatusArbType)(); + inline void releaseDCs(); bool updateObtainedParams(HDC hdc, int *obtainedSwapInterval = 0); @@ -230,7 +232,7 @@ private: bool m_extensionsUsed; int m_swapInterval; bool m_ownsContext; - GLenum (APIENTRY * m_getGraphicsResetStatus)(); + GlGetGraphicsResetStatusArbType m_getGraphicsResetStatus; bool m_lost; }; #endif diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index a511cc61647..c52e4e612ef 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -283,16 +283,21 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::supportedRenderers() bool QWindowsOpenGLTester::testDesktopGL() { #if !defined(QT_NO_OPENGL) + typedef HGLRC (WINAPI *CreateContextType)(HDC); + typedef BOOL (WINAPI *DeleteContextType)(HGLRC); + typedef BOOL (WINAPI *MakeCurrentType)(HDC, HGLRC); + typedef PROC (WINAPI *WglGetProcAddressType)(LPCSTR); + HMODULE lib = 0; HWND wnd = 0; HDC dc = 0; HGLRC context = 0; LPCTSTR className = L"qtopengltest"; - HGLRC (WINAPI * CreateContext)(HDC dc) = 0; - BOOL (WINAPI * DeleteContext)(HGLRC context) = 0; - BOOL (WINAPI * MakeCurrent)(HDC dc, HGLRC context) = 0; - PROC (WINAPI * WGL_GetProcAddress)(LPCSTR name) = 0; + CreateContextType CreateContext = nullptr; + DeleteContextType DeleteContext = nullptr; + MakeCurrentType MakeCurrent = nullptr; + WglGetProcAddressType WGL_GetProcAddress = nullptr; bool result = false; @@ -300,16 +305,20 @@ bool QWindowsOpenGLTester::testDesktopGL() // This will typically fail on systems that do not have a real OpenGL driver. lib = LoadLibraryA("opengl32.dll"); if (lib) { - CreateContext = reinterpret_cast(::GetProcAddress(lib, "wglCreateContext")); + CreateContext = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglCreateContext"))); if (!CreateContext) goto cleanup; - DeleteContext = reinterpret_cast(::GetProcAddress(lib, "wglDeleteContext")); + DeleteContext = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglDeleteContext"))); if (!DeleteContext) goto cleanup; - MakeCurrent = reinterpret_cast(::GetProcAddress(lib, "wglMakeCurrent")); + MakeCurrent = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglMakeCurrent"))); if (!MakeCurrent) goto cleanup; - WGL_GetProcAddress = reinterpret_cast(::GetProcAddress(lib, "wglGetProcAddress")); + WGL_GetProcAddress = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "wglGetProcAddress"))); if (!WGL_GetProcAddress) goto cleanup; @@ -356,7 +365,8 @@ bool QWindowsOpenGLTester::testDesktopGL() // Check the version. If we got 1.x then it's all hopeless and we can stop right here. typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name); - GetString_t GetString = reinterpret_cast(::GetProcAddress(lib, "glGetString")); + GetString_t GetString = reinterpret_cast( + reinterpret_cast(::GetProcAddress(lib, "glGetString"))); if (GetString) { if (const char *versionStr = reinterpret_cast(GetString(GL_VERSION))) { const QByteArray version(versionStr); From da82bfd8230cf1e8b2719e6eca27df5a73dc0cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 26 Jun 2018 12:56:37 +0200 Subject: [PATCH 096/123] Android: tst_QTimeZone::transitionEachZone: skip 2 zones When testing zones "America/Mazatlan" and "Mexico/BajaSur" the test crashes from an assert. Skip testing the zones for now. Task-number: QTBUG-69132 Change-Id: I595089647792e9a2c094d63cb837584b8cdc9cb9 Reviewed-by: Jesus Fernandez --- tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp index 29efd8fb4ae..ed80d4528d4 100644 --- a/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp +++ b/tests/auto/corelib/tools/qtimezone/tst_qtimezone.cpp @@ -507,6 +507,10 @@ void tst_QTimeZone::transitionEachZone() && zone == "Europe/Samara" && i == -3) { continue; } +#endif +#ifdef Q_OS_ANDROID + if (zone == "America/Mazatlan" || zone == "Mexico/BajaSur") + QSKIP("Crashes on Android, see QTBUG-69132"); #endif qint64 here = secs + i * 3600; QDateTime when = QDateTime::fromMSecsSinceEpoch(here * 1000, named); From 3079b3433d770833949d998f96800ad4e7c63aea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 26 Jun 2018 12:26:39 +0200 Subject: [PATCH 097/123] Android: tst_qtimezone: Blacklist a bunch Task-number: QTBUG-69122 Task-number: QTBUG-69128 Task-number: QTBUG-69129 Task-number: QTBUG-69131 Change-Id: Ida626a6675764e9554785b5e56cfba3ab7206f17 Reviewed-by: Jesus Fernandez --- tests/auto/corelib/tools/qtimezone/BLACKLIST | 171 +++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 tests/auto/corelib/tools/qtimezone/BLACKLIST diff --git a/tests/auto/corelib/tools/qtimezone/BLACKLIST b/tests/auto/corelib/tools/qtimezone/BLACKLIST new file mode 100644 index 00000000000..840c3b11816 --- /dev/null +++ b/tests/auto/corelib/tools/qtimezone/BLACKLIST @@ -0,0 +1,171 @@ +# QTBUG-69122 +[dataStreamTest] +android + +# QTBUG-69128 +[isTimeZoneIdAvailable] +android + +# QTBUG-69129 +[specificTransition] +android + +# QTBUG-69131 +[transitionEachZone:America/Cancun@2010] +android +[transitionEachZone:America/Eirunepe@2010] +android +[transitionEachZone:America/Montevideo@2010] +android +[transitionEachZone:America/Porto_Acre@2010] +android +[transitionEachZone:America/Rio_Branco@2010] +android +[transitionEachZone:Asia/Anadyr@2010] +android +[transitionEachZone:Asia/Chita@2010] +android +[transitionEachZone:Asia/Kamchatka@2010] +android +[transitionEachZone:Asia/Khandyga@2010] +android +[transitionEachZone:Asia/Magadan@2010] +android +[transitionEachZone:Asia/Novokuznetsk@2010] +android +[transitionEachZone:Asia/Pyongyang@2010] +android +[transitionEachZone:Asia/Ust-Nera@2010] +android +[transitionEachZone:Asia/Yerevan@2010] +android +[transitionEachZone:Europe/Kaliningrad@2010] +android +[transitionEachZone:Europe/Minsk@2010] +android +[transitionEachZone:Europe/Moscow@2010] +android +[transitionEachZone:Europe/Samara@2010] +android +[transitionEachZone:Europe/Simferopol@2010] +android +[transitionEachZone:Europe/Volgograd@2010] +android +[transitionEachZone:W-SU@2010] +android +[transitionEachZone:Africa/Bissau@1970] +android +[transitionEachZone:Africa/Juba@1970] +android +[transitionEachZone:Africa/Khartoum@1970] +android +[transitionEachZone:America/Metlakatla@1970] +android +[transitionEachZone:America/Montevideo@1970] +android +[transitionEachZone:America/Paramaribo@1970] +android +[transitionEachZone:America/Santarem@1970] +android +[transitionEachZone:America/Santo_Domingo@1970] +android +[transitionEachZone:Asia/Anadyr@1970] +android +[transitionEachZone:Asia/Bahrain@1970] +android +[transitionEachZone:Asia/Chita@1970] +android +[transitionEachZone:Asia/Dushanbe@1970] +android +[transitionEachZone:Asia/Ho_Chi_Minh@1970] +android +[transitionEachZone:Asia/Kathmandu@1970] +android +[transitionEachZone:Asia/Katmandu@1970] +android +[transitionEachZone:Asia/Kuala_Lumpur@1970] +android +[transitionEachZone:Asia/Magadan@1970] +android +[transitionEachZone:Asia/Novosibirsk@1970] +android +[transitionEachZone:Asia/Pontianak@1970] +android +[transitionEachZone:Asia/Pyongyang@1970] +android +[transitionEachZone:Asia/Qatar@1970] +android +[transitionEachZone:Asia/Qyzylorda@1970] +android +[transitionEachZone:Asia/Saigon@1970] +android +[transitionEachZone:Asia/Sakhalin@1970] +android +[transitionEachZone:Asia/Singapore@1970] +android +[transitionEachZone:Asia/Tashkent@1970] +android +[transitionEachZone:Asia/Thimbu@1970] +android +[transitionEachZone:Asia/Thimphu@1970] +android +[transitionEachZone:Asia/Ust-Nera@1970] +android +[transitionEachZone:Atlantic/Cape_Verde@1970] +android +[transitionEachZone:Chile/EasterIsland@1970] +android +[transitionEachZone:Europe/Kaliningrad@1970] +android +[transitionEachZone:Pacific/Bougainville@1970] +android +[transitionEachZone:Pacific/Easter@1970] +android +[transitionEachZone:Pacific/Enderbury@1970] +android +[transitionEachZone:Pacific/Galapagos@1970] +android +[transitionEachZone:Pacific/Kiritimati@1970] +android +[transitionEachZone:Pacific/Kosrae@1970] +android +[transitionEachZone:Pacific/Kwajalein@1970] +android +[transitionEachZone:Pacific/Nauru@1970] +android +[transitionEachZone:Pacific/Niue@1970] +android +[transitionEachZone:Singapore@1970] +android +[transitionEachZone:Brazil/Acre@2010] +android +[transitionEachZone:Pacific/Bougainville@2010] +android +[transitionEachZone:Africa/Algiers@1970] +android +[transitionEachZone:Africa/Monrovia@1970] +android +[transitionEachZone:Kwajalein@1970] +android +[transitionEachZone:Indian/Chagos@1970] +android +[transitionEachZone:Europe/Volgograd@1970] +android +[transitionEachZone:Atlantic/Stanley@1970] +android +[transitionEachZone:Antarctica/Mawson@1970] +android +[transitionEachZone:America/Swift_Current@1970] +android +[transitionEachZone:America/Guyana@1970] +android +[transitionEachZone:America/Grand_Turk@1970] +android +[transitionEachZone:America/Dawson_Creek@1970] +android +[transitionEachZone:America/Cancun@1970] +android +[transitionEachZone:America/Caracas@1970] +android +[transitionEachZone:America/Danmarkshavn@1970] +android From 528a16b00e011261c60bc5c14849f54de33c0e4a Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 25 Jun 2018 15:35:40 +0200 Subject: [PATCH 098/123] QAbstractItemModelTester: add missing includes The code (in macros) uses these classes, so the header should ensure they are defined. Change-Id: Ic68fa5559b7c0481927b47775b9cb7da12be7979 Reviewed-by: Jesus Fernandez --- src/testlib/qabstractitemmodeltester.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/testlib/qabstractitemmodeltester.h b/src/testlib/qabstractitemmodeltester.h index 07bc170a7ab..757074c6ae4 100644 --- a/src/testlib/qabstractitemmodeltester.h +++ b/src/testlib/qabstractitemmodeltester.h @@ -42,6 +42,8 @@ #include #include +#include +#include #ifdef QT_GUI_LIB #include From e3a1b18bc3e213c318107b84b07543d945b48514 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 24 Apr 2018 13:41:28 +0200 Subject: [PATCH 099/123] ItemModels: search for the child index in 2 directions Previously, the search for the index of a child was done by searching forwards (minus 2) from the last search, and subsequently backwards when it wasn't found. This would cause quite some searching in models with lots of items, and where the child lay before the last search. We still assume that subsequent searches for children are "nearby" the previous search, but instead of first searching forwards and then backwards, do the search in both directions. Task-number: QTBUG-61368 Change-Id: Idb549c2d02840632cd658f906816ce911f3ff8bc Reviewed-by: David Faure --- src/gui/itemmodels/qstandarditemmodel_p.h | 36 ++++++++++++++++++----- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h index d3ff2787a59..4589a622235 100644 --- a/src/gui/itemmodels/qstandarditemmodel_p.h +++ b/src/gui/itemmodels/qstandarditemmodel_p.h @@ -114,7 +114,7 @@ public: rows(0), columns(0), q_ptr(0), - lastIndexOf(2) + lastIndexOf(-1) { } inline int childIndex(int row, int column) const { @@ -124,11 +124,33 @@ public: } return (row * columnCount()) + column; } - inline int childIndex(const QStandardItem *child) { - int start = qMax(0, lastIndexOf -2); - lastIndexOf = children.indexOf(const_cast(child), start); - if (lastIndexOf == -1 && start != 0) - lastIndexOf = children.lastIndexOf(const_cast(child), start); + inline int childIndex(const QStandardItem *child) const { + const int lastChild = children.size() - 1; + if (lastIndexOf == -1) + lastIndexOf = lastChild / 2; + // assuming the item is in the vicinity of the last search, iterate forwards and + // backwards through the children + int backwardIter = lastIndexOf - 1; + int forwardIter = lastIndexOf; + Q_FOREVER { + if (forwardIter <= lastChild) { + if (children.at(forwardIter) == child) { + lastIndexOf = forwardIter; + break; + } + ++forwardIter; + } else if (backwardIter < 0) { + lastIndexOf = -1; + break; + } + if (backwardIter >= 0) { + if (children.at(backwardIter) == child) { + lastIndexOf = backwardIter; + break; + } + --backwardIter; + } + } return lastIndexOf; } QPair position() const; @@ -170,7 +192,7 @@ public: QStandardItem *q_ptr; - int lastIndexOf; + mutable int lastIndexOf; }; class QStandardItemModelPrivate : public QAbstractItemModelPrivate From 74be42ca598c4f13486191c0b8c58bee3d1f1090 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 24 Apr 2018 17:06:49 +0200 Subject: [PATCH 100/123] ItemModels: Cache last-known child index Instead of caching the last index of a search for a child item, cache the index of the child in the child item. When the item model is not changed, the index is valid. Otherwise, the index can only change when items get inserted or removed before the child. So in that case, start searching in the vicinity of the previously known index. As an example: a selectAll() on the view will always hit the cached index, so no search is performed for any item in the model/view. Task-number: QTBUG-61368 Change-Id: I85d085299987237fae23451d9e8bbb6060464ef2 Reviewed-by: David Faure --- src/gui/itemmodels/qstandarditemmodel.cpp | 8 +++++++ src/gui/itemmodels/qstandarditemmodel_p.h | 28 ++++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp index f55e90c1537..235bc5bd7db 100644 --- a/src/gui/itemmodels/qstandarditemmodel.cpp +++ b/src/gui/itemmodels/qstandarditemmodel.cpp @@ -142,6 +142,8 @@ void QStandardItemPrivate::setChild(int row, int column, QStandardItem *item, oldItem->d_func()->setModel(0); delete oldItem; children.replace(index, item); + if (item) + item->d_func()->lastKnownIndex = index; if (model && emitChanged) emit model->layoutChanged(); @@ -475,6 +477,8 @@ bool QStandardItemPrivate::insertRows(int row, const QList &item item->d_func()->parent = q; int index = childIndex(i + row, 0); children.replace(index, item); + if (item) + item->d_func()->lastKnownIndex = index; } if (model) model->d_func()->rowsInserted(q, row, count); @@ -512,6 +516,8 @@ bool QStandardItemPrivate::insertRows(int row, int count, const QListd_func()->lastKnownIndex = index; ++index; } } @@ -558,6 +564,8 @@ bool QStandardItemPrivate::insertColumns(int column, int count, const QListd_func()->lastKnownIndex = index; } } if (model) diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h index 4589a622235..00e83f7b085 100644 --- a/src/gui/itemmodels/qstandarditemmodel_p.h +++ b/src/gui/itemmodels/qstandarditemmodel_p.h @@ -114,7 +114,7 @@ public: rows(0), columns(0), q_ptr(0), - lastIndexOf(-1) + lastKnownIndex(-1) { } inline int childIndex(int row, int column) const { @@ -126,32 +126,38 @@ public: } inline int childIndex(const QStandardItem *child) const { const int lastChild = children.size() - 1; - if (lastIndexOf == -1) - lastIndexOf = lastChild / 2; - // assuming the item is in the vicinity of the last search, iterate forwards and + int &childsLastIndexInParent = child->d_func()->lastKnownIndex; + if (childsLastIndexInParent != -1 && childsLastIndexInParent <= lastChild) { + if (children.at(childsLastIndexInParent) == child) + return childsLastIndexInParent; + } else { + childsLastIndexInParent = lastChild / 2; + } + + // assuming the item is in the vicinity of the previous index, iterate forwards and // backwards through the children - int backwardIter = lastIndexOf - 1; - int forwardIter = lastIndexOf; + int backwardIter = childsLastIndexInParent - 1; + int forwardIter = childsLastIndexInParent; Q_FOREVER { if (forwardIter <= lastChild) { if (children.at(forwardIter) == child) { - lastIndexOf = forwardIter; + childsLastIndexInParent = forwardIter; break; } ++forwardIter; } else if (backwardIter < 0) { - lastIndexOf = -1; + childsLastIndexInParent = -1; break; } if (backwardIter >= 0) { if (children.at(backwardIter) == child) { - lastIndexOf = backwardIter; + childsLastIndexInParent = backwardIter; break; } --backwardIter; } } - return lastIndexOf; + return childsLastIndexInParent; } QPair position() const; void setChild(int row, int column, QStandardItem *item, @@ -192,7 +198,7 @@ public: QStandardItem *q_ptr; - mutable int lastIndexOf; + mutable int lastKnownIndex; // this is a cached value }; class QStandardItemModelPrivate : public QAbstractItemModelPrivate From 27ea5a65dd3fdabdad1569f5330f90248cdca4f5 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 25 Jun 2018 15:50:35 +0200 Subject: [PATCH 101/123] QAbstractItemModelTester: fix out-of-bounds index() calls When removing rows, the tester is looking at the data of the row "just before" and the row "just after" the removed rows, to see if they are still the same at the end of the removal operation. Guard this with bounds check, in case there is no row just before or just after. This is the opportunity to use modeltester in tst_qidentityproxymodel, which was already a testcase for removing the only row in a given parent. Change-Id: Iec8228c16b9c670b794e2665356d153679178494 Reviewed-by: Giuseppe D'Angelo --- src/testlib/qabstractitemmodeltester.cpp | 19 +++++++++++++++---- .../tst_qidentityproxymodel.cpp | 12 +++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp index e970be2c8da..04fa99bc4d9 100644 --- a/src/testlib/qabstractitemmodeltester.cpp +++ b/src/testlib/qabstractitemmodeltester.cpp @@ -712,8 +712,17 @@ void QAbstractItemModelTesterPrivate::rowsAboutToBeRemoved(const QModelIndex &pa Changing c; c.parent = parent; c.oldSize = model->rowCount(parent); - c.last = model->data(model->index(start - 1, 0, parent)); - c.next = model->data(model->index(end + 1, 0, parent)); + if (start > 0) { + const QModelIndex startIndex = model->index(start - 1, 0, parent); + MODELTESTER_VERIFY(startIndex.isValid()); + c.last = model->data(startIndex); + } + if (end < c.oldSize - 1) { + const QModelIndex endIndex = model->index(end + 1, 0, parent); + MODELTESTER_VERIFY(endIndex.isValid()); + c.next = model->data(endIndex); + } + remove.push(c); } @@ -732,8 +741,10 @@ void QAbstractItemModelTesterPrivate::rowsRemoved(const QModelIndex &parent, int Changing c = remove.pop(); MODELTESTER_COMPARE(parent, c.parent); MODELTESTER_COMPARE(model->rowCount(parent), c.oldSize - (end - start + 1)); - MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last); - MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next); + if (start > 0) + MODELTESTER_COMPARE(model->data(model->index(start - 1, 0, c.parent)), c.last); + if (end < c.oldSize - 1) + MODELTESTER_COMPARE(model->data(model->index(start, 0, c.parent)), c.next); } void QAbstractItemModelTesterPrivate::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) diff --git a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp index f8c5c926771..262c6dd9c88 100644 --- a/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -26,9 +26,12 @@ ** ****************************************************************************/ -#include -#include -#include +#include +#include +#include +#include +#include +#include #include "dynamictreemodel.h" #include "qidentityproxymodel.h" @@ -76,6 +79,7 @@ protected: private: QStandardItemModel *m_model; QIdentityProxyModel *m_proxy; + QAbstractItemModelTester *m_modelTest; }; tst_QIdentityProxyModel::tst_QIdentityProxyModel() @@ -88,12 +92,14 @@ void tst_QIdentityProxyModel::initTestCase() qRegisterMetaType >(); m_model = new QStandardItemModel(0, 1); m_proxy = new QIdentityProxyModel(); + m_modelTest = new QAbstractItemModelTester(m_proxy, this); } void tst_QIdentityProxyModel::cleanupTestCase() { delete m_proxy; delete m_model; + delete m_modelTest; } void tst_QIdentityProxyModel::cleanup() From 4af292fe5158c2d19e8ab1351c71c3940c7f1032 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 25 Jun 2018 16:26:46 +0200 Subject: [PATCH 102/123] QAbstractItemModelTester: don't call match(QModelIndex(), ...) The documentation for match() indicates that the index has to be valid since it determines which column to search in (in addition to "from which row"). So call match with a valid index, if the model isn't empty. Change-Id: I5f3754cf14d053bf04d207cefe7dcc938e0f4a5a Reviewed-by: Giuseppe D'Angelo --- src/testlib/qabstractitemmodeltester.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/testlib/qabstractitemmodeltester.cpp b/src/testlib/qabstractitemmodeltester.cpp index 04fa99bc4d9..fc6f696ecd2 100644 --- a/src/testlib/qabstractitemmodeltester.cpp +++ b/src/testlib/qabstractitemmodeltester.cpp @@ -322,9 +322,10 @@ void QAbstractItemModelTesterPrivate::nonDestructiveBasicTest() Qt::ItemFlags flags = model->flags(QModelIndex()); MODELTESTER_VERIFY(flags == Qt::ItemIsDropEnabled || flags == 0); model->hasChildren(QModelIndex()); - model->hasIndex(0, 0); + const bool hasRow = model->hasIndex(0, 0); QVariant cache; - model->match(QModelIndex(), -1, cache); + if (hasRow) + model->match(model->index(0, 0), -1, cache); model->mimeTypes(); MODELTESTER_VERIFY(!model->parent(QModelIndex()).isValid()); MODELTESTER_VERIFY(model->rowCount() >= 0); From 4d73ab73c81fff83e4423f0d3c918781587f14bf Mon Sep 17 00:00:00 2001 From: Alexander Volkov Date: Mon, 23 Apr 2018 14:10:01 +0300 Subject: [PATCH 103/123] Return a correct filter from QFileDialog::selectedMimeTypeFilter() QFileDialog::selectedMimeTypeFilter() returns either an empty filter in the case when a platform file dialog doesn't implement mime type filters, or initiallySelectedMimeTypeFilter() in the case of Qt's file dialog. In both cases the result is incorrect. Make it return a mime type filter corresponding to a selected name filter. As a result, tst_QFiledialog::setMimeTypeFilters() has to be fixed: QFileDialog::selectMimeTypeFilter() can't select a name filter for an invalid mime type, and "application/json" is not supported by RHEL 6.6, so replace it by "application/pdf". Change-Id: I58d3be860a9b5e8a72cba86d74b520178115a812 Reviewed-by: David Faure --- src/widgets/dialogs/qfiledialog.cpp | 43 +++++++++++++------ .../dialogs/qfiledialog/tst_qfiledialog.cpp | 10 +++-- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 5d8ca458c29..ecd2ab67762 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -1462,19 +1462,6 @@ void QFileDialog::selectNameFilter(const QString &filter) } } -/*! - * \since 5.9 - * \return The mimetype of the file that the user selected in the file dialog. - */ -QString QFileDialog::selectedMimeTypeFilter() const -{ - Q_D(const QFileDialog); - if (!d->usingWidgets()) - return d->selectedMimeTypeFilter_sys(); - - return d->options->initiallySelectedMimeTypeFilter(); -} - /*! \since 4.4 @@ -1611,6 +1598,36 @@ void QFileDialog::selectMimeTypeFilter(const QString &filter) #endif // QT_NO_MIMETYPE +/*! + * \since 5.9 + * \return The mimetype of the file that the user selected in the file dialog. + */ +QString QFileDialog::selectedMimeTypeFilter() const +{ + Q_D(const QFileDialog); + QString mimeTypeFilter; + if (!d->usingWidgets()) + mimeTypeFilter = d->selectedMimeTypeFilter_sys(); + +#ifndef QT_NO_MIMETYPE + if (mimeTypeFilter.isNull() && !d->options->mimeTypeFilters().isEmpty()) { + const auto nameFilter = selectedNameFilter(); + const auto mimeTypes = d->options->mimeTypeFilters(); + for (const auto &mimeType: mimeTypes) { + QString filter = nameFilterForMime(mimeType); + if (testOption(HideNameFilterDetails)) + filter = qt_strip_filters({ filter }).first(); + if (filter == nameFilter) { + mimeTypeFilter = mimeType; + break; + } + } + } +#endif + + return mimeTypeFilter; +} + /*! \property QFileDialog::viewMode \brief the way files and directories are displayed in the dialog diff --git a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp index c3bdf3701f6..47d63b7d536 100644 --- a/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp +++ b/tests/auto/widgets/dialogs/qfiledialog/tst_qfiledialog.cpp @@ -1049,12 +1049,12 @@ void tst_QFiledialog::setMimeTypeFilters_data() QTest::addColumn("expectedSelectedMimeTypeFilter"); const auto headerMime = QStringLiteral("text/x-chdr"); - const auto jsonMime = QStringLiteral("application/json"); + const auto pdfMime = QStringLiteral("application/pdf"); const auto zipMime = QStringLiteral("application/zip"); QTest::newRow("single mime filter (C header file)") << QStringList {headerMime} << headerMime << headerMime; - QTest::newRow("single mime filter (JSON file)") << QStringList {jsonMime} << jsonMime << jsonMime; - QTest::newRow("multiple mime filters") << QStringList {jsonMime, zipMime} << jsonMime << jsonMime; + QTest::newRow("single mime filter (JSON file)") << QStringList {pdfMime} << pdfMime << pdfMime; + QTest::newRow("multiple mime filters") << QStringList {pdfMime, zipMime} << pdfMime << pdfMime; } void tst_QFiledialog::setMimeTypeFilters() @@ -1068,6 +1068,10 @@ void tst_QFiledialog::setMimeTypeFilters() fd.selectMimeTypeFilter(targetMimeTypeFilter); QCOMPARE(fd.selectedMimeTypeFilter(), expectedSelectedMimeTypeFilter); + + auto *filters = fd.findChild("fileTypeCombo"); + filters->setCurrentIndex(filters->count() - 1); + QCOMPARE(fd.selectedMimeTypeFilter(), mimeTypeFilters.last()); } void tst_QFiledialog::setEmptyNameFilter() From 9050ce4ff569de97dbcdc837044d0cc3f7e01e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 27 Jun 2018 16:59:57 +0200 Subject: [PATCH 104/123] macOS: Guard non-reentrant uses of NSOpenGLContext NSOpenGLContext should be re-entrant, but is not in practice, resulting in deadlocks when there are two render threads, eg: thread #23, name = 'QSGRenderThread' frame #0: 0x00007fff5c6dda4e libsystem_kernel.dylib`__psynch_mutexwait + 10 frame #1: 0x00007fff5c8a5b9d libsystem_pthread.dylib`_pthread_mutex_lock_wait + 83 frame #2: 0x00007fff5c8a34c8 libsystem_pthread.dylib`_pthread_mutex_lock_slow + 253 frame #3: 0x00007fff31ebb52e AppKit`flush_notify + 110 frame #4: 0x00007fff3e75ee2a GLEngine`glSwap_Exec + 186 frame #5: 0x00007fff3e740797 OpenGL`CGLFlushDrawable + 59 frame #6: 0x00007fff31ad43ac AppKit`-[NSOpenGLContext flushBuffer] + 27 ... Task-number: QTBUG-69040 Change-Id: I6f28b4cc5faf61ae93f66353ce2abdf8c223d994 Reviewed-by: Simon Hausmann --- src/plugins/platforms/cocoa/qcocoaglcontext.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index b656025ec7e..7ffe0003d33 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -117,6 +117,9 @@ static void updateFormatFromContext(QSurfaceFormat *format) format->setProfile(QSurfaceFormat::CompatibilityProfile); } + // NSOpenGLContext is not re-entrant (https://openradar.appspot.com/37064579) +static QMutex s_contextMutex; + QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle) : m_context(nil), @@ -248,6 +251,7 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) QWindow *window = static_cast(surface)->window(); setActiveWindow(window); + QMutexLocker locker(&s_contextMutex); [m_context flushBuffer]; } @@ -400,6 +404,7 @@ QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName) void QCocoaGLContext::update() { + QMutexLocker locker(&s_contextMutex); [m_context update]; } From 9fde78269526925a764e45370ffcae509e5db8e9 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 25 Jun 2018 15:58:42 +0200 Subject: [PATCH 105/123] configure: permit digits in variable assignments on the cmdline Change-Id: I21e4f93b119d28fe30cb2436c76a03b67c78fe7a Reviewed-by: Rainer Keller Reviewed-by: Maurice Kalinowski --- mkspecs/features/qt_configure.prf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index 1211129283b..c4ddda5b1f0 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -158,7 +158,7 @@ defineTest(qtConfCommandline_optionalString) { nextok = $${3} isEmpty(val) { $$nextok: val = $$qtConfPeekNextCommandlineArg() - contains(val, "^-.*|[A-Z_]+=.*")|isEmpty(val): \ + contains(val, "^-.*|[A-Z0-9_]+=.*")|isEmpty(val): \ val = "yes" else: \ val = $$qtConfGetNextCommandlineArg() @@ -233,9 +233,9 @@ defineTest(qtConfParseCommandLine) { $$didCustomCall: \ next() - contains(c, "([A-Z_]+)=(.*)") { - opt = $$replace(c, "^([A-Z_]+)=(.*)", "\\1") - val = $$replace(c, "^([A-Z_]+)=(.*)", "\\2") + contains(c, "([A-Z0-9_]+)=(.*)") { + opt = $$replace(c, "^([A-Z0-9_]+)=(.*)", "\\1") + val = $$replace(c, "^([A-Z0-9_]+)=(.*)", "\\2") for (cc, allConfigs) { var = $$eval($${cc}.commandline.assignments.$${opt}) !isEmpty(var): \ From 79955402924ea21b564cc5eadb624eaa60bdaa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 26 Jun 2018 15:50:28 +0200 Subject: [PATCH 106/123] tst_qthreadpool: Skip "stackSize" if unsupported If you're on a Unix platform which don't have the necessary defines then the thread will never be launched due to an error. Skip the test instead. Change-Id: I83159988b8f330a750c7aa328a8805e4fa478070 Reviewed-by: Eskil Abrahamsen Blomfeldt --- tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp index 1092216fb7b..838431cd5a9 100644 --- a/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp +++ b/tests/auto/corelib/thread/qthreadpool/tst_qthreadpool.cpp @@ -32,6 +32,10 @@ #include #include +#ifdef Q_OS_UNIX +#include +#endif + typedef void (*FunctionPointer)(); class FunctionPointerTask : public QRunnable @@ -1145,6 +1149,10 @@ void tst_QThreadPool::destroyingWaitsForTasksToFinish() // stack size used by the native thread. void tst_QThreadPool::stackSize() { +#if defined(Q_OS_UNIX) && !(defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)) + QSKIP("Setting stack size is unsupported on this platform."); +#endif + uint targetStackSize = 512 * 1024; uint threadStackSize = 1; // impossible value From 9f1568d18c36186c239138306442de2508c79bc0 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Wed, 27 Jun 2018 12:21:32 +0200 Subject: [PATCH 107/123] Fix QtWayland non-toplevel in-source builds Tell qtwaylandscanner to export the symbols when we're building a module. This is done by specifying the include directory on the qtwaylandscanner command line. Task-number: QTBUG-68773 Change-Id: Ib575222261831ab01eb43e6c7caefb07e314492b Reviewed-by: Johan Helsing Reviewed-by: Liang Qi Reviewed-by: Oswald Buddenhagen --- mkspecs/features/wayland-scanner.prf | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mkspecs/features/wayland-scanner.prf b/mkspecs/features/wayland-scanner.prf index f1e78b0914f..2360917a3b1 100644 --- a/mkspecs/features/wayland-scanner.prf +++ b/mkspecs/features/wayland-scanner.prf @@ -14,6 +14,10 @@ isEmpty(QMAKE_WAYLAND_SCANNER):error("QMAKE_WAYLAND_SCANNER not defined for this mkspec") +!isEmpty(MODULE_INCNAME) { + WAYLAND_INCLUDE_DIR = $$MODULE_INCNAME/private +} + wayland_server_header.name = wayland ${QMAKE_FILE_BASE} wayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM wayland_server_header.variable_out = HEADERS @@ -45,7 +49,7 @@ qtwayland_client_header.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_header.variable_out = HEADERS qtwayland_client_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-client-protocol$${first(QMAKE_EXT_H)} qtwayland_client_header.output = qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +qtwayland_client_header.commands = $$QMAKE_QTWAYLANDSCANNER client-header ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_client_header.commands = @echo QtWayland client header ${QMAKE_FILE_IN} && $$qtwayland_client_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_header @@ -54,7 +58,7 @@ qtwayland_client_code.input = WAYLANDCLIENTSOURCES WAYLANDCLIENTSOURCES_SYSTEM qtwayland_client_code.variable_out = SOURCES qtwayland_client_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_client_code.output = qwayland-${QMAKE_FILE_BASE}.cpp -qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +qtwayland_client_code.commands = $$QMAKE_QTWAYLANDSCANNER client-code ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_client_code.commands = @echo QtWayland client code ${QMAKE_FILE_IN} && $$qtwayland_client_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_client_code @@ -63,7 +67,7 @@ qtwayland_server_header.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_header.variable_out = HEADERS qtwayland_server_header.depends += $$QMAKE_QTWAYLANDSCANNER_EXE wayland-${QMAKE_FILE_BASE}-server-protocol$${first(QMAKE_EXT_H)} qtwayland_server_header.output = qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} -qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +qtwayland_server_header.commands = $$QMAKE_QTWAYLANDSCANNER server-header ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_server_header.commands = @echo QtWayland server header ${QMAKE_FILE_IN} && $$qtwayland_server_header.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_header @@ -72,6 +76,6 @@ qtwayland_server_code.input = WAYLANDSERVERSOURCES WAYLANDSERVERSOURCES_SYSTEM qtwayland_server_code.variable_out = SOURCES qtwayland_server_code.depends += $$QMAKE_QTWAYLANDSCANNER_EXE qwayland-server-${QMAKE_FILE_BASE}$${first(QMAKE_EXT_H)} qtwayland_server_code.output = qwayland-server-${QMAKE_FILE_BASE}.cpp -qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} > ${QMAKE_FILE_OUT} +qtwayland_server_code.commands = $$QMAKE_QTWAYLANDSCANNER server-code ${QMAKE_FILE_IN} $$WAYLAND_INCLUDE_DIR > ${QMAKE_FILE_OUT} silent:qtwayland_server_code.commands = @echo QtWayland server code ${QMAKE_FILE_IN} && $$qtwayland_server_code.commands QMAKE_EXTRA_COMPILERS += qtwayland_server_code From 8a73085a0dc1bdb6d25ac4afcd5429018b55b967 Mon Sep 17 00:00:00 2001 From: David Faure Date: Mon, 25 Jun 2018 17:55:54 +0200 Subject: [PATCH 108/123] QSortFilterProxyModel unittest: add test for filtered-out-after-setData MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The row names for this test were very unspecific. After reverse-engineering what they are testing, I gave them proper descriptive names, which allowed me to notice that there were tests for "filtered in after sourceModel->setData" but not for "filtered out after sourceModel->setData". Change-Id: Ib79108db803ae77fb65d29cf0c0ef96c26655980 Reviewed-by: Christian Ehrlicher Reviewed-by: Thorbjørn Lund Martsum --- .../tst_qsortfilterproxymodel.cpp | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 296442b0c7e..a7ab1e20d9e 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -1894,6 +1894,7 @@ void tst_QSortFilterProxyModel::changeSourceData_data() QTest::addColumn("sourceItems"); QTest::addColumn("sortOrder"); QTest::addColumn("filter"); + QTest::addColumn("expectedInitialProxyItems"); QTest::addColumn("dynamic"); QTest::addColumn("row"); QTest::addColumn("newValue"); @@ -1901,10 +1902,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() QTest::addColumn("insertIntervals"); QTest::addColumn("proxyItems"); - QTest::newRow("changeSourceData (1)") + QTest::newRow("move_to_end_ascending") << (QStringList() << "c" << "b" << "a") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "" // filter + << (QStringList() << "a" << "b" << "c") // expectedInitialProxyItems << true // dynamic << 2 // row << "z" // newValue @@ -1913,10 +1915,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "b" << "c" << "z") // proxyItems ; - QTest::newRow("changeSourceData (2)") + QTest::newRow("move_to_end_descending") << (QStringList() << "b" << "c" << "z") // sourceItems << static_cast(Qt::DescendingOrder) // sortOrder << "" // filter + << (QStringList() << "z" << "c" << "b") // expectedInitialProxyItems << true // dynamic << 1 // row << "a" // newValue @@ -1925,10 +1928,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "z" << "b" << "a") // proxyItems ; - QTest::newRow("changeSourceData (3)") + QTest::newRow("no_op_change") << (QStringList() << "a" << "b") // sourceItems << static_cast(Qt::DescendingOrder) // sortOrder << "" // filter + << (QStringList() << "b" << "a") // expectedInitialProxyItems << true // dynamic << 0 // row << "a" // newValue @@ -1937,10 +1941,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "b" << "a") // proxyItems ; - QTest::newRow("changeSourceData (4)") + QTest::newRow("filtered_out_value_stays_out") << (QStringList() << "a" << "b" << "c" << "d") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "a|c" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems << true // dynamic << 1 // row << "x" // newValue @@ -1949,10 +1954,11 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "a" << "c") // proxyItems ; - QTest::newRow("changeSourceData (5)") + QTest::newRow("filtered_out_now_matches") << (QStringList() << "a" << "b" << "c" << "d") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "a|c|x" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems << true // dynamic << 1 // row << "x" // newValue @@ -1961,10 +1967,24 @@ void tst_QSortFilterProxyModel::changeSourceData_data() << (QStringList() << "a" << "c" << "x") // proxyItems ; - QTest::newRow("changeSourceData (6)") + QTest::newRow("value_is_now_filtered_out") + << (QStringList() << "a" << "b" << "c" << "d") // sourceItems + << static_cast(Qt::AscendingOrder) // sortOrder + << "a|c" // filter + << (QStringList() << "a" << "c") // expectedInitialProxyItems + << true // dynamic + << 2 // row + << "x" // newValue + << (IntPairList() << IntPair(1, 1)) // removeIntervals + << IntPairList() // insertIntervals + << (QStringList() << "a") // proxyItems + ; + + QTest::newRow("non_dynamic_filter_does_not_update_sort") << (QStringList() << "c" << "b" << "a") // sourceItems << static_cast(Qt::AscendingOrder) // sortOrder << "" // filter + << (QStringList() << "a" << "b" << "c") // expectedInitialProxyItems << false // dynamic << 2 // row << "x" // newValue @@ -1979,6 +1999,7 @@ void tst_QSortFilterProxyModel::changeSourceData() QFETCH(QStringList, sourceItems); QFETCH(int, sortOrder); QFETCH(QString, filter); + QFETCH(QStringList, expectedInitialProxyItems); QFETCH(bool, dynamic); QFETCH(int, row); QFETCH(QString, newValue); @@ -2004,6 +2025,12 @@ void tst_QSortFilterProxyModel::changeSourceData() proxy.setFilterRegExp(filter); + QCOMPARE(proxy.rowCount(), expectedInitialProxyItems.count()); + for (int i = 0; i < expectedInitialProxyItems.count(); ++i) { + const QModelIndex index = proxy.index(i, 0, QModelIndex()); + QCOMPARE(proxy.data(index, Qt::DisplayRole).toString(), expectedInitialProxyItems.at(i)); + } + QSignalSpy removeSpy(&proxy, &QSortFilterProxyModel::rowsRemoved); QSignalSpy insertSpy(&proxy, &QSortFilterProxyModel::rowsInserted); From 6ee26c543ef0d74110c296c73384e1461aa017da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 26 Jun 2018 16:50:50 +0200 Subject: [PATCH 109/123] Android: Pass tst_QUuid Same issue as has been seen a few other places: path to executable being wrong, and then a crash when the paths are fixed. Change-Id: I77a596c6e52d2a02a69a6b9dfe91f878b3ffe07c Reviewed-by: Thiago Macieira --- tests/auto/corelib/plugin/quuid/tst_quuid.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp index bad72c081b0..16552059dd5 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp @@ -94,7 +94,11 @@ void tst_QUuid::initTestCase() #if QT_CONFIG(process) // chdir to the directory containing our testdata, then refer to it with relative paths +#ifdef Q_OS_ANDROID + QString testdata_dir = QCoreApplication::applicationDirPath(); +#else // !Q_OS_ANDROID QString testdata_dir = QFileInfo(QFINDTESTDATA("testProcessUniqueness")).absolutePath(); +#endif QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir)); #endif @@ -401,6 +405,9 @@ void tst_QUuid::processUniqueness() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif QProcess process; QString processOneOutput; QString processTwoOutput; @@ -408,6 +415,8 @@ void tst_QUuid::processUniqueness() // Start it once #ifdef Q_OS_MAC process.start("testProcessUniqueness/testProcessUniqueness.app"); +#elif defined(Q_OS_ANDROID) + process.start("libtestProcessUniqueness.so"); #else process.start("testProcessUniqueness/testProcessUniqueness"); #endif @@ -417,6 +426,8 @@ void tst_QUuid::processUniqueness() // Start it twice #ifdef Q_OS_MAC process.start("testProcessUniqueness/testProcessUniqueness.app"); +#elif defined(Q_OS_ANDROID) + process.start("libtestProcessUniqueness.so"); #else process.start("testProcessUniqueness/testProcessUniqueness"); #endif From 568ee7da5ad603c65704c33cfea9526d61fb4c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Mon, 25 Jun 2018 16:45:39 +0200 Subject: [PATCH 110/123] Android: Pass tst_qlocale To make it run we make sure it finds the syslocaleapp, however since it causes a crash we skip the test that uses it... "formatTimeZone" was failing, but it is the exact same issue as in e08ba34f26197fb9893fd48a38bdd0dfff7d4a60, so we solve it the exact same way. Change-Id: Ifd5c796735775dad94acf55210cf18c0f4d375ca Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../corelib/tools/qlocale/tst_qlocale.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 375cecd5213..884cff553cd 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -168,14 +168,18 @@ tst_QLocale::tst_QLocale() void tst_QLocale::initTestCase() { #if QT_CONFIG(process) +# ifdef Q_OS_ANDROID + m_sysapp = QCoreApplication::applicationDirPath() + "/libsyslocaleapp.so"; +# else // !defined(Q_OS_ANDROID) const QString syslocaleapp_dir = QFINDTESTDATA("syslocaleapp"); QVERIFY2(!syslocaleapp_dir.isEmpty(), qPrintable(QStringLiteral("Cannot find 'syslocaleapp' starting from ") + QDir::toNativeSeparators(QDir::currentPath()))); m_sysapp = syslocaleapp_dir + QStringLiteral("/syslocaleapp"); -#ifdef Q_OS_WIN +# ifdef Q_OS_WIN m_sysapp += QStringLiteral(".exe"); -#endif +# endif +# endif // Q_OS_ANDROID const QFileInfo fi(m_sysapp); QVERIFY2(fi.exists() && fi.isExecutable(), qPrintable(QDir::toNativeSeparators(m_sysapp) @@ -502,6 +506,9 @@ void tst_QLocale::emptyCtor() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif #define TEST_CTOR(req_lc, exp_str) \ { \ /* Test constructor without arguments. Needs separate process */ \ @@ -1542,17 +1549,25 @@ void tst_QLocale::formatTimeZone() QSKIP("You must test using Central European (CET/CEST) time zone, e.g. TZ=Europe/Oslo"); } +#ifdef Q_OS_ANDROID // Only reports (general) zones as offsets (QTBUG-68837) + const QString cet(QStringLiteral("GMT+01:00")); + const QString cest(QStringLiteral("GMT+02:00")); +#else + const QString cet(QStringLiteral("CET")); + const QString cest(QStringLiteral("CEST")); +#endif + QDateTime dt6(QDate(2013, 1, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); #endif - QCOMPARE(enUS.toString(dt6, "t"), QLatin1String("CET")); + QCOMPARE(enUS.toString(dt6, "t"), cet); QDateTime dt7(QDate(2013, 6, 1), QTime(0, 0, 0), QTimeZone("Europe/Berlin")); #ifdef Q_OS_WIN QEXPECT_FAIL("", "QTimeZone windows backend only returns long name", Continue); #endif - QCOMPARE(enUS.toString(dt7, "t"), QLatin1String("CEST")); + QCOMPARE(enUS.toString(dt7, "t"), cest); // Current datetime should return current abbreviation QCOMPARE(enUS.toString(QDateTime::currentDateTime(), "t"), From d420987d54342e6933251e7db1012b8df8a83384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 5 Jun 2018 15:54:07 +0200 Subject: [PATCH 111/123] Android: fix tst_qlogging The "app" subfolder was already excluded in the .pro-file but Android supports QProcess, so lets include it in the build. Unfortunately it currently has trouble and crashes (the child process or both processes). So we skip those tests. Task-number: QTBUG-68596 Change-Id: I2e6d0869c408bf08b22c02145db8ce522c64c617 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../auto/corelib/global/qlogging/qlogging.pro | 2 +- .../corelib/global/qlogging/tst_qlogging.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/auto/corelib/global/qlogging/qlogging.pro b/tests/auto/corelib/global/qlogging/qlogging.pro index 3f7c0a4074d..bbe75297d51 100644 --- a/tests/auto/corelib/global/qlogging/qlogging.pro +++ b/tests/auto/corelib/global/qlogging/qlogging.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -!android:!winrt { +!winrt { test.depends = app SUBDIRS += app } diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 3465385ba7a..e7a3748c300 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -101,7 +101,11 @@ tst_qmessagehandler::tst_qmessagehandler() void tst_qmessagehandler::initTestCase() { #if QT_CONFIG(process) +# ifdef Q_OS_ANDROID + m_appDir = QCoreApplication::applicationDirPath(); +# else // !android m_appDir = QFINDTESTDATA("app"); +# endif QVERIFY2(!m_appDir.isEmpty(), qPrintable( QString::fromLatin1("Couldn't find helper app dir starting from %1.").arg(QDir::currentPath()))); @@ -818,12 +822,19 @@ void tst_qmessagehandler::qMessagePattern() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif QFETCH(QString, pattern); QFETCH(bool, valid); QFETCH(QList, expected); QProcess process; +#ifdef Q_OS_ANDROID + const QString appExe = m_appDir + "/libapp.so"; +#else // !android const QString appExe = m_appDir + "/app"; +#endif // // test QT_MESSAGE_PATTERN @@ -860,13 +871,20 @@ void tst_qmessagehandler::setMessagePattern() #if !QT_CONFIG(process) QSKIP("This test requires QProcess support"); #else +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android"); +#endif // // test qSetMessagePattern // QProcess process; +#ifdef Q_OS_ANDROID + const QString appExe = m_appDir + "/libapp.so"; +#else // !android const QString appExe = m_appDir + "/app"; +#endif // make sure there is no QT_MESSAGE_PATTERN in the environment QStringList environment = m_baseEnvironment; From 8757e6fee11fbd72c1a3ade1aea0800f63b966ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 6 Jun 2018 16:13:48 +0200 Subject: [PATCH 112/123] Android: Make tst_qfile pass By disabling the "stdinprocess"-related tests/code... ... but differently. After fixing my earlier mistakes I'm getting segmentation faults when it executes a couple different library calls after the QProcess object has started. Task-number: QTBUG-68596 Change-Id: Id42a1f939c000754a187dee90c4a4cdfec816232 Reviewed-by: Frederik Gladhorn Reviewed-by: Eskil Abrahamsen Blomfeldt --- tests/auto/corelib/io/qfile/tst_qfile.cpp | 25 ++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index c2029238987..66652005854 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -379,6 +379,12 @@ private: QString m_noEndOfLineFile; }; +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) + #define STDINPROCESS_NAME "libstdinprocess.so" +#else // !android || android_embedded + #define STDINPROCESS_NAME "stdinprocess" +#endif // android && !android_embededd + static const char noReadFile[] = "noreadfile"; static const char readOnlyFile[] = "readonlyfile"; @@ -448,7 +454,11 @@ void tst_QFile::initTestCase() { QVERIFY2(m_temporaryDir.isValid(), qPrintable(m_temporaryDir.errorString())); #if QT_CONFIG(process) +#if defined(Q_OS_ANDROID) + m_stdinProcessDir = QCoreApplication::applicationDirPath(); +#else m_stdinProcessDir = QFINDTESTDATA("stdinprocess"); +#endif QVERIFY(!m_stdinProcessDir.isEmpty()); #endif m_testLogFile = QFINDTESTDATA("testlog.txt"); @@ -964,11 +974,14 @@ void tst_QFile::readAllStdin() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when doing nanosleep. See QTBUG-69034."); +#endif QByteArray lotsOfData(1024, '@'); // 10 megs QProcess process; StdinReaderProcessGuard processGuard(&process); - process.start(m_stdinProcessDir + QStringLiteral("/stdinprocess"), QStringList(QStringLiteral("all"))); + process.start(m_stdinProcessDir + QStringLiteral("/" STDINPROCESS_NAME), QStringList(QStringLiteral("all"))); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); for (int i = 0; i < 5; ++i) { QTest::qWait(1000); @@ -987,6 +1000,9 @@ void tst_QFile::readLineStdin() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when doing nanosleep. See QTBUG-69034."); +#endif QByteArray lotsOfData(1024, '@'); // 10 megs for (int i = 0; i < lotsOfData.size(); ++i) { if ((i % 32) == 31) @@ -998,7 +1014,7 @@ void tst_QFile::readLineStdin() for (int i = 0; i < 2; ++i) { QProcess process; StdinReaderProcessGuard processGuard(&process); - process.start(m_stdinProcessDir + QStringLiteral("/stdinprocess"), + process.start(m_stdinProcessDir + QStringLiteral("/" STDINPROCESS_NAME), QStringList() << QStringLiteral("line") << QString::number(i), QIODevice::Text | QIODevice::ReadWrite); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); @@ -1028,10 +1044,13 @@ void tst_QFile::readLineStdin_lineByLine() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else +#if defined(Q_OS_ANDROID) + QSKIP("This test crashes when calling ::poll. See QTBUG-69034."); +#endif for (int i = 0; i < 2; ++i) { QProcess process; StdinReaderProcessGuard processGuard(&process); - process.start(m_stdinProcessDir + QStringLiteral("/stdinprocess"), + process.start(m_stdinProcessDir + QStringLiteral("/" STDINPROCESS_NAME), QStringList() << QStringLiteral("line") << QString::number(i), QIODevice::Text | QIODevice::ReadWrite); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); From 626ab2ab89f17c219c567009b4f3fb6fbae8477f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 27 Jun 2018 14:28:48 +0200 Subject: [PATCH 113/123] Android: Blacklist some cases in tst_qwindow Task-number: QTBUG-69154 Task-number: QTBUG-69155 Task-number: QTBUG-69156 Task-number: QTBUG-69157 Task-number: QTBUG-69159 Task-number: QTBUG-69160 Task-number: QTBUG-69161 Task-number: QTBUG-69162 Task-number: QTBUG-69163 Change-Id: Ie44de7fd3f4871bebcaadcc4a8735bf47692ea49 Reviewed-by: Jesus Fernandez --- tests/auto/gui/kernel/qwindow/BLACKLIST | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST index 70091121bcc..df02b5b33eb 100644 --- a/tests/auto/gui/kernel/qwindow/BLACKLIST +++ b/tests/auto/gui/kernel/qwindow/BLACKLIST @@ -7,14 +7,22 @@ osx-10.12 ci ubuntu-16.04 # QTBUG-66851 opensuse +# QTBUG-69160 +android [setVisible] +# QTBUG-69154 +android [modalWindowEnterEventOnHide_QTBUG35109] ubuntu-16.04 osx ci +# QTBUG-69162 +android [modalDialogClosingOneOfTwoModal] osx [modalWindowModallity] osx +# QTBUG-69163 +android [visibility] osx-10.11 ci osx-10.12 ci @@ -24,3 +32,18 @@ rhel-7.4 [isActive] # QTBUG-67768 ubuntu +# QTBUG-69157 +android + +[exposeEventOnShrink_QTBUG54040] +# QTBUG-69155 +android +[initialSize] +# QTBUG-69159 +android +[modalWindowPosition] +# QTBUG-69161 +android +[childWindowPositioning:show] +# QTBUG-69156 +android From d5fd308d1fdd15339590def21a1dde7c36def018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Wed, 27 Jun 2018 15:05:14 +0200 Subject: [PATCH 114/123] Android: Blacklist tst_QPainter::textOnTransparentImage Task-number: QTBUG-69166 Change-Id: I16289801ff64b09894a5379a584270b53ad7e105 Reviewed-by: Jesus Fernandez --- tests/auto/gui/painting/qpainter/BLACKLIST | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/auto/gui/painting/qpainter/BLACKLIST diff --git a/tests/auto/gui/painting/qpainter/BLACKLIST b/tests/auto/gui/painting/qpainter/BLACKLIST new file mode 100644 index 00000000000..b828cbc75e9 --- /dev/null +++ b/tests/auto/gui/painting/qpainter/BLACKLIST @@ -0,0 +1,3 @@ +[textOnTransparentImage] +# QTBUG-69166 +android From 023a818738d64da01ebecc5d4a26356055ba0021 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Wed, 27 Jun 2018 12:31:02 +0200 Subject: [PATCH 115/123] Doc: Remove old and broken QDBus adaptor example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QTBUG-69091 Change-Id: I991a5bc01c316a5e23204550618d730af755292c Reviewed-by: Topi Reiniö --- .../snippets/code/doc_src_qdbusadaptors.cpp | 212 ------------------ src/dbus/doc/src/dbus-adaptors.qdoc | 128 +---------- 2 files changed, 2 insertions(+), 338 deletions(-) diff --git a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp index 0f43cd73fbb..0fc7a2b26cb 100644 --- a/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp +++ b/src/dbus/doc/snippets/code/doc_src_qdbusadaptors.cpp @@ -48,218 +48,6 @@ ** ****************************************************************************/ -//! [0] -class MainApplicationAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) - -private: - QApplication *app; - -public: - MainApplicationAdaptor(QApplication *application) - : QDBusAbstractAdaptor(application), app(application) - { - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit())); - connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)), - SLOT(focusChangedSlot(QWidget*,QWidget*))); - } - - QString caption() - { - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(""); // must not return a null QString - } - - void setCaption(const QString &newCaption) - { - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); - } - - QString organizationName() - { - return app->organizationName(); - } - - QString organizationDomain() - { - return app->organizationDomain(); - } - -public slots: - Q_NOREPLY void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } - -private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } - -signals: - void aboutToQuit(); - void mainWindowHasFocus(); -}; -//! [0] - - -//! [1] -interface org.kde.DBus.MainApplication -{ - property readwrite STRING caption - property read STRING organizationName - property read STRING organizationDomain - - method quit() annotation("org.freedesktop.DBus.Method.NoReply", "true") - method reparseConfiguration() - method mainWindowObject(out STRING) - method disableSessionManagement(in BOOLEAN enable) - - signal aboutToQuit() - signal mainWindowHasFocus() -} -//! [1] - - -//! [2] -int main(int argc, char **argv) -{ - // create the QApplication object - QApplication app(argc, argv); - - // create the MainApplication adaptor: - new MainApplicationAdaptor(app); - - // connect to D-Bus and register as an object: - QDBusConnection::sessionBus().registerObject("/MainApplication", &app); - - // add main window, etc. - [...] - - app.exec(); -} -//! [2] - - -//! [3] -class MainApplicationAdaptor: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.DBus.MainApplication") -//! [3] - - -//! [4] - Q_PROPERTY(QString caption READ caption WRITE setCaption) - Q_PROPERTY(QString organizationName READ organizationName) - Q_PROPERTY(QString organizationDomain READ organizationDomain) -//! [4] - - -//! [5] -QString caption() -{ - if (app->hasMainWindow()) - return app->mainWindow()->caption(); - return QString(); -} - -void setCaption(const QString &newCaption) -{ - if (app->hasMainWindow()) - app->mainWindow()->setCaption(newCaption); -} - -QString organizationName() -{ - return app->organizationName(); -} - -QString organizationDomain() -{ - return app->organizationDomain(); -} -//! [5] - - -//! [6] -MyInterfaceAdaptor(QApplication *application) - : QDBusAbstractAdaptor(application), app(application) -{ - connect(application, SIGNAL(aboutToQuit()), SIGNAL(aboutToQuit()); - connect(application, SIGNAL(focusChanged(QWidget*,QWidget*)), - SLOT(focusChangedSlot(QWidget*,QWidget*))); -} -//! [6] - - -//! [7] -public slots: - Q_NOREPLY void quit() - { app->quit(); } - - void reparseConfiguration() - { app->reparseConfiguration(); } - - QString mainWindowObject() - { - if (app->hasMainWindow()) - return QString("/%1/mainwindow").arg(app->applicationName()); - return QString(); - } - - void setSessionManagement(bool enable) - { - if (enable) - app->enableSessionManagement(); - else - app->disableSessionManagement(); - } -//! [7] - - -//! [8] -signals: - void aboutToQuit(); - void mainWindowHasFocus(); -//! [8] - - -//! [9] -private slots: - void focusChangedSlot(QWidget *, QWidget *now) - { - if (now == app->mainWindow()) - emit mainWindowHasFocus(); - } -//! [9] - - //! [10] struct RequestData { diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc index 0b0dacf819e..fe9d57f1d1e 100644 --- a/src/dbus/doc/src/dbus-adaptors.qdoc +++ b/src/dbus/doc/src/dbus-adaptors.qdoc @@ -68,132 +68,11 @@ \li \l{Declaring Slots in D-Bus Adaptors} \li \l{Declaring Signals in D-Bus Adaptors} \li \l{The Qt D-Bus Type System} - \li \l{D-Bus Adaptor Example} \endlist \sa QDBusAbstractAdaptor */ -/*! - \page qdbusadaptorexample.html - \title D-Bus Adaptor Example - - \previouspage The Qt D-Bus Type System - \contentspage Using Qt D-Bus Adaptors - - The following example code shows how a D-Bus interface can be implemented - using an adaptor. - - A sample usage of QDBusAbstractAdaptor is as follows: - \snippet code/doc_src_qdbusadaptors.cpp 0 - - The code above would create an interface that could be represented more or less in the following - canonical representation: - \snippet code/doc_src_qdbusadaptors.cpp 1 - - This adaptor could be used in the application's main function as follows - \snippet code/doc_src_qdbusadaptors.cpp 2 - - Break-down analysis: - \tableofcontents - - \section1 The Header - - The header of the example is: - \snippet code/doc_src_qdbusadaptors.cpp 3 - - The code does the following: - \list - \li it declares the adaptor MainApplicationAdaptor, which descends from QDBusAbstractAdaptor - \li it declares the Qt meta-object data using the Q_OBJECT macro - \li it declares the name of the D-Bus interface it implements. - \endlist - - \section1 The Properties - - The properties are declared as follows: - \snippet code/doc_src_qdbusadaptors.cpp 4 - - And are implemented as follows: - \snippet code/doc_src_qdbusadaptors.cpp 5 - - The code declares three properties: one of them is a read-write property called "caption" of - string type. The other two are read-only, also of the string type. - - The properties organizationName and organizationDomain are simple relays of the app object's - organizationName and organizationDomain properties. However, the caption property requires - verifying if the application has a main window associated with it: if there isn't any, the - caption property is empty. Note how it is possible to access data defined in other objects - through the getter/setter functions. - - \section1 The Constructor - - The constructor: - \snippet code/doc_src_qdbusadaptors.cpp 6 - - The constructor does the following: - \list - \li it initialises its base class (QDBusAbstractAdaptor) with the parent object it is related to. - \li it stores the app pointer in a member variable. Note that it would be possible to access the - same object using the QDBusAbstractAdaptor::object() function, but it would be necessary to - use \a static_cast<> to properly access the methods in QApplication that are not part of - QObject. - \li it connects the application's signal \a aboutToQuit to its own signal \a aboutToQuit. - \li it connects the application's signal \a focusChanged to a private slot to do some further - processing before emitting a D-Bus signal. - \endlist - - Note that there is no destructor in the example. An eventual destructor could be used to emit - one last signal before the object is destroyed, for instance. - - \section1 Slots/methods - - The public slots in the example (which will be exported as D-Bus methods) are the following: - \snippet code/doc_src_qdbusadaptors.cpp 7 - - This snippet of code defines 4 methods with different properties each: - \list 1 - \li \c quit: this method takes no parameters and is defined to be asynchronous. That is, callers - are expected to use "fire-and-forget" mechanism when calling this method, since it provides no - useful reply. This is represented in D-Bus by the use of the - org.freedesktop.DBus.Method.NoReply annotation. See \l Q_NOREPLY for more information on - asynchronous methods - - \li \c reparseConfiguration: this simple method, with no input or output arguments simply relays - the call to the application's reparseConfiguration member function. - - \li \c mainWindowObject: this method takes no input parameter, but returns one string output - argument, containing the path to the main window object (if the application has a main - window), or an empty string if it has no main window. Note that this method could have also - been written: void mainWindowObject(QString &path). - - \li \c setSessionManagement: this method takes one input argument (a boolean) and, depending on - its value, it calls one function or another in the application. - \endlist - - See also: \l Q_NOREPLY. - - \section1 Signals - - The signals in this example are defined as follows: - \snippet code/doc_src_qdbusadaptors.cpp 8 - - However, signal definition isn't enough: signals have to be emitted. One simple way of emitting - signals is to connect another signal to them, so that Qt's signal handling system chains them - automatically. This is what is done for the \a aboutToQuit signal. - - When this is the case, one can use the QDBusAbstractAdaptor::setAutoRelaySignals to - automatically connect every signal from the real object to the adaptor. - - When simple signal-to-signal connection isn't enough, one can use a private slot do do some - work. This is what was done for the mainWindowHasFocus signal: - \snippet code/doc_src_qdbusadaptors.cpp 9 - - This private slot (which will not be exported as a method via D-Bus) was connected to the - \c focusChanged signal in the adaptor's constructor. It is therefore able to shape the - application's signal into what the interface expects it to be. -*/ - /*! \page qdbusdeclaringslots.html \title Declaring Slots in D-Bus Adaptors @@ -230,8 +109,7 @@ synchronize with the caller should provide its own method of synchronization. Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method - signature, before the \c void return type and the slot name. (See the - \c quit() slot in the \l{D-Bus Adaptor Example}). + signature, before the \c void return type and the slot name. \section1 Input-Only Slots @@ -341,8 +219,7 @@ However, signals must still be emitted. The easiest way to emit an adaptor signal is to connect another signal to it, so that Qt's signals and slots mechanism automatically emits the adaptor signal, too. This can be done in - the adaptor's constructor, as has been done in the - \l{D-Bus Adaptor Example}{D-Bus Adaptor example}. + the adaptor's constructor. The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also be used to make and break connections between signals in the real object and @@ -360,7 +237,6 @@ \previouspage Declaring Signals in D-Bus Adaptors \contentspage Using Qt D-Bus Adaptors - \nextpage D-Bus Adaptor Example D-Bus has an extensible type system based on a few primitives and composition of the primitives in arrays and structures. Qt D-Bus From 3d867b84a3ac4c2b32b7d476eaeadc2c7fae277b Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 20 Jun 2018 18:50:07 +0200 Subject: [PATCH 116/123] Fix automatic showing/hiding of the Windows 10 on-screen keyboard The automatic showing/hiding of the built-in on-screen keyboard in touchscreen-based Windows computers, like the Microsoft Surface line, has stopped working after recent Windows updates. The OSK no longer seems to rely on UI Automation properties to detect text widgets. However, it can be triggered by showing an invisible caret. Task-number: QTBUG-68808 Change-Id: Ia604d21e314965dcdc61f1ced050cc3ed771f567 Reviewed-by: Friedemann Kleint --- .../windows/qwindowsinputcontext.cpp | 92 +++++++++++++------ .../platforms/windows/qwindowsinputcontext.h | 9 +- .../platforms/windows/qwindowswindow.h | 11 +-- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 2dbca6047c9..261c931f2bd 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -164,19 +164,22 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp */ -HIMC QWindowsInputContext::m_defaultContext = 0; - QWindowsInputContext::QWindowsInputContext() : m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")), m_languageId(currentInputLanguageId()), m_locale(qt_localeFromLCID(m_languageId)) { + const quint32 bmpData = 0; + m_transparentBitmap = CreateBitmap(2, 2, 1, 1, &bmpData); + connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QWindowsInputContext::cursorRectChanged); } QWindowsInputContext::~QWindowsInputContext() { + if (m_transparentBitmap) + DeleteObject(m_transparentBitmap); } bool QWindowsInputContext::hasCapability(Capability capability) const @@ -243,6 +246,43 @@ bool QWindowsInputContext::isInputPanelVisible() const return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd); } +void QWindowsInputContext::showInputPanel() +{ + if (!inputMethodAccepted()) + return; + + QWindow *window = QGuiApplication::focusWindow(); + if (!window) + return; + + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); + if (!platformWindow) + return; + + // Create an invisible 2x2 caret, which will be kept at the microfocus position. + // It is important for triggering the on-screen keyboard in touch-screen devices, + // for some Chinese input methods, and for Magnifier's "follow keyboard" feature. + if (!m_caretCreated && m_transparentBitmap) + m_caretCreated = CreateCaret(platformWindow->handle(), m_transparentBitmap, 0, 0); + + // For some reason, the on-screen keyboard is only triggered on the Surface + // with Windows 10 if the Windows IME is (re)enabled _after_ the caret is shown. + if (m_caretCreated) { + cursorRectChanged(); + ShowCaret(platformWindow->handle()); + setWindowsImeEnabled(platformWindow, false); + setWindowsImeEnabled(platformWindow, true); + } +} + +void QWindowsInputContext::hideInputPanel() +{ + if (m_caretCreated) { + DestroyCaret(); + m_caretCreated = false; + } +} + void QWindowsInputContext::updateEnabled() { if (!QGuiApplication::focusObject()) @@ -257,18 +297,14 @@ void QWindowsInputContext::updateEnabled() void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled) { - if (!platformWindow || platformWindow->testFlag(QWindowsWindow::InputMethodDisabled) == !enabled) + if (!platformWindow) return; if (enabled) { - // Re-enable Windows IME by associating default context saved on first disabling. - ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext); - platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled); + // Re-enable Windows IME by associating default context. + ImmAssociateContextEx(platformWindow->handle(), 0, IACE_DEFAULT); } else { - // Disable Windows IME by associating 0 context. Store context first time. - const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0); - platformWindow->setFlag(QWindowsWindow::InputMethodDisabled); - if (!QWindowsInputContext::m_defaultContext && oldImC) - QWindowsInputContext::m_defaultContext = oldImC; + // Disable Windows IME by associating 0 context. + ImmAssociateContext(platformWindow->handle(), 0); } } @@ -285,15 +321,25 @@ void QWindowsInputContext::update(Qt::InputMethodQueries queries) void QWindowsInputContext::cursorRectChanged() { - if (!m_compositionContext.hwnd) + QWindow *window = QGuiApplication::focusWindow(); + if (!window) return; + + qreal factor = QHighDpiScaling::factor(window); + const QInputMethod *inputMethod = QGuiApplication::inputMethod(); const QRectF cursorRectangleF = inputMethod->cursorRectangle(); if (!cursorRectangleF.isValid()) return; + const QRect cursorRectangle = - QRectF(cursorRectangleF.topLeft() * m_compositionContext.factor, - cursorRectangleF.size() * m_compositionContext.factor).toRect(); + QRectF(cursorRectangleF.topLeft() * factor, cursorRectangleF.size() * factor).toRect(); + + if (m_caretCreated) + SetCaretPos(cursorRectangle.x(), cursorRectangle.y()); + + if (!m_compositionContext.hwnd) + return; qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; @@ -317,9 +363,6 @@ void QWindowsInputContext::cursorRectChanged() candf.rcArea.right = cursorRectangle.x() + cursorRectangle.width(); candf.rcArea.bottom = cursorRectangle.y() + cursorRectangle.height(); - if (m_compositionContext.haveCaret) - SetCaretPos(cursorRectangle.x(), cursorRectangle.y()); - ImmSetCompositionWindow(himc, &cf); ImmSetCandidateWindow(himc, &candf); ImmReleaseContext(m_compositionContext.hwnd, himc); @@ -411,7 +454,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd) qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window << "language=" << m_languageId; if (!fo || QWindowsWindow::handleOf(window) != hwnd) return false; - initContext(hwnd, QHighDpiScaling::factor(window), fo); + initContext(hwnd, fo); startContextComposition(); return true; } @@ -551,18 +594,13 @@ bool QWindowsInputContext::endComposition(HWND hwnd) return true; } -void QWindowsInputContext::initContext(HWND hwnd, qreal factor, QObject *focusObject) +void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject) { if (m_compositionContext.hwnd) doneContext(); m_compositionContext.hwnd = hwnd; m_compositionContext.focusObject = focusObject; - m_compositionContext.factor = factor; - // Create a hidden caret which is kept at the microfocus - // position in update(). This is important for some - // Chinese input methods. - m_compositionContext.haveCaret = CreateCaret(hwnd, 0, 1, 1); - HideCaret(hwnd); + update(Qt::ImQueryAll); m_compositionContext.isComposing = false; m_compositionContext.position = 0; @@ -572,12 +610,10 @@ void QWindowsInputContext::doneContext() { if (!m_compositionContext.hwnd) return; - if (m_compositionContext.haveCaret) - DestroyCaret(); m_compositionContext.hwnd = 0; m_compositionContext.composition.clear(); m_compositionContext.position = 0; - m_compositionContext.isComposing = m_compositionContext.haveCaret = false; + m_compositionContext.isComposing = false; m_compositionContext.focusObject = 0; } diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index ada1fc0d29e..d647628ff1c 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -58,12 +58,10 @@ class QWindowsInputContext : public QPlatformInputContext struct CompositionContext { HWND hwnd = 0; - bool haveCaret = false; QString composition; int position = 0; bool isComposing = false; QPointer focusObject; - qreal factor = 1; }; public: explicit QWindowsInputContext(); @@ -81,6 +79,8 @@ public: QRectF keyboardRect() const override; bool isInputPanelVisible() const override; + void showInputPanel() override; + void hideInputPanel() override; bool startComposition(HWND hwnd); bool composition(HWND hwnd, LPARAM lParam); @@ -96,7 +96,7 @@ private slots: void cursorRectChanged(); private: - void initContext(HWND hwnd, qreal factor, QObject *focusObject); + void initContext(HWND hwnd, QObject *focusObject); void doneContext(); void startContextComposition(); void endContextComposition(); @@ -104,7 +104,8 @@ private: HWND getVirtualKeyboardWindowHandle() const; const DWORD m_WM_MSIME_MOUSE; - static HIMC m_defaultContext; + bool m_caretCreated = false; + HBITMAP m_transparentBitmap; CompositionContext m_compositionContext; bool m_endCompositionRecursionGuard = false; LCID m_languageId; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index fe2518e3297..6d439bce1a1 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -214,12 +214,11 @@ public: WithinCreate = 0x20000, WithinMaximize = 0x40000, MaximizeToFullScreen = 0x80000, - InputMethodDisabled = 0x100000, - Compositing = 0x200000, - HasBorderInFullScreen = 0x400000, - WithinDpiChanged = 0x800000, - VulkanSurface = 0x1000000, - ResizeMoveActive = 0x2000000 + Compositing = 0x100000, + HasBorderInFullScreen = 0x200000, + WithinDpiChanged = 0x400000, + VulkanSurface = 0x800000, + ResizeMoveActive = 0x1000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); From 80a550dd79b8ed0ac72e775c98caefc4df16b882 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 18 May 2018 12:19:25 +0200 Subject: [PATCH 117/123] Replace LGPL licenses in .qdoc files with FDL .qdoc files should only be licensed under FDL (for documentation) or BSD (if they only contain code). Change-Id: I2a8a5b2c7bd3f927b8f71506c3672bc4916aca1e Reviewed-by: Leena Miettinen --- src/corelib/global/qglobalstatic.qdoc | 30 +++++++-------------- src/corelib/thread/qfuture.qdoc | 30 +++++++-------------- src/corelib/thread/qfuturesynchronizer.qdoc | 30 +++++++-------------- src/corelib/tools/qstringiterator.qdoc | 30 +++++++-------------- src/corelib/tools/qvector.qdoc | 30 +++++++-------------- 5 files changed, 45 insertions(+), 105 deletions(-) diff --git a/src/corelib/global/qglobalstatic.qdoc b/src/corelib/global/qglobalstatic.qdoc index e3705ee6be0..303709bb1df 100644 --- a/src/corelib/global/qglobalstatic.qdoc +++ b/src/corelib/global/qglobalstatic.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,25 +14,13 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index e607d090c59..7db65dacd3b 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,25 +14,13 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/corelib/thread/qfuturesynchronizer.qdoc b/src/corelib/thread/qfuturesynchronizer.qdoc index c9c402ff878..67dafb039e6 100644 --- a/src/corelib/thread/qfuturesynchronizer.qdoc +++ b/src/corelib/thread/qfuturesynchronizer.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,25 +14,13 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/corelib/tools/qstringiterator.qdoc b/src/corelib/tools/qstringiterator.qdoc index caec8803f3a..9d7c54ce9fd 100644 --- a/src/corelib/tools/qstringiterator.qdoc +++ b/src/corelib/tools/qstringiterator.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,25 +14,13 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/corelib/tools/qvector.qdoc b/src/corelib/tools/qvector.qdoc index 9a08b030f7b..75b17a42077 100644 --- a/src/corelib/tools/qvector.qdoc +++ b/src/corelib/tools/qvector.qdoc @@ -3,9 +3,9 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the QtCore module of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,25 +14,13 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ From e5b3db841d9912cfc1a8252f5e6f687006a5ea2b Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 22 Jun 2018 15:56:15 +0200 Subject: [PATCH 118/123] Fix: bad-looking scaled rendering of painterpath in OpenGL paint engine For performance, the triangulation of a painter path is stored for reuse. Re-triangulation was only done if the path was to be painted at a significantly different scale AND it contained a curve (bezier) element. But also the triangulation of a path with only straight lines can lose precision if rendered at a small scale, and so look bad when used at a higher scale factor. Fix by removing the mentioned curve element condition. Task-number: QTBUG-68873 Change-Id: Id3492514e9382a5828377b7bafea8cfac7b850a6 Reviewed-by: Laszlo Agocs --- src/gui/opengl/qopenglpaintengine.cpp | 38 ++++++++++++--------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index 17dc9df6196..3d1c3622753 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -797,20 +797,18 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (data) { cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded for curved paths and generate curves if so... - if (path.isCurved()) { - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { + // Check if scale factor is exceeded and regenerate if so... + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { #ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - cache->vbo = 0; - Q_ASSERT(cache->ibo == 0); + glDeleteBuffers(1, &cache->vbo); + cache->vbo = 0; + Q_ASSERT(cache->ibo == 0); #else - free(cache->vertices); - Q_ASSERT(cache->indices == 0); + free(cache->vertices); + Q_ASSERT(cache->indices == 0); #endif - updateCache = true; - } + updateCache = true; } } else { cache = new QOpenGL2PEVectorPathCache; @@ -879,19 +877,17 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) if (data) { cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded for curved paths and generate curves if so... - if (path.isCurved()) { - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { + // Check if scale factor is exceeded and regenerate if so... + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { #ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - glDeleteBuffers(1, &cache->ibo); + glDeleteBuffers(1, &cache->vbo); + glDeleteBuffers(1, &cache->ibo); #else - free(cache->vertices); - free(cache->indices); + free(cache->vertices); + free(cache->indices); #endif - updateCache = true; - } + updateCache = true; } } else { cache = new QOpenGL2PEVectorPathCache; From 7f7ceb567fe2f58b47b66415f30918f3b482f2b0 Mon Sep 17 00:00:00 2001 From: Paul Wicking Date: Thu, 28 Jun 2018 15:04:35 +0200 Subject: [PATCH 119/123] Doc: Add references to QDBusAbstractAdaptor implementation example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding references where applicable, as removed by 023a818738d64da01ebecc5d4a26356055ba0021 when removing stale example. Add example run snippet to the example landing page. Remove stale example qdoc file that is superceded by current example. Task-number: QTBUG-69191 Change-Id: I62dc66edc86da5efb4c79fd124edb2fa619aeb6b Reviewed-by: Topi Reiniö --- doc/src/examples/complexpingpong.qdoc | 36 ---------------------- examples/dbus/doc/src/complexpingpong.qdoc | 8 +++++ src/dbus/doc/src/dbus-adaptors.qdoc | 8 +++-- 3 files changed, 14 insertions(+), 38 deletions(-) delete mode 100644 doc/src/examples/complexpingpong.qdoc diff --git a/doc/src/examples/complexpingpong.qdoc b/doc/src/examples/complexpingpong.qdoc deleted file mode 100644 index 4a7cec21bb4..00000000000 --- a/doc/src/examples/complexpingpong.qdoc +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \example complexpingpong - \title Complex Ping Pong Example - - The Complex Ping Pong example improves on the \l{D-Bus Ping Pong Example} by providing - a more useful demonstration of D-Bus interfaces. - - \quotefile doc/src/snippets/complexpingpong-example.txt -*/ diff --git a/examples/dbus/doc/src/complexpingpong.qdoc b/examples/dbus/doc/src/complexpingpong.qdoc index fca654a06a8..d09708c0ffc 100644 --- a/examples/dbus/doc/src/complexpingpong.qdoc +++ b/examples/dbus/doc/src/complexpingpong.qdoc @@ -40,4 +40,12 @@ \include examples-run.qdocinc To run, execute the \c complexping application. + + \badcode + $ ./complexping + Ask your question: When is the next Qt release? + Reply was: Sorry, I don't know the answer + Ask your question: What is the answer to life, the universe and everything? + Reply was: 42 + \endcode */ diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc index fe9d57f1d1e..9ebf0cedf21 100644 --- a/src/dbus/doc/src/dbus-adaptors.qdoc +++ b/src/dbus/doc/src/dbus-adaptors.qdoc @@ -68,6 +68,8 @@ \li \l{Declaring Slots in D-Bus Adaptors} \li \l{Declaring Signals in D-Bus Adaptors} \li \l{The Qt D-Bus Type System} + \li In the \l{D-Bus Complex Ping Pong Example}, \c complexpong.h and + \c complexpong.cpp show an implementation of QDBusAbstractAdaptor. \endlist \sa QDBusAbstractAdaptor @@ -109,7 +111,8 @@ synchronize with the caller should provide its own method of synchronization. Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method - signature, before the \c void return type and the slot name. + signature, before the \c void return type and the slot name. The \c quit() + slot in the \l {D-Bus Complex Ping Pong Example} is an example of this. \section1 Input-Only Slots @@ -219,7 +222,8 @@ However, signals must still be emitted. The easiest way to emit an adaptor signal is to connect another signal to it, so that Qt's signals and slots mechanism automatically emits the adaptor signal, too. This can be done in - the adaptor's constructor. + the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping + Pong Example}. The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also be used to make and break connections between signals in the real object and From 34d212cb02f168e59c2a5c8e95a12377a57bfb7e Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Wed, 6 Jun 2018 09:08:33 +0200 Subject: [PATCH 120/123] QMenuBar: Account for displays that are above 0x0 If a display is placed above a primary screen which has the top left set to be 0x0, then menus that are defaulting to go up can still be displayed on that screen when the menubar is placed on the bottom of it. This ensures that this is the case and also adds a manual test to aid verification of it in the future. Change-Id: Ib657ccdc1aabfe1586c72585c087ac80a6c632c2 Reviewed-by: Friedemann Kleint --- src/widgets/widgets/qmenubar.cpp | 2 +- .../defaultUpMenuBar/defaultUpMenuBar.pro | 4 + .../widgets/widgets/defaultUpMenuBar/main.cpp | 125 ++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro create mode 100644 tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index 7c4dd896a4a..6df53dc4e4b 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -327,7 +327,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) QRect screenRect = QDesktopWidgetPrivate::screenGeometry(pos + QPoint(adjustedActionRect.width() / 2, 0)); pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y())); - const bool fitUp = (q->mapToGlobal(adjustedActionRect.topLeft()).y() >= popup_size.height()); + const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top()); const bool fitDown = (pos.y() + popup_size.height() <= screenRect.bottom()); const bool rtl = q->isRightToLeft(); const int actionWidth = adjustedActionRect.width(); diff --git a/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro b/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro new file mode 100644 index 00000000000..f9cffb37092 --- /dev/null +++ b/tests/manual/widgets/widgets/defaultUpMenuBar/defaultUpMenuBar.pro @@ -0,0 +1,4 @@ +QT += widgets +TEMPLATE = app +TARGET = defaultUpMenuBar +SOURCES += main.cpp diff --git a/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp b/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp new file mode 100644 index 00000000000..602127febe2 --- /dev/null +++ b/tests/manual/widgets/widgets/defaultUpMenuBar/main.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + ** + ** Copyright (C) 2018 The Qt Company Ltd. + ** Contact: https://www.qt.io/licensing/ + ** + ** This file is part of the test suite of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:BSD$ + ** Commercial License Usage + ** Licensees holding valid commercial Qt licenses may use this file in + ** accordance with the commercial license agreement provided with the + ** Software or, alternatively, in accordance with the terms contained in + ** a written agreement between you and The Qt Company. For licensing terms + ** and conditions see https://www.qt.io/terms-conditions. For further + ** information use the contact form at https://www.qt.io/contact-us. + ** + ** BSD License Usage + ** Alternatively, you may use this file under the terms of the BSD license + ** as follows: + ** + ** "Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions are + ** met: + ** * Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** * Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in + ** the documentation and/or other materials provided with the + ** distribution. + ** * Neither the name of The Qt Company Ltd nor the names of its + ** contributors may be used to endorse or promote products derived + ** from this software without specific prior written permission. + ** + ** + ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + +// This test is to check that the menus in a menubar are displayed correctly in both the top and +// bottom cases. Especially when using multiple screens. If possible relayout the screens in order +// to have one that is entirely in negative coordinates (i.e. the primary starts at 0x0 and the +// secondary is above it). + +#include +#include + +class MainWindow : public QMainWindow +{ +public: + MainWindow(QWidget *parent = 0) : QMainWindow(parent) + { + auto *menu1Act1 = new QAction("Action 1"); + auto *menu1Act2 = new QAction("Action 2"); + auto *menu1Act3 = new QAction("Action 3"); + auto *menu1Act4 = new QAction("Action 4"); + auto *menu2Act1 = new QAction("2- Action 1"); + auto *menu2Act2 = new QAction("2- Action 2"); + auto *menu2Act3 = new QAction("2- Action 3"); + auto *menu2Act4 = new QAction("2- Action 4"); + auto *menu1 = new QMenu("Menu 1"); + menu1->addAction(menu1Act1); + menu1->addAction(menu1Act2); + menu1->addAction(menu1Act3); + menu1->addAction(menu1Act4); + auto *menu2 = new QMenu("Menu 2"); + menu2->addAction(menu2Act1); + menu2->addAction(menu2Act2); + menu2->addAction(menu2Act3); + menu2->addAction(menu2Act4); + menuBar()->addMenu(menu1); + menuBar()->addMenu(menu2); + menuBar()->setNativeMenuBar(false); + + auto *menu1Bottom = new QMenu("Menu 1"); + menu1Bottom->addAction(menu1Act1); + menu1Bottom->addAction(menu1Act2); + menu1Bottom->addAction(menu1Act3); + menu1Bottom->addAction(menu1Act4); + auto *menu2Bottom = new QMenu("Menu 2"); + menu2Bottom->addAction(menu2Act1); + menu2Bottom->addAction(menu2Act2); + menu2Bottom->addAction(menu2Act3); + menu2Bottom->addAction(menu2Act4); + + QWidget *central = new QWidget; + QVBoxLayout *layout = new QVBoxLayout; + auto *menuBarBottom = new QMenuBar(this); + menuBarBottom->addMenu(menu1Bottom); + menuBarBottom->addMenu(menu2Bottom); + menuBarBottom->setDefaultUp(true); + menuBarBottom->setNativeMenuBar(false); + layout->addWidget(menuBarBottom); + layout->setAlignment(menuBarBottom, Qt::AlignBottom); + central->setLayout(layout); + setCentralWidget(central); + setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + } +}; + +int main(int argc, char **argv) +{ + QApplication a(argc, argv); + QList windows; + for (QScreen *screen : QApplication::screens()) { + MainWindow *mainWindow = new MainWindow; + mainWindow->setGeometry(screen->geometry()); + QWindowsWindowFunctions::setHasBorderInFullScreen(mainWindow->windowHandle(), true); + mainWindow->showMaximized(); + } + int ret = a.exec(); + qDeleteAll(windows); + return ret; +} From 0ac09c40f28987169786b3063af423e9fe93c6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Thu, 28 Jun 2018 11:55:42 +0200 Subject: [PATCH 121/123] Android: Pass tst_qlibrary To make the minimum amount of changes: - Extract the library files into the expected hierarchy. - Introduce a variable with the path to the directory. - Make the static function a member function so it can use the variable Change-Id: Ibf3106c3606d198a8deb8cb2a5cbde57207221c7 Reviewed-by: Thiago Macieira --- .../auto/corelib/plugin/qlibrary/tst/tst.pro | 11 ++++ .../corelib/plugin/qlibrary/tst_qlibrary.cpp | 61 ++++++++++++++----- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro index 6e71ec8ff93..56bef144057 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro +++ b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro @@ -12,3 +12,14 @@ win32 { } TESTDATA += ../library_path/invalid.so + +android { + libs.prefix = android_test_data + libs.base = $$OUT_PWD/.. + libs.files += $$OUT_PWD/../libmylib.so \ + $$OUT_PWD/../libmylib.so2 \ + $$OUT_PWD/../libmylib.prl \ + $$OUT_PWD/../system.qt.test.mylib.so + + RESOURCES += libs +} diff --git a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp index 72d60d71c72..c9c9202a80f 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp @@ -88,12 +88,6 @@ # define PREFIX "lib" #endif -static QString sys_qualifiedLibraryName(const QString &fileName) -{ - QString appDir = QCoreApplication::applicationDirPath(); - return appDir + QLatin1Char('/') + PREFIX + fileName + SUFFIX; -} - QT_FORWARD_DECLARE_CLASS(QLibrary) class tst_QLibrary : public QObject { @@ -106,6 +100,13 @@ enum QLibraryOperation { OperationMask = 7, DontSetFileName = 0x100 }; + + QString sys_qualifiedLibraryName(const QString &fileName); + + QString directory; +#ifdef Q_OS_ANDROID + QSharedPointer temporaryDir; +#endif private slots: void initTestCase(); @@ -130,19 +131,49 @@ private slots: void multipleInstancesForOneLibrary(); }; +QString tst_QLibrary::sys_qualifiedLibraryName(const QString &fileName) +{ + return directory + QLatin1Char('/') + PREFIX + fileName + SUFFIX; +} + typedef int (*VersionFunction)(void); void tst_QLibrary::initTestCase() { -#ifndef Q_OS_WINRT +#ifdef Q_OS_ANDROID + auto tempDir = QEXTRACTTESTDATA("android_test_data"); + + QVERIFY2(QDir::setCurrent(tempDir->path()), qPrintable("Could not chdir to " + tempDir->path())); + + // copy :/library_path into ./library_path + QVERIFY(QDir().mkdir("library_path")); + QDirIterator iterator(":/library_path", QDirIterator::Subdirectories); + while (iterator.hasNext()) { + iterator.next(); + QFileInfo sourceFileInfo(iterator.path()); + QFileInfo targetFileInfo("./library_path/" + sourceFileInfo.fileName()); + if (!targetFileInfo.exists()) { + QDir().mkpath(targetFileInfo.path()); + QVERIFY(QFile::copy(sourceFileInfo.filePath(), targetFileInfo.filePath())); + } + } + directory = tempDir->path(); + temporaryDir = std::move(tempDir); +#elif !defined(Q_OS_WINRT) // chdir to our testdata directory, and use relative paths in some tests. QString testdatadir = QFileInfo(QFINDTESTDATA("library_path")).absolutePath(); QVERIFY2(QDir::setCurrent(testdatadir), qPrintable("Could not chdir to " + testdatadir)); + directory = QCoreApplication::applicationDirPath(); +#elif defined(Q_OS_WINRT) + directory = QCoreApplication::applicationDirPath(); #endif } void tst_QLibrary::version_data() { +#ifdef Q_OS_ANDROID + QSKIP("Versioned .so files are not generated for Android, so this test is not applicable."); +#endif QTest::addColumn("lib"); QTest::addColumn("loadversion"); QTest::addColumn("resultversion"); @@ -159,7 +190,7 @@ void tst_QLibrary::version() QFETCH( int, resultversion ); #if !defined(Q_OS_AIX) && !defined(Q_OS_WIN) - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QLibrary library( appDir + QLatin1Char('/') + lib, loadversion ); QVERIFY2(library.load(), qPrintable(library.errorString())); @@ -179,7 +210,7 @@ void tst_QLibrary::load_data() QTest::addColumn("lib"); QTest::addColumn("result"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "ok00" ) << appDir + "/mylib" << true; QTest::newRow( "notexist" ) << appDir + "/nolib" << false; @@ -220,7 +251,7 @@ void tst_QLibrary::unload_data() QTest::addColumn("lib"); QTest::addColumn("result"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "mylib" ) << appDir + "/mylib" << true; QTest::newRow( "ok01" ) << appDir + "/nolib" << false; @@ -243,7 +274,7 @@ void tst_QLibrary::unload() void tst_QLibrary::unload_after_implicit_load() { - QLibrary library( QCoreApplication::applicationDirPath() + "/mylib" ); + QLibrary library( directory + "/mylib" ); QFunctionPointer p = library.resolve("mylibversion"); QVERIFY(p); // Check if it was loaded QVERIFY(library.isLoaded()); @@ -257,7 +288,7 @@ void tst_QLibrary::resolve_data() QTest::addColumn("symbol"); QTest::addColumn("goodPointer"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow( "ok00" ) << appDir + "/mylib" << QString("mylibversion") << true; QTest::newRow( "bad00" ) << appDir + "/mylib" << QString("nosym") << false; @@ -333,7 +364,7 @@ void tst_QLibrary::errorString_data() QTest::addColumn("success"); QTest::addColumn("errorString"); - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; QTest::newRow("bad load()") << (int)Load << QString("nosuchlib") << false << QString("Cannot load library nosuchlib: .*"); QTest::newRow("call errorString() on QLibrary with no d-pointer (crashtest)") << (int)(Load | DontSetFileName) << QString() << false << QString("Unknown error"); @@ -398,7 +429,7 @@ void tst_QLibrary::loadHints_data() QLibrary::LoadHints lh; - QString appDir = QCoreApplication::applicationDirPath(); + QString appDir = directory; lh |= QLibrary::ResolveAllSymbolsHint; # if defined(Q_OS_WIN32) || defined(Q_OS_WINRT) @@ -477,7 +508,7 @@ void tst_QLibrary::fileName() void tst_QLibrary::multipleInstancesForOneLibrary() { - QString lib = QCoreApplication::applicationDirPath() + "/mylib"; + QString lib = directory + "/mylib"; { QLibrary lib1(lib); From 35e005bc4fd790d41a5b5248e85bbdac33fbf043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= Date: Sat, 30 Jun 2018 13:53:03 +0200 Subject: [PATCH 122/123] Fix metatype trait for types that are both QObject and Q_GADGET Fixes ambiguous template instantiation for types that derive from both a QObject and Q_GADGET. For such types we treat them only as QObjects as they extend the functionality of the gadget. Task-number: QTBUG-68803 Change-Id: Ic42766034e14e5df43c4e6f7811e2c0be1dc7e74 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/kernel/qmetatype.h | 4 ++-- tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index a0969ee9082..cf68752f857 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1413,8 +1413,8 @@ namespace QtPrivate static char checkType(void (X::*)()); static void *checkType(void (T::*)()); enum { - IsRealGadget = sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *), - IsGadgetOrDerivedFrom = true + IsRealGadget = !IsPointerToTypeDerivedFromQObject::Value && sizeof(checkType(&T::qt_check_for_QGADGET_macro)) == sizeof(void *), + IsGadgetOrDerivedFrom = !IsPointerToTypeDerivedFromQObject::Value }; }; diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index c6fd5d17c2d..e3121999806 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1696,11 +1696,21 @@ public: Q_ENUM(MyEnum) }; +class MyQObjectFromGadget : public QObject, public MyGadget +{ + Q_OBJECT +public: + MyQObjectFromGadget(QObject *parent = 0) + : QObject(parent) + {} +}; + Q_DECLARE_METATYPE(MyGadget); Q_DECLARE_METATYPE(MyGadget*); Q_DECLARE_METATYPE(const QMetaObject *); Q_DECLARE_METATYPE(Qt::ScrollBarPolicy); Q_DECLARE_METATYPE(MyGadget::MyEnum); +Q_DECLARE_METATYPE(MyQObjectFromGadget*); void tst_QMetaType::metaObject_data() { @@ -1719,6 +1729,7 @@ void tst_QMetaType::metaObject_data() QTest::newRow("MyGadget*") << ::qMetaTypeId() << &MyGadget::staticMetaObject << false << true << false; QTest::newRow("MyEnum") << ::qMetaTypeId() << &MyGadget::staticMetaObject << false << false << false; QTest::newRow("Qt::ScrollBarPolicy") << ::qMetaTypeId() << &QObject::staticQtMetaObject << false << false << false; + QTest::newRow("MyQObjectFromGadget*") << ::qMetaTypeId() << &MyQObjectFromGadget::staticMetaObject << false << false << true; QTest::newRow("GadgetDerivedAndTyped") << ::qMetaTypeId>() << &GadgetDerivedAndTyped::staticMetaObject << true << false << false; QTest::newRow("GadgetDerivedAndTyped*") << ::qMetaTypeId*>() << &GadgetDerivedAndTyped::staticMetaObject << false << true << false; From e75e4b39b78ba05ea2cd45dc96acf99fc89c5915 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 30 Jun 2018 19:03:48 +0200 Subject: [PATCH 123/123] Reduce amount of log output of the qcomplextext autotest Writing out one test result per line in the test data files is excessive and only bloats the log, given that this algorithm is rarely changed. Task-number: QTQAINFRA-2037 Change-Id: Ib9e568c7ded73d45e4b64671e97d5581a74f8f93 Reviewed-by: Thiago Macieira --- .../other/qcomplextext/tst_qcomplextext.cpp | 144 +++++++----------- 1 file changed, 56 insertions(+), 88 deletions(-) diff --git a/tests/auto/other/qcomplextext/tst_qcomplextext.cpp b/tests/auto/other/qcomplextext/tst_qcomplextext.cpp index 812cd8f3696..0116e546a0a 100644 --- a/tests/auto/other/qcomplextext/tst_qcomplextext.cpp +++ b/tests/auto/other/qcomplextext/tst_qcomplextext.cpp @@ -48,9 +48,7 @@ private slots: void bidiInvalidCursorNoMovement_data(); void bidiInvalidCursorNoMovement(); - void bidiCharacterTest_data(); void bidiCharacterTest(); - void bidiTest_data(); void bidiTest(); }; @@ -279,67 +277,6 @@ void tst_QComplexText::bidiCursor_PDF() QVERIFY(line.cursorToX(size) == line.cursorToX(size - 1)); } -void tst_QComplexText::bidiCharacterTest_data() -{ - QTest::addColumn("data"); - QTest::addColumn("paragraphDirection"); - QTest::addColumn>("resolvedLevels"); - QTest::addColumn>("visualOrder"); - - QString testFile = QFINDTESTDATA("data/BidiCharacterTest.txt"); - QFile f(testFile); - QVERIFY(f.exists()); - - f.open(QIODevice::ReadOnly); - - int linenum = 0; - while (!f.atEnd()) { - linenum++; - - QByteArray line = f.readLine().simplified(); - if (line.startsWith('#') || line.isEmpty()) - continue; - QVERIFY(!line.contains('#')); - - QList parts = line.split(';'); - QVERIFY(parts.size() == 5); - - QString data; - QList dataParts = parts.at(0).split(' '); - for (const auto &p : dataParts) { - bool ok; - data += QChar((ushort)p.toInt(&ok, 16)); - QVERIFY(ok); - } - - int paragraphDirection = parts.at(1).toInt(); -// int resolvedParagraphLevel = parts.at(2).toInt(); - - QVector resolvedLevels; - QList levelParts = parts.at(3).split(' '); - for (const auto &p : levelParts) { - if (p == "x") { - resolvedLevels += -1; - } else { - bool ok; - resolvedLevels += p.toInt(&ok); - QVERIFY(ok); - } - } - - QVector visualOrder; - QList orderParts = parts.at(4).split(' '); - for (const auto &p : orderParts) { - bool ok; - visualOrder += p.toInt(&ok); - QVERIFY(ok); - } - - const QByteArray nm = "line #" + QByteArray::number(linenum); - QTest::newRow(nm.constData()) << data << paragraphDirection << resolvedLevels << visualOrder; - } -} - static void testBidiString(const QString &data, int paragraphDirection, const QVector &resolvedLevels, const QVector &visualOrder) { Q_UNUSED(resolvedLevels); @@ -421,12 +358,59 @@ static void testBidiString(const QString &data, int paragraphDirection, const QV void tst_QComplexText::bidiCharacterTest() { - QFETCH(QString, data); - QFETCH(int, paragraphDirection); - QFETCH(QVector, resolvedLevels); - QFETCH(QVector, visualOrder); + QString testFile = QFINDTESTDATA("data/BidiCharacterTest.txt"); + QFile f(testFile); + QVERIFY(f.exists()); - testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); + f.open(QIODevice::ReadOnly); + + int linenum = 0; + while (!f.atEnd()) { + linenum++; + + QByteArray line = f.readLine().simplified(); + if (line.startsWith('#') || line.isEmpty()) + continue; + QVERIFY(!line.contains('#')); + + QList parts = line.split(';'); + QVERIFY(parts.size() == 5); + + QString data; + QList dataParts = parts.at(0).split(' '); + for (const auto &p : dataParts) { + bool ok; + data += QChar((ushort)p.toInt(&ok, 16)); + QVERIFY(ok); + } + + int paragraphDirection = parts.at(1).toInt(); +// int resolvedParagraphLevel = parts.at(2).toInt(); + + QVector resolvedLevels; + QList levelParts = parts.at(3).split(' '); + for (const auto &p : levelParts) { + if (p == "x") { + resolvedLevels += -1; + } else { + bool ok; + resolvedLevels += p.toInt(&ok); + QVERIFY(ok); + } + } + + QVector visualOrder; + QList orderParts = parts.at(4).split(' '); + for (const auto &p : orderParts) { + bool ok; + visualOrder += p.toInt(&ok); + QVERIFY(ok); + } + + const QByteArray nm = "line #" + QByteArray::number(linenum); + + testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); + } } ushort unicodeForDirection(const QByteArray &direction) @@ -466,13 +450,8 @@ ushort unicodeForDirection(const QByteArray &direction) Q_UNREACHABLE(); } -void tst_QComplexText::bidiTest_data() +void tst_QComplexText::bidiTest() { - QTest::addColumn("data"); - QTest::addColumn("paragraphDirection"); - QTest::addColumn>("resolvedLevels"); - QTest::addColumn>("visualOrder"); - QString testFile = QFINDTESTDATA("data/BidiTest.txt"); QFile f(testFile); QVERIFY(f.exists()); @@ -534,24 +513,13 @@ void tst_QComplexText::bidiTest_data() const QByteArray nm = "line #" + QByteArray::number(linenum); if (paragraphDirections & 1) - QTest::newRow((nm + " (Auto)").constData()) << data << 2 << resolvedLevels << visualOrder; + testBidiString(data, 2, resolvedLevels, visualOrder); if (paragraphDirections & 2) - QTest::newRow((nm + " (LTR)").constData()) << data << 0 << resolvedLevels << visualOrder; + testBidiString(data, 0, resolvedLevels, visualOrder); if (paragraphDirections & 4) - QTest::newRow((nm + " (RTL)").constData()) << data << 1 << resolvedLevels << visualOrder; + testBidiString(data, 1, resolvedLevels, visualOrder); } - -} - -void tst_QComplexText::bidiTest() -{ - QFETCH(QString, data); - QFETCH(int, paragraphDirection); - QFETCH(QVector, resolvedLevels); - QFETCH(QVector, visualOrder); - - testBidiString(data, paragraphDirection, resolvedLevels, visualOrder); }