diff options
35 files changed, 660 insertions, 206 deletions
diff --git a/dist/changes-5.11.1 b/dist/changes-5.11.1 new file mode 100644 index 0000000000..ed219df454 --- /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. diff --git a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings index 08de0be8d3..a3f43a8b38 100644 --- a/mkspecs/macx-xcode/WorkspaceSettings.xcsettings +++ b/mkspecs/macx-xcode/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> + <key>BuildSystemType</key> + <string>Original</string> <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key> <false/> </dict> diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 18b62c5135..80891e682f 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"); diff --git a/src/corelib/Qt5CoreMacros.cmake b/src/corelib/Qt5CoreMacros.cmake index 1627de4002..819b48f973 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/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index ff0e03108b..cacb95b674 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(__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 +# if !defined(MAC_OS_X_VERSION_10_14) +# define MAC_OS_X_VERSION_10_14 101400 # 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__ diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index ca8bd30698..c528b16f9c 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 c29c4dfc14..6b11e90a4e 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -44,6 +44,10 @@ #include <AppKit/NSText.h> #endif +#if defined(QT_PLATFORM_UIKIT) +#include <UIKit/UIKit.h> +#endif + #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -189,6 +193,43 @@ AppleApplication *qt_apple_sharedApplication() } #endif +#if defined(Q_OS_MACOS) && !defined(QT_BOOTSTRAPPED) +bool qt_apple_isSandboxed() +{ + static bool isSandboxed = []() { + QCFType<SecStaticCodeRef> staticCode = nullptr; + NSURL *bundleUrl = [[NSBundle mainBundle] bundleURL]; + if (SecStaticCodeCreateWithPath((__bridge CFURLRef)bundleUrl, + kSecCSDefaultFlags, &staticCode) != errSecSuccess) + return false; + + QCFType<SecRequirementRef> 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 9bd2e31bc9..af939abaac 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/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c73dac42d6..2ef689b5b9 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 diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 15c141448d..057a4c2943 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()); + + // 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(maximizedRect); + return QCocoaScreen::mapToNative(maximizedFrame); } - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro index 6eb9f2c534..71257d09f7 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 cc76d198f5..bf4e9cc900 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 5987bc1540..e8a3f5b30e 100644 --- a/src/plugins/platforms/ios/qiosfiledialog.mm +++ b/src/plugins/platforms/ios/qiosfiledialog.mm @@ -43,6 +43,8 @@ #include <QtGui/qwindow.h> #include <QDebug> +#include <QtCore/private/qcore_mac_p.h> + #include "qiosfiledialog.h" #include "qiosintegration.h" #include "qiosoptionalplugininterface.h" @@ -94,7 +96,7 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent) } UIWindow *window = parent ? reinterpret_cast<UIView *>(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 f27b2242df..a523d1be45 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 <QtCore/private/qcore_mac_p.h> + 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 050c592aca..493c283ec1 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 <QtCore/private/qcore_mac_p.h> + #include <QGuiApplication> #include <QtGui/private/qwindow_p.h> @@ -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<UIWindow *, UIWindowLevel> 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 b8ce49aaca..ed2bfbc0d8 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 9d05b792c2..a7de9b473a 100644 --- a/src/plugins/platforms/ios/qiosmessagedialog.mm +++ b/src/plugins/platforms/ios/qiosmessagedialog.mm @@ -43,6 +43,8 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatformtheme.h> +#include <QtCore/private/qcore_mac_p.h> + #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<UIView *>(parent->winId()).window : [UIApplication sharedApplication].keyWindow; + UIWindow *window = parent ? reinterpret_cast<UIView *>(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 c394592d76..f367d1e75e 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 <QtCore/private/qcore_mac_p.h> + #include <QtGui/private/qwindow_p.h> #include <private/qcoregraphics_p.h> @@ -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<QIOSViewController *>(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 3c44e1d7d6..7222bf6793 100644 --- a/src/plugins/platforms/ios/qiosservices.mm +++ b/src/plugins/platforms/ios/qiosservices.mm @@ -40,6 +40,9 @@ #include "qiosservices.h" #include <QtCore/qurl.h> +#include <QtCore/qdebug.h> +#include <QtCore/private/qcore_mac_p.h> + #include <QtGui/qdesktopservices.h> #import <UIKit/UIApplication.h> @@ -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 fe3c29d037..87c282e24a 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -46,6 +46,7 @@ #include <QtGui/private/qinputmethod_p.h> #include <QtCore/private/qobject_p.h> +#include <QtCore/private/qcore_mac_p.h> #include "qiosglobal.h" #include "qiostextinputoverlay.h" @@ -475,7 +476,7 @@ static void executeBlockWithoutAnimation(Block block) if (enabled) { _focusView = [reinterpret_cast<UIView *>(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 91980d3f35..5534264a60 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -41,6 +41,7 @@ #include <QtCore/QStringList> #include <QtCore/QVariant> +#include <QtCore/private/qcore_mac_p.h> #include <QtGui/QFont> @@ -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 d7db6ba856..aa909d6f63 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -41,6 +41,7 @@ #import "qiosviewcontroller.h" #include <QtCore/qscopedvaluerollback.h> +#include <QtCore/private/qcore_mac_p.h> #include <QtGui/QGuiApplication> #include <QtGui/QWindow> @@ -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(); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 8cfcc49f9a..b81cb8efa1 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<uint32_t>::max())) { - qWarning("QXcbShmImage: xcb_shm_create_segment() can't be called for size %zu, maximum allowed size is %u", - segmentSize, std::numeric_limits<uint32_t>::max()); + qCWarning(lcQpaXcb, "xcb_shm_create_segment() can't be called for size %zu, maximum" + "allowed size is %u", segmentSize, std::numeric_limits<uint32_t>::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,47 +362,54 @@ void QXcbBackingStoreImage::createShmSegment(size_t segmentSize) close(fds[0]); m_shm_info.shmseg = seg; m_shm_info.shmaddr = static_cast<quint8 *>(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"); + if (createSystemVShmSegment(connection(), segmentSize, &m_shm_info)) + m_segmentSize = segmentSize; + } +} - 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; - } +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; + } - m_shm_info.shmseg = seg; - m_shm_info.shmid = id; // unused - m_shm_info.shmaddr = static_cast<quint8 *>(addr); + 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; + } - m_segmentSize = segmentSize; + 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<quint8 *>(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<quint8 *>(addr); } + return true; } void QXcbBackingStoreImage::destroyShmSegment(size_t segmentSize) @@ -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<xcb_shm_segment_info_t *>(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<QXcbWindow *>(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 747626c213..734de1f7d7 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<QRegion> m_paintRegions; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 879d31f29a..5fd1fc6a47 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 <QSocketNotifier> #include <QAbstractEventDispatcher> @@ -585,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) @@ -973,7 +975,7 @@ void QXcbConnection::printXcbError(const char *message, xcb_generic_error_t *err uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1); uint clamped_major_code = qMin<uint>(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), @@ -1683,12 +1685,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<xXIDeviceEvent *>(event); + // Xlib's XI2 events need memmove, see xi2PrepareXIGenericDeviceEvent() + auto sourceId = *reinterpret_cast<uint16_t *>(reinterpret_cast<char *>(&xdev->sourceid) + 4); if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && - const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid)) + const_cast<QXcbConnection *>(this)->tabletDataForDevice(sourceId)) return false; #endif // QT_CONFIG(tabletevent) for (int j = nextIndex; j < eventqueue->size(); ++j) { @@ -2101,20 +2105,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<QLoggingCategory*>(&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() diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index e1bd8eb752..df458e85d7 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); diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 5999163c91..2d212bfe3b 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<NSComboBox *>(cc); const auto frameRect = cw.adjustedControlFrame(combo->rect); cb.frame = frameRect.toCGRect(); -#if !QT_CONFIG(appstore_compliant) - static_cast<NSComboBoxCell *>(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<NSButtonCell *>([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]; diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index cef1d1b6da..fdf21fb499 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<QAbstractDeclarativeDataImpl*>(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/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 00e9ff7400..9a8206de45 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/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 41f9d69c12..5f1f6d880a 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<QAbstractDeclarativeDataImpl*>(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; diff --git a/tests/auto/cmake/CMakeLists.txt b/tests/auto/cmake/CMakeLists.txt index f1d8657091..ec75ec7caf 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 0000000000..be05c75054 --- /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 0000000000..507cc8479d --- /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 <stephen.kelly@kdab.com> +** 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 <QtTest> +#include <QWindow> + +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 0000000000..44eb7fe96e --- /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 <stephen.kelly@kdab.com> +** 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 <QtTest> + +class Two : public QObject +{ + Q_OBJECT +public: + Two(QObject *parent = 0) + { + + } +}; + +QTEST_MAIN(Two) + +#include "two.moc" diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index fd83228c8b..0dd98cf61c 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -43,6 +43,7 @@ #include <qtreewidget.h> #include <qdebug.h> #include <qscreen.h> +#include <qdesktopwidget.h> typedef QList<int> 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<QStatusTipEvent *>(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" |