From f4fff02cbb1f9399f407c15a27741c6cd1a17133 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Mon, 10 Oct 2016 16:09:32 +0200 Subject: QXcbShmImage: don't use shmget()'s return unless it succeeds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When shmget() failed, we didn't set m_shm_info.shmid (not even to the -1 failure id) but did pass it (i.e. uninitialized noise) to shmat(), among other related functions. Guard against this; handle failure gracefully. Task-number: QTBUG-56419 Change-Id: Ie823c36c2ede03af6cb5d94ce7b4b5cd543c1008 Reviewed-by: Timur Pocheptsov Reviewed-by: Błażej Szczygieł Reviewed-by: Shawn Rutledge Reviewed-by: Joni Poikelin Reviewed-by: Laszlo Agocs --- src/plugins/platforms/xcb/qxcbbackingstore.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 3b04c59e28..0b76830d8e 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -150,12 +150,13 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI return; int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0600); - if (id == -1) + if (id == -1) { qWarning("QXcbShmImage: shmget() failed (%d: %s) for size %d (%dx%d)", errno, strerror(errno), segmentSize, size.width(), size.height()); - else - m_shm_info.shmid = id; - m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); + } else { + m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat(id, 0, 0); + } + m_shm_info.shmid = id; m_shm_info.shmseg = xcb_generate_id(xcb_connection()); const xcb_query_extension_reply_t *shm_reply = xcb_get_extension_data(xcb_connection(), &xcb_shm_id); @@ -166,9 +167,10 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI if (!shm_present || error || id == -1) { free(error); - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); - + if (id != -1) { + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + } m_shm_info.shmaddr = 0; m_xcb_image->data = (uint8_t *)malloc(segmentSize); -- cgit v1.2.3 From dde86ebb9b020811a731a180c4f4d98f3b60728b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 6 Oct 2016 18:34:10 +0200 Subject: Android: Don't update offscreen windows Offscreen windows should not be handle by the platform plugin. Task-number: QTBUG-50973 Change-Id: I719a24b9bbcaad460d78fdc4095e86d615357cd2 Reviewed-by: Laszlo Agocs --- src/plugins/platforms/android/androidjnimain.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index fe2401f561..69c590940f 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -621,7 +621,12 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) if (QGuiApplication::instance() != nullptr) { foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - QRect availableGeometry = w->screen()->availableGeometry(); + + // Skip non-platform windows, e.g., offscreen windows. + if (!w->handle()) + continue; + + QRect availableGeometry = w->screen()->availableGeometry(); if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size()))); } -- cgit v1.2.3 From e9110b162cad1c07341fa3ed424484a58f9c642a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 14 Oct 2016 16:44:47 +0200 Subject: iOS: Report correct physical DPI for iPhone 7 Plus Task-number: QTBUG-56509 Change-Id: Ibae94262c2a4c917aeca00cb1a1c28e5ae60f0c4 Reviewed-by: Jake Petroules --- src/plugins/platforms/ios/qiosscreen.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 4018a02f8d..7d1c01f36b 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -201,8 +201,8 @@ QIOSScreen::QIOSScreen(UIScreen *screen) else m_depth = 24; - if (deviceIdentifier.contains(QRegularExpression("^iPhone(7,1|8,2)$"))) { - // iPhone 6 Plus or iPhone 6S Plus + if (deviceIdentifier.contains(QRegularExpression("^iPhone(7,1|8,2|9,2|9,4)$"))) { + // iPhone Plus models m_physicalDpi = 401; } else if (deviceIdentifier.contains(QRegularExpression("^iPad(1,1|2,[1-4]|3,[1-6]|4,[1-3]|5,[3-4]|6,[7-8])$"))) { // All iPads except the iPad Mini series -- cgit v1.2.3 From b00565bc2803bb783e8f2b0d02becfa73323e283 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 15 Jun 2016 14:07:33 +0200 Subject: iOS: check if qApp is still valid before accessing it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the application quits, the iOS plugin can be told to delete after qApp has been set to null. So we need to add a check for this, to avoid error messages. Change-Id: I687e0b26e0c54fdd5a8539fe0f31b2e756ea92d8 Reviewed-by: Tor Arne Vestbø Reviewed-by: Jake Petroules --- src/plugins/platforms/ios/qiostextinputoverlay.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index d930965bde..54c2e98d71 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -994,7 +994,8 @@ QIOSTextInputOverlay::QIOSTextInputOverlay() QIOSTextInputOverlay::~QIOSTextInputOverlay() { - disconnect(qApp, 0, this, 0); + if (qApp) + disconnect(qApp, 0, this, 0); } void QIOSTextInputOverlay::updateFocusObject() -- cgit v1.2.3 From 4a4368df5663729a34761c394a6f02b72071e89c Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Tue, 18 Oct 2016 13:17:53 +0300 Subject: QAndroidPlatformTheme: wrap char* in QL1S to avoid warnings Change-Id: Idcc70038051b03366aa447f3a4c48912d3f911d5 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/android/qandroidplatformtheme.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index 9350a15721..801bb78436 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -458,9 +458,9 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const case StyleNames: if (qEnvironmentVariableIntValue("QT_USE_ANDROID_NATIVE_STYLE") && m_androidStyleData) { - return QStringList("android"); + return QStringList(QLatin1String("android")); } - return QStringList("fusion"); + return QStringList(QLatin1String("fusion")); case MouseDoubleClickDistance: { -- cgit v1.2.3 From ee22c6505a1f7cf52a862b1bd9219511db893417 Mon Sep 17 00:00:00 2001 From: Clinton Stimpson Date: Tue, 30 Aug 2016 07:52:17 -0600 Subject: xcb: fix passing of focus from child to its top level QWindow With the client message _NET_ACTIVE_WINDOW, not all window managers will pass focus from a child window to its root window, Detect this child-to-root case, and use xcb_set_input_focus() instead. Task-number: QTBUG-39362 Change-Id: Ib32193018e3b725b323f87d7306c9ae9493d78a7 Reviewed-by: Shawn Rutledge Reviewed-by: Edward Welbourne Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/xcb/qxcbwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5f402b6eca..25a8b41195 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1698,9 +1698,11 @@ void QXcbWindow::requestActivateWindow() m_deferredActivation = false; updateNetWmUserTime(connection()->time()); + QWindow *focusWindow = QGuiApplication::focusWindow(); if (window()->isTopLevel() && !(window()->flags() & Qt::X11BypassWindowManagerHint) + && (!focusWindow || !window()->isAncestorOf(focusWindow)) && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) { xcb_client_message_event_t event; @@ -1711,7 +1713,6 @@ void QXcbWindow::requestActivateWindow() event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW); event.data.data32[0] = 1; event.data.data32[1] = connection()->time(); - QWindow *focusWindow = QGuiApplication::focusWindow(); event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE; event.data.data32[3] = 0; event.data.data32[4] = 0; -- cgit v1.2.3 From cd081ca96a5387abe36f46a347363e07edcdcd67 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Mon, 19 Sep 2016 12:13:33 +0200 Subject: macOS: Only show menu and allow dragging on proxy when a file path is set If there is no file path set then it should not be possible to see a menu or to drag from a proxy icon in the titlebar. Task-number: QTBUG-56082 Change-Id: Ib8305bcab5717bc8cb7ddabbb079f152debbdded Reviewed-by: Jake Petroules --- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 2 ++ src/plugins/platforms/cocoa/qnswindowdelegate.h | 3 ++- src/plugins/platforms/cocoa/qnswindowdelegate.mm | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 9fcb221d37..9cf6328281 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -346,6 +346,7 @@ public: // for QNSView // This object is tracked by QCocoaWindowPointer, // preventing the use of dangling pointers. QObject sentinel; + bool m_hasWindowFilePath; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c0d5904367..977a5ae657 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -379,6 +379,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_topContentBorderThickness(0) , m_bottomContentBorderThickness(0) , m_normalGeometry(QRect(0,0,-1,-1)) + , m_hasWindowFilePath(false) { #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; @@ -941,6 +942,7 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) QFileInfo fi(filePath); [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; + m_hasWindowFilePath = fi.exists(); } void QCocoaWindow::setWindowIcon(const QIcon &icon) diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index b8d344aa0e..a5f3dca68c 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -51,7 +51,8 @@ - (void)windowWillMove:(NSNotification *)notification; - (BOOL)windowShouldClose:(NSNotification *)notification; - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; - +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; +- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSWindowDelegate); diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 015274cac7..a26f381ddb 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -109,4 +109,19 @@ return YES; } +- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu +{ + Q_UNUSED(window); + Q_UNUSED(menu); + return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; +} + +- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard +{ + Q_UNUSED(window); + Q_UNUSED(event); + Q_UNUSED(dragImageLocation); + Q_UNUSED(pasteboard); + return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; +} @end -- cgit v1.2.3 From b6df7257501b54521c25587c3c5e600b2c9393d1 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 20 Oct 2016 18:31:10 +0200 Subject: Fix UB (ininited pointer read) in qt_egl_device_integration() The m_integration member of DeviceIntegration, a naked pointer, was checked for nullptr in the DeviceIntegration ctor, but never set to nullptr. Fix by init'ing it to nullptr in the ctor-init-list. Coverity-Id: 172056 Change-Id: Ia1dc9b67b9d16a991bba82338eedb19de68f91d8 Reviewed-by: Thiago Macieira --- src/plugins/platforms/eglfs/qeglfshooks.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/qeglfshooks.cpp b/src/plugins/platforms/eglfs/qeglfshooks.cpp index cf016d1b01..638960d998 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks.cpp @@ -61,6 +61,7 @@ private: Q_GLOBAL_STATIC(DeviceIntegration, deviceIntegration) DeviceIntegration::DeviceIntegration() + : m_integration(Q_NULLPTR) { QStringList pluginKeys = QEGLDeviceIntegrationFactory::keys(); if (!pluginKeys.isEmpty()) { -- cgit v1.2.3 From 10b9321c1dc19236620ba20bdf54cae73891d1ef Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Wed, 19 Oct 2016 15:30:58 +0300 Subject: qxcbconnection.cpp: fix warning about unused function isXIEvent() is used iff XCB_USE_XINPUT2 is defined. So move declaration of the function in XCB_USE_XINPUT2 define scope. Change-Id: I6f045cd07d572ee7425ee6edc5ac73dcf0afdb37 Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/plugins/platforms/xcb/qxcbconnection.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index c533a2a5f5..3d808d1d37 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -110,6 +110,7 @@ Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen") #define XCB_GE_GENERIC 35 #endif +#if defined(XCB_USE_XINPUT2) // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" // - "pad1" and "pad" became "pad0" @@ -127,6 +128,7 @@ static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; return e->extension == opCode; } +#endif // XCB_USE_XINPUT2 #ifdef XCB_USE_XLIB static const char * const xcbConnectionErrors[] = { -- cgit v1.2.3 From 391741bd7b9d07a6c3fd2e5c0bc70d3c00f29ac8 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 19 Oct 2016 17:50:52 +0200 Subject: Cocoa integration - remove erroneous warning The conditional statement checks/allows only right/left mouse buttons in handleMouseDraggedEvent and generates a lot of useless/misleading warnings in case we press (for example) a middle mouse button (when we're also moving mouse cursor, intentionally or not). Task-number: QTBUG-54160 Task-number: QTBUG-42846 Change-Id: I5c54b6204cb90036c7d98724537f1c985b40d9cc Reviewed-by: Shawn Rutledge --- src/plugins/platforms/cocoa/qnsview.mm | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 51a69be759..0e46c3150b 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -892,11 +892,6 @@ QT_WARNING_POP if (!(m_acceptedMouseDowns & button) == button) return false; - if (!(m_buttons & (m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton))) { - qCWarning(lcQpaCocoaWindow) << "QNSView mouseDragged: Internal mouse button tracking" - << "invalid (missing Qt::LeftButton)"; - } - [self handleMouseEvent:theEvent]; return true; } -- cgit v1.2.3 From 9c83d7f871f95b1cc03fb404bd602df32056b9cb Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 30 Sep 2016 15:39:03 -0700 Subject: QCocoaMenuBar: Update even if no window is attached Then we need to check if the current active (or focused) window has any menubar associated. In case there isn't, and the menubar has no window associated, then we should update immediately. The previous condition is still valid. Change-Id: I4532ccc87354d91c76b53f5433dc3944b9e29584 Task-number: QTBUG-56275 Reviewed-by: Erik Verbruggen --- src/plugins/platforms/cocoa/qcocoamenubar.h | 1 + src/plugins/platforms/cocoa/qcocoamenubar.mm | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index e84da7aeb0..2865dd2460 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -70,6 +70,7 @@ private: static QCocoaWindow *findWindowForMenubar(); static QCocoaMenuBar *findGlobalMenubar(); + bool needsImmediateUpdate(); bool shouldDisable(QCocoaWindow *active) const; NSMenuItem *nativeItemForMenu(QCocoaMenu *menu) const; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 3523182e6d..82aebf8cf3 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -89,6 +89,32 @@ QCocoaMenuBar::~QCocoaMenuBar() } } +bool QCocoaMenuBar::needsImmediateUpdate() +{ + if (m_window && m_window->window()->isActive()) { + return true; + } else if (!m_window) { + // Only update if the focus/active window has no + // menubar, which means it'll be using this menubar. + // This is to avoid a modification in a parentless + // menubar to affect a window-assigned menubar. + QWindow *fw = QGuiApplication::focusWindow(); + if (!fw) { + // Same if there's no focus window, BTW. + return true; + } else { + QCocoaWindow *cw = static_cast(fw->handle()); + if (cw && !cw->menubar()) + return true; + } + } + + // Either the menubar is attached to a non-active window, + // or the application's focus window has its own menubar + // (which is different from this one) + return false; +} + void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *before) { QCocoaMenu *menu = static_cast(platformMenu); @@ -129,7 +155,7 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor syncMenu(menu); - if (m_window && m_window->window()->isActive()) + if (needsImmediateUpdate()) updateMenuBarImmediately(); } -- cgit v1.2.3 From 99ce5d5e85007cb656cd48ab161be14af8f16238 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 28 Sep 2016 13:58:56 +0200 Subject: iOS: refactor usage of photos into optional plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starting from iOS 10, apps that tries to access photos on the device need to specify the reason for this up front by adding the key 'NSPhotoLibraryUsageDescription' into Info.plist. If the key is missing, the app will be rejected from AppStore. This causes problems for the iOS plugin as it stands since parts of it already tries to access photos, e.g to show an image picker dialog if a file dialog is set to open QStandardPaths::PicturesLocation. This means that currently, all apps written with Qt will be rejected from AppStore unless the developer adds this key, whether he tries to access photos or not. To solve this, we choose to split the plugin into two parts, one that contains the core functionality, and one that contains optional support. The latter will need to be enabled explicit by the developer in the pro file, or in this case, indirectly by adding the right key to the Info.plist. This patch refactors the code in the plugin that gives access to photos into a separate optional plugin called 'nsphotolibrarysupport'. Change-Id: Ic4351eb0bbfffdf840fd88cd00bb29a25907798f Reviewed-by: Tor Arne Vestbø Reviewed-by: Jake Petroules --- src/plugins/platforms/ios/ios.pro | 63 +-- src/plugins/platforms/ios/kernel.pro | 58 +++ .../nsphotolibrarysupport.pro | 22 + .../ios/optional/nsphotolibrarysupport/plugin.json | 3 + .../ios/optional/nsphotolibrarysupport/plugin.mm | 64 +++ .../qiosfileengineassetslibrary.h | 76 ++++ .../qiosfileengineassetslibrary.mm | 469 +++++++++++++++++++++ .../nsphotolibrarysupport/qiosfileenginefactory.h | 55 +++ .../qiosimagepickercontroller.h | 42 ++ .../qiosimagepickercontroller.mm | 66 +++ src/plugins/platforms/ios/optional/optional.pro | 2 + src/plugins/platforms/ios/qiosfiledialog.h | 2 + src/plugins/platforms/ios/qiosfiledialog.mm | 79 ++-- .../platforms/ios/qiosfileengineassetslibrary.h | 76 ---- .../platforms/ios/qiosfileengineassetslibrary.mm | 469 --------------------- src/plugins/platforms/ios/qiosfileenginefactory.h | 55 --- src/plugins/platforms/ios/qiosintegration.h | 7 +- src/plugins/platforms/ios/qiosintegration.mm | 8 + .../platforms/ios/qiosoptionalplugininterface.h | 59 +++ 19 files changed, 966 insertions(+), 709 deletions(-) create mode 100644 src/plugins/platforms/ios/kernel.pro create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.json create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h create mode 100644 src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm create mode 100644 src/plugins/platforms/ios/optional/optional.pro delete mode 100644 src/plugins/platforms/ios/qiosfileengineassetslibrary.h delete mode 100644 src/plugins/platforms/ios/qiosfileengineassetslibrary.mm delete mode 100644 src/plugins/platforms/ios/qiosfileenginefactory.h create mode 100644 src/plugins/platforms/ios/qiosoptionalplugininterface.h (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index 545db8c093..594ccefcf1 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -1,61 +1,2 @@ -TARGET = qios - -QT += core-private gui-private platformsupport-private -LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AssetsLibrary - -OBJECTIVE_SOURCES = \ - plugin.mm \ - qiosintegration.mm \ - qioseventdispatcher.mm \ - qioswindow.mm \ - qiosscreen.mm \ - qiosbackingstore.mm \ - qiosapplicationdelegate.mm \ - qiosapplicationstate.mm \ - qiosviewcontroller.mm \ - qioscontext.mm \ - qiosinputcontext.mm \ - qiostheme.mm \ - qiosglobal.mm \ - qiosservices.mm \ - quiview.mm \ - qiosclipboard.mm \ - quiaccessibilityelement.mm \ - qiosplatformaccessibility.mm \ - qiostextresponder.mm \ - qiosmenu.mm \ - qiosfileengineassetslibrary.mm \ - qiosfiledialog.mm - -HEADERS = \ - qiosintegration.h \ - qioseventdispatcher.h \ - qioswindow.h \ - qiosscreen.h \ - qiosbackingstore.h \ - qiosapplicationdelegate.h \ - qiosapplicationstate.h \ - qiosviewcontroller.h \ - qioscontext.h \ - qiosinputcontext.h \ - qiostheme.h \ - qiosglobal.h \ - qiosservices.h \ - quiview.h \ - qiosclipboard.h \ - quiaccessibilityelement.h \ - qiosplatformaccessibility.h \ - qiostextresponder.h \ - qiosmenu.h \ - qiosfileenginefactory.h \ - qiosfileengineassetslibrary.h \ - qiosfiledialog.h - -OTHER_FILES = \ - quiview_textinput.mm \ - quiview_accessibility.mm - -PLUGIN_TYPE = platforms -PLUGIN_CLASS_NAME = QIOSIntegrationPlugin -!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -load(qt_plugin) +TEMPLATE = subdirs +SUBDIRS = kernel.pro optional diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro new file mode 100644 index 0000000000..84035877c5 --- /dev/null +++ b/src/plugins/platforms/ios/kernel.pro @@ -0,0 +1,58 @@ +TARGET = qios + +QT += core-private gui-private platformsupport-private +LIBS += -framework Foundation -framework UIKit -framework QuartzCore + +OBJECTIVE_SOURCES = \ + plugin.mm \ + qiosintegration.mm \ + qioseventdispatcher.mm \ + qioswindow.mm \ + qiosscreen.mm \ + qiosbackingstore.mm \ + qiosapplicationdelegate.mm \ + qiosapplicationstate.mm \ + qiosviewcontroller.mm \ + qioscontext.mm \ + qiosinputcontext.mm \ + qiostheme.mm \ + qiosglobal.mm \ + qiosservices.mm \ + quiview.mm \ + qiosclipboard.mm \ + quiaccessibilityelement.mm \ + qiosplatformaccessibility.mm \ + qiostextresponder.mm \ + qiosmenu.mm \ + qiosfiledialog.mm + +HEADERS = \ + qiosintegration.h \ + qioseventdispatcher.h \ + qioswindow.h \ + qiosscreen.h \ + qiosbackingstore.h \ + qiosapplicationdelegate.h \ + qiosapplicationstate.h \ + qiosviewcontroller.h \ + qioscontext.h \ + qiosinputcontext.h \ + qiostheme.h \ + qiosglobal.h \ + qiosservices.h \ + quiview.h \ + qiosclipboard.h \ + quiaccessibilityelement.h \ + qiosplatformaccessibility.h \ + qiostextresponder.h \ + qiosmenu.h \ + qiosfiledialog.h + +OTHER_FILES = \ + quiview_textinput.mm \ + quiview_accessibility.mm + +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = QIOSIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - +load(qt_plugin) diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro new file mode 100644 index 0000000000..f4588dda03 --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/nsphotolibrarysupport.pro @@ -0,0 +1,22 @@ +TARGET = qiosnsphotolibrarysupport + +QT += core gui gui-private +LIBS += -framework UIKit -framework AssetsLibrary + +HEADERS = \ + qiosfileengineassetslibrary.h \ + qiosfileenginefactory.h \ + qiosimagepickercontroller.h + +OBJECTIVE_SOURCES = \ + plugin.mm \ + qiosfileengineassetslibrary.mm \ + qiosimagepickercontroller.mm \ + +OTHER_FILES = \ + plugin.json + +PLUGIN_CLASS_NAME = QIosOptionalPlugin_NSPhotoLibrary +PLUGIN_EXTENDS = - +PLUGIN_TYPE = platforms/darwin +load(qt_plugin) diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.json b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.json new file mode 100644 index 0000000000..4491fb3d59 --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "NSPhotoLibrarySupport" ] +} diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm new file mode 100644 index 0000000000..2ec0d33a41 --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/plugin.mm @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../../qiosoptionalplugininterface.h" +#include "../../qiosfiledialog.h" + +#include "qiosimagepickercontroller.h" +#include "qiosfileenginefactory.h" + +QT_BEGIN_NAMESPACE + +class QIosOptionalPlugin_NSPhotoLibrary : public QObject, QIosOptionalPluginInterface +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QIosOptionalPluginInterface_iid FILE "plugin.json") + Q_INTERFACES(QIosOptionalPluginInterface) + +public: + explicit QIosOptionalPlugin_NSPhotoLibrary(QObject* = 0) {}; + ~QIosOptionalPlugin_NSPhotoLibrary() {} + + UIViewController* createImagePickerController(QIOSFileDialog *fileDialog) const override + { + return [[[QIOSImagePickerController alloc] initWithQIOSFileDialog:fileDialog] autorelease]; + } + +private: + QIOSFileEngineFactory m_fileEngineFactory; + +}; + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h new file mode 100644 index 0000000000..0e29a1003e --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSFILEENGINEASSETSLIBRARY_H +#define QIOSFILEENGINEASSETSLIBRARY_H + +#include + +Q_FORWARD_DECLARE_OBJC_CLASS(ALAsset); +class QIOSAssetData; + +class QIOSFileEngineAssetsLibrary : public QAbstractFileEngine +{ +public: + QIOSFileEngineAssetsLibrary(const QString &fileName); + ~QIOSFileEngineAssetsLibrary(); + + bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE; + bool close() Q_DECL_OVERRIDE; + FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE; + qint64 size() const Q_DECL_OVERRIDE; + qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; + qint64 pos() const Q_DECL_OVERRIDE; + bool seek(qint64 pos) Q_DECL_OVERRIDE; + QString fileName(FileName file) const Q_DECL_OVERRIDE; + void setFileName(const QString &file) Q_DECL_OVERRIDE; + QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE; + +#ifndef QT_NO_FILESYSTEMITERATOR + Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; + Iterator *endEntryList() Q_DECL_OVERRIDE; +#endif + + void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); } + +private: + QString m_fileName; + QString m_assetUrl; + qint64 m_offset; + mutable QIOSAssetData *m_data; + + ALAsset *loadAsset() const; +}; + +#endif // QIOSFILEENGINEASSETSLIBRARY_H + diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm new file mode 100644 index 0000000000..2e88c37c01 --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm @@ -0,0 +1,469 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiosfileengineassetslibrary.h" + +#import +#import + +#include +#include +#include +#include +#include + +static QThreadStorage g_iteratorCurrentUrl; +static QThreadStorage > g_assetDataCache; + +static const int kBufferSize = 10; +static ALAsset *kNoAsset = 0; + +static bool ensureAuthorizationDialogNotBlocked() +{ + if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusNotDetermined) + return true; + + if (static_cast(QObjectPrivate::get(qApp))->in_exec) + return true; + + if ([NSThread isMainThread]) { + // The dialog is about to show, but since main has not finished, the dialog will be held + // back until the launch completes. This is problematic since we cannot successfully return + // back to the caller before the asset is ready, which also includes showing the dialog. To + // work around this, we create an event loop to that will complete the launch (return from the + // applicationDidFinishLaunching callback). But this will only work if we're on the main thread. + QEventLoop loop; + QTimer::singleShot(1, &loop, &QEventLoop::quit); + loop.exec(); + } else { + NSLog(@"QIOSFileEngine: unable to show assets authorization dialog from non-gui thread before QApplication is executing."); + return false; + } + + return true; +} + +// ------------------------------------------------------------------------- + +class QIOSAssetEnumerator +{ +public: + QIOSAssetEnumerator(ALAssetsLibrary *assetsLibrary, ALAssetsGroupType type) + : m_semWriteAsset(dispatch_semaphore_create(kBufferSize)) + , m_semReadAsset(dispatch_semaphore_create(0)) + , m_stop(false) + , m_assetsLibrary([assetsLibrary retain]) + , m_type(type) + , m_buffer(QVector(kBufferSize)) + , m_readIndex(0) + , m_writeIndex(0) + , m_nextAssetReady(false) + { + if (!ensureAuthorizationDialogNotBlocked()) + writeAsset(kNoAsset); + else + startEnumerate(); + } + + ~QIOSAssetEnumerator() + { + m_stop = true; + + // Flush and autorelease remaining assets in the buffer + while (hasNext()) + next(); + + // Documentation states that we need to balance out calls to 'wait' + // and 'signal'. Since the enumeration function always will be one 'wait' + // ahead, we need to signal m_semProceedToNextAsset one last time. + dispatch_semaphore_signal(m_semWriteAsset); + dispatch_release(m_semReadAsset); + dispatch_release(m_semWriteAsset); + + [m_assetsLibrary autorelease]; + } + + bool hasNext() + { + if (!m_nextAssetReady) { + dispatch_semaphore_wait(m_semReadAsset, DISPATCH_TIME_FOREVER); + m_nextAssetReady = true; + } + return m_buffer[m_readIndex] != kNoAsset; + } + + ALAsset *next() + { + Q_ASSERT(m_nextAssetReady); + Q_ASSERT(m_buffer[m_readIndex]); + + ALAsset *asset = [m_buffer[m_readIndex] autorelease]; + dispatch_semaphore_signal(m_semWriteAsset); + + m_readIndex = (m_readIndex + 1) % kBufferSize; + m_nextAssetReady = false; + return asset; + } + +private: + dispatch_semaphore_t m_semWriteAsset; + dispatch_semaphore_t m_semReadAsset; + std::atomic_bool m_stop; + + ALAssetsLibrary *m_assetsLibrary; + ALAssetsGroupType m_type; + QVector m_buffer; + int m_readIndex; + int m_writeIndex; + bool m_nextAssetReady; + + void writeAsset(ALAsset *asset) + { + dispatch_semaphore_wait(m_semWriteAsset, DISPATCH_TIME_FOREVER); + m_buffer[m_writeIndex] = [asset retain]; + dispatch_semaphore_signal(m_semReadAsset); + m_writeIndex = (m_writeIndex + 1) % kBufferSize; + } + + void startEnumerate() + { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [m_assetsLibrary enumerateGroupsWithTypes:m_type usingBlock:^(ALAssetsGroup *group, BOOL *stopEnumerate) { + + if (!group) { + writeAsset(kNoAsset); + return; + } + + if (m_stop) { + *stopEnumerate = true; + return; + } + + [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stopEnumerate) { + Q_UNUSED(index); + if (!asset || ![[asset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) + return; + + writeAsset(asset); + *stopEnumerate = m_stop; + }]; + } failureBlock:^(NSError *error) { + NSLog(@"QIOSFileEngine: %@", error); + writeAsset(kNoAsset); + }]; + }); + } + +}; + +// ------------------------------------------------------------------------- + +class QIOSAssetData : public QObject +{ +public: + QIOSAssetData(const QString &assetUrl, QIOSFileEngineAssetsLibrary *engine) + : m_asset(0) + , m_assetUrl(assetUrl) + , m_assetLibrary(0) + { + if (!ensureAuthorizationDialogNotBlocked()) + return; + + if (QIOSAssetData *assetData = g_assetDataCache.localData()) { + // It's a common pattern that QFiles pointing to the same path are created and destroyed + // several times during a single event loop cycle. To avoid loading the same asset + // over and over, we check if the last loaded asset has not been destroyed yet, and try to + // reuse its data. + if (assetData->m_assetUrl == assetUrl) { + m_assetLibrary = [assetData->m_assetLibrary retain]; + m_asset = [assetData->m_asset retain]; + return; + } + } + + // We can only load images from the asset library async. And this might take time, since it + // involves showing the authorization dialog. But the QFile API is synchronuous, so we need to + // wait until we have access to the data. [ALAssetLibrary assetForUrl:] will shedule a block on + // the current thread. But instead of spinning the event loop to force the block to execute, we + // wrap the call inside a synchronuous dispatch queue so that it executes on another thread. + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSURL *url = [NSURL URLWithString:assetUrl.toNSString()]; + m_assetLibrary = [[ALAssetsLibrary alloc] init]; + [m_assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) { + + if (!asset) { + // When an asset couldn't be loaded, chances are that it belongs to ALAssetsGroupPhotoStream. + // Such assets can be stored in the cloud and might need to be downloaded first. Unfortunately, + // forcing that to happen is hidden behind private APIs ([ALAsset requestDefaultRepresentation]). + // As a work-around, we search for it instead, since that will give us a pointer to the asset. + QIOSAssetEnumerator e(m_assetLibrary, ALAssetsGroupPhotoStream); + while (e.hasNext()) { + ALAsset *a = e.next(); + QString url = QUrl::fromNSURL([a valueForProperty:ALAssetPropertyAssetURL]).toString(); + if (url == assetUrl) { + asset = a; + break; + } + } + } + + if (!asset) + engine->setError(QFile::OpenError, QLatin1String("could not open image")); + + m_asset = [asset retain]; + dispatch_semaphore_signal(semaphore); + } failureBlock:^(NSError *error) { + engine->setError(QFile::OpenError, QString::fromNSString(error.localizedDescription)); + dispatch_semaphore_signal(semaphore); + }]; + }); + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + dispatch_release(semaphore); + + g_assetDataCache.setLocalData(this); + } + + ~QIOSAssetData() + { + [m_assetLibrary release]; + [m_asset release]; + if (g_assetDataCache.localData() == this) + g_assetDataCache.setLocalData(0); + } + + ALAsset *m_asset; + +private: + QString m_assetUrl; + ALAssetsLibrary *m_assetLibrary; +}; + +// ------------------------------------------------------------------------- + +#ifndef QT_NO_FILESYSTEMITERATOR + +class QIOSFileEngineIteratorAssetsLibrary : public QAbstractFileEngineIterator +{ +public: + QIOSAssetEnumerator *m_enumerator; + + QIOSFileEngineIteratorAssetsLibrary( + QDir::Filters filters, const QStringList &nameFilters) + : QAbstractFileEngineIterator(filters, nameFilters) + , m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll)) + { + } + + ~QIOSFileEngineIteratorAssetsLibrary() + { + delete m_enumerator; + g_iteratorCurrentUrl.setLocalData(QString()); + } + + QString next() Q_DECL_OVERRIDE + { + // Cache the URL that we are about to return, since QDir will immediately create a + // new file engine on the file and ask if it exists. Unless we do this, we end up + // creating a new ALAsset just to verify its existence, which will be especially + // costly for assets belonging to ALAssetsGroupPhotoStream. + ALAsset *asset = m_enumerator->next(); + QString url = QUrl::fromNSURL([asset valueForProperty:ALAssetPropertyAssetURL]).toString(); + g_iteratorCurrentUrl.setLocalData(url); + return url; + } + + bool hasNext() const Q_DECL_OVERRIDE + { + return m_enumerator->hasNext(); + } + + QString currentFileName() const Q_DECL_OVERRIDE + { + return g_iteratorCurrentUrl.localData(); + } + + QFileInfo currentFileInfo() const Q_DECL_OVERRIDE + { + return QFileInfo(currentFileName()); + } +}; + +#endif + +// ------------------------------------------------------------------------- + +QIOSFileEngineAssetsLibrary::QIOSFileEngineAssetsLibrary(const QString &fileName) + : m_offset(0) + , m_data(0) +{ + setFileName(fileName); +} + +QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() +{ + close(); +} + +ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const +{ + if (!m_data) + m_data = new QIOSAssetData(m_assetUrl, const_cast(this)); + return m_data->m_asset; +} + +bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode) +{ + if (openMode & (QIODevice::WriteOnly | QIODevice::Text)) + return false; + return loadAsset(); +} + +bool QIOSFileEngineAssetsLibrary::close() +{ + if (m_data) { + // Delete later, so that we can reuse the asset if a QFile is + // opened with the same path during the same event loop cycle. + m_data->deleteLater(); + m_data = 0; + } + return true; +} + +QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractFileEngine::FileFlags type) const +{ + QAbstractFileEngine::FileFlags flags = 0; + const bool isDir = (m_assetUrl == QLatin1String("assets-library://")); + const bool exists = isDir || m_assetUrl == g_iteratorCurrentUrl.localData() || loadAsset(); + + if (!exists) + return flags; + + if (type & FlagsMask) + flags |= ExistsFlag; + if (type & PermsMask) { + ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; + if (status != ALAuthorizationStatusRestricted && status != ALAuthorizationStatusDenied) + flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; + } + if (type & TypesMask) + flags |= isDir ? DirectoryType : FileType; + + return flags; +} + +qint64 QIOSFileEngineAssetsLibrary::size() const +{ + if (ALAsset *asset = loadAsset()) + return [[asset defaultRepresentation] size]; + return 0; +} + +qint64 QIOSFileEngineAssetsLibrary::read(char *data, qint64 maxlen) +{ + ALAsset *asset = loadAsset(); + if (!asset) + return -1; + + qint64 bytesRead = qMin(maxlen, size() - m_offset); + if (!bytesRead) + return 0; + + NSError *error = 0; + [[asset defaultRepresentation] getBytes:(uint8_t *)data fromOffset:m_offset length:bytesRead error:&error]; + + if (error) { + setError(QFile::ReadError, QString::fromNSString(error.localizedDescription)); + return -1; + } + + m_offset += bytesRead; + return bytesRead; +} + +qint64 QIOSFileEngineAssetsLibrary::pos() const +{ + return m_offset; +} + +bool QIOSFileEngineAssetsLibrary::seek(qint64 pos) +{ + if (pos >= size()) + return false; + m_offset = pos; + return true; +} + +QString QIOSFileEngineAssetsLibrary::fileName(FileName file) const +{ + Q_UNUSED(file); + return m_fileName; +} + +void QIOSFileEngineAssetsLibrary::setFileName(const QString &file) +{ + if (m_data) + close(); + m_fileName = file; + // QUrl::fromLocalFile() will remove double slashes. Since the asset url is + // passed around as a file name in the app (and converted to/from a file url, e.g + // in QFileDialog), we need to ensure that m_assetUrl ends up being valid. + int index = file.indexOf(QLatin1String("/asset")); + if (index == -1) + m_assetUrl = QLatin1String("assets-library://"); + else + m_assetUrl = QLatin1String("assets-library:/") + file.mid(index); +} + +QStringList QIOSFileEngineAssetsLibrary::entryList(QDir::Filters filters, const QStringList &filterNames) const +{ + return QAbstractFileEngine::entryList(filters, filterNames); +} + +#ifndef QT_NO_FILESYSTEMITERATOR + +QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::beginEntryList( + QDir::Filters filters, const QStringList &filterNames) +{ + return new QIOSFileEngineIteratorAssetsLibrary(filters, filterNames); +} + +QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList() +{ + return 0; +} + +#endif diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h new file mode 100644 index 0000000000..29f543caae --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSFILEENGINEFACTORY_H +#define QIOSFILEENGINEFACTORY_H + +#include +#include +#include "qiosfileengineassetslibrary.h" + +class QIOSFileEngineFactory : public QAbstractFileEngineHandler +{ +public: + QAbstractFileEngine* create(const QString &fileName) const + { + static QLatin1String assetsScheme("assets-library:"); + + if (fileName.toLower().startsWith(assetsScheme)) + return new QIOSFileEngineAssetsLibrary(fileName); + + return 0; + } +}; + +#endif // QIOSFILEENGINEFACTORY_H diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h new file mode 100644 index 0000000000..df3f6b9fa3 --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import + +#include "../../qiosfiledialog.h" + +@interface QIOSImagePickerController : UIImagePickerController { + QIOSFileDialog *m_fileDialog; +} +- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog; +@end diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm new file mode 100644 index 0000000000..f9662b964a --- /dev/null +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosimagepickercontroller.mm @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import + +#include "qiosimagepickercontroller.h" + +@implementation QIOSImagePickerController + +- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog +{ + self = [super init]; + if (self) { + m_fileDialog = fileDialog; + [self setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]; + [self setDelegate:self]; + } + return self; +} + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + Q_UNUSED(picker); + NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL]; + QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString([url description])); + m_fileDialog->selectedFilesChanged(QList() << fileUrl); + emit m_fileDialog->accept(); +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + Q_UNUSED(picker) + emit m_fileDialog->reject(); +} + +@end diff --git a/src/plugins/platforms/ios/optional/optional.pro b/src/plugins/platforms/ios/optional/optional.pro new file mode 100644 index 0000000000..5e3421a025 --- /dev/null +++ b/src/plugins/platforms/ios/optional/optional.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = nsphotolibrarysupport diff --git a/src/plugins/platforms/ios/qiosfiledialog.h b/src/plugins/platforms/ios/qiosfiledialog.h index b4bf85edd9..668cf18caf 100644 --- a/src/plugins/platforms/ios/qiosfiledialog.h +++ b/src/plugins/platforms/ios/qiosfiledialog.h @@ -66,6 +66,8 @@ private: QList m_selection; QEventLoop m_eventLoop; UIViewController *m_viewController; + + bool showImagePickerDialog(QWindow *parent); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm index 7c32784e9d..a70eb11ef8 100644 --- a/src/plugins/platforms/ios/qiosfiledialog.mm +++ b/src/plugins/platforms/ios/qiosfiledialog.mm @@ -31,52 +31,18 @@ ** ****************************************************************************/ -#include "qiosfiledialog.h" - #import #include #include +#include -@interface QIOSImagePickerController : UIImagePickerController { - QIOSFileDialog *m_fileDialog; -} -@end - -@implementation QIOSImagePickerController - -- (id)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog -{ - self = [super init]; - if (self) { - m_fileDialog = fileDialog; - [self setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]; - [self setDelegate:self]; - } - return self; -} - -- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info -{ - Q_UNUSED(picker); - NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL]; - QUrl fileUrl = QUrl::fromLocalFile(QString::fromNSString([url description])); - m_fileDialog->selectedFilesChanged(QList() << fileUrl); - emit m_fileDialog->accept(); -} - -- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker -{ - Q_UNUSED(picker) - emit m_fileDialog->reject(); -} - -@end - -// -------------------------------------------------------------------------- +#include "qiosfiledialog.h" +#include "qiosintegration.h" +#include "qiosoptionalplugininterface.h" QIOSFileDialog::QIOSFileDialog() - : m_viewController(0) + : m_viewController(Q_NULLPTR) { } @@ -98,17 +64,36 @@ bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window bool acceptOpen = options()->acceptMode() == QFileDialogOptions::AcceptOpen; QString directory = options()->initialDirectory().toLocalFile(); - if (acceptOpen && directory.startsWith(QLatin1String("assets-library:"))) { - m_viewController = [[QIOSImagePickerController alloc] initWithQIOSFileDialog:this]; - UIWindow *window = parent ? reinterpret_cast(parent->winId()).window - : [UIApplication sharedApplication].keyWindow; - [window.rootViewController presentViewController:m_viewController animated:YES completion:nil]; - return true; - } + if (acceptOpen && directory.startsWith(QLatin1String("assets-library:"))) + return showImagePickerDialog(parent); return false; } +bool QIOSFileDialog::showImagePickerDialog(QWindow *parent) +{ + if (!m_viewController) { + QFactoryLoader *plugins = QIOSIntegration::instance()->optionalPlugins(); + for (int i = 0; i < plugins->metaData().size(); ++i) { + QIosOptionalPluginInterface *plugin = qobject_cast(plugins->instance(i)); + m_viewController = [plugin->createImagePickerController(this) retain]; + if (m_viewController) + break; + } + } + + if (!m_viewController) { + qWarning() << "QIOSFileDialog: Could not resolve Qt plugin that gives access to photos on iOS"; + return false; + } + + UIWindow *window = parent ? reinterpret_cast(parent->winId()).window + : [UIApplication sharedApplication].keyWindow; + [window.rootViewController presentViewController:m_viewController animated:YES completion:nil]; + + return true; +} + void QIOSFileDialog::hide() { // QFileDialog will remember the last directory set, and open subsequent dialogs in the same @@ -120,6 +105,8 @@ void QIOSFileDialog::hide() emit directoryEntered(QUrl::fromLocalFile(QDir::currentPath())); [m_viewController dismissViewControllerAnimated:YES completion:nil]; + [m_viewController release]; + m_viewController = Q_NULLPTR; m_eventLoop.exit(); } diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/qiosfileengineassetslibrary.h deleted file mode 100644 index 37bbc7bf23..0000000000 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QIOSFILEENGINEASSETSLIBRARY_H -#define QIOSFILEENGINEASSETSLIBRARY_H - -#include - -Q_FORWARD_DECLARE_OBJC_CLASS(ALAsset); -class QIOSAssetData; - -class QIOSFileEngineAssetsLibrary : public QAbstractFileEngine -{ -public: - QIOSFileEngineAssetsLibrary(const QString &fileName); - ~QIOSFileEngineAssetsLibrary(); - - bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE; - bool close() Q_DECL_OVERRIDE; - FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE; - qint64 size() const Q_DECL_OVERRIDE; - qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 pos() const Q_DECL_OVERRIDE; - bool seek(qint64 pos) Q_DECL_OVERRIDE; - QString fileName(FileName file) const Q_DECL_OVERRIDE; - void setFileName(const QString &file) Q_DECL_OVERRIDE; - QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE; - -#ifndef QT_NO_FILESYSTEMITERATOR - Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; - Iterator *endEntryList() Q_DECL_OVERRIDE; -#endif - - void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); } - -private: - QString m_fileName; - QString m_assetUrl; - qint64 m_offset; - mutable QIOSAssetData *m_data; - - ALAsset *loadAsset() const; -}; - -#endif // QIOSFILEENGINEASSETSLIBRARY_H - diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm deleted file mode 100644 index bb12c164d6..0000000000 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm +++ /dev/null @@ -1,469 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qiosfileengineassetslibrary.h" - -#import -#import - -#include -#include -#include -#include -#include - -static QThreadStorage g_iteratorCurrentUrl; -static QThreadStorage > g_assetDataCache; - -static const int kBufferSize = 10; -static ALAsset *kNoAsset = 0; - -static bool ensureAuthorizationDialogNotBlocked() -{ - if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusNotDetermined) - return true; - - if (static_cast(QObjectPrivate::get(qApp))->in_exec) - return true; - - if ([NSThread isMainThread]) { - // The dialog is about to show, but since main has not finished, the dialog will be held - // back until the launch completes. This is problematic since we cannot successfully return - // back to the caller before the asset is ready, which also includes showing the dialog. To - // work around this, we create an event loop to that will complete the launch (return from the - // applicationDidFinishLaunching callback). But this will only work if we're on the main thread. - QEventLoop loop; - QTimer::singleShot(1, &loop, &QEventLoop::quit); - loop.exec(); - } else { - NSLog(@"QIOSFileEngine: unable to show assets authorization dialog from non-gui thread before QApplication is executing."); - return false; - } - - return true; -} - -// ------------------------------------------------------------------------- - -class QIOSAssetEnumerator -{ -public: - QIOSAssetEnumerator(ALAssetsLibrary *assetsLibrary, ALAssetsGroupType type) - : m_semWriteAsset(dispatch_semaphore_create(kBufferSize)) - , m_semReadAsset(dispatch_semaphore_create(0)) - , m_stop(false) - , m_assetsLibrary([assetsLibrary retain]) - , m_type(type) - , m_buffer(QVector(kBufferSize)) - , m_readIndex(0) - , m_writeIndex(0) - , m_nextAssetReady(false) - { - if (!ensureAuthorizationDialogNotBlocked()) - writeAsset(kNoAsset); - else - startEnumerate(); - } - - ~QIOSAssetEnumerator() - { - m_stop = true; - - // Flush and autorelease remaining assets in the buffer - while (hasNext()) - next(); - - // Documentation states that we need to balance out calls to 'wait' - // and 'signal'. Since the enumeration function always will be one 'wait' - // ahead, we need to signal m_semProceedToNextAsset one last time. - dispatch_semaphore_signal(m_semWriteAsset); - dispatch_release(m_semReadAsset); - dispatch_release(m_semWriteAsset); - - [m_assetsLibrary autorelease]; - } - - bool hasNext() - { - if (!m_nextAssetReady) { - dispatch_semaphore_wait(m_semReadAsset, DISPATCH_TIME_FOREVER); - m_nextAssetReady = true; - } - return m_buffer[m_readIndex] != kNoAsset; - } - - ALAsset *next() - { - Q_ASSERT(m_nextAssetReady); - Q_ASSERT(m_buffer[m_readIndex]); - - ALAsset *asset = [m_buffer[m_readIndex] autorelease]; - dispatch_semaphore_signal(m_semWriteAsset); - - m_readIndex = (m_readIndex + 1) % kBufferSize; - m_nextAssetReady = false; - return asset; - } - -private: - dispatch_semaphore_t m_semWriteAsset; - dispatch_semaphore_t m_semReadAsset; - std::atomic_bool m_stop; - - ALAssetsLibrary *m_assetsLibrary; - ALAssetsGroupType m_type; - QVector m_buffer; - int m_readIndex; - int m_writeIndex; - bool m_nextAssetReady; - - void writeAsset(ALAsset *asset) - { - dispatch_semaphore_wait(m_semWriteAsset, DISPATCH_TIME_FOREVER); - m_buffer[m_writeIndex] = [asset retain]; - dispatch_semaphore_signal(m_semReadAsset); - m_writeIndex = (m_writeIndex + 1) % kBufferSize; - } - - void startEnumerate() - { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - [m_assetsLibrary enumerateGroupsWithTypes:m_type usingBlock:^(ALAssetsGroup *group, BOOL *stopEnumerate) { - - if (!group) { - writeAsset(kNoAsset); - return; - } - - if (m_stop) { - *stopEnumerate = true; - return; - } - - [group enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stopEnumerate) { - Q_UNUSED(index); - if (!asset || ![[asset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) - return; - - writeAsset(asset); - *stopEnumerate = m_stop; - }]; - } failureBlock:^(NSError *error) { - NSLog(@"QIOSFileEngine: %@", error); - writeAsset(kNoAsset); - }]; - }); - } - -}; - -// ------------------------------------------------------------------------- - -class QIOSAssetData : public QObject -{ -public: - QIOSAssetData(const QString &assetUrl, QIOSFileEngineAssetsLibrary *engine) - : m_asset(0) - , m_assetUrl(assetUrl) - , m_assetLibrary(0) - { - if (!ensureAuthorizationDialogNotBlocked()) - return; - - if (QIOSAssetData *assetData = g_assetDataCache.localData()) { - // It's a common pattern that QFiles pointing to the same path are created and destroyed - // several times during a single event loop cycle. To avoid loading the same asset - // over and over, we check if the last loaded asset has not been destroyed yet, and try to - // reuse its data. - if (assetData->m_assetUrl == assetUrl) { - m_assetLibrary = [assetData->m_assetLibrary retain]; - m_asset = [assetData->m_asset retain]; - return; - } - } - - // We can only load images from the asset library async. And this might take time, since it - // involves showing the authorization dialog. But the QFile API is synchronuous, so we need to - // wait until we have access to the data. [ALAssetLibrary assetForUrl:] will shedule a block on - // the current thread. But instead of spinning the event loop to force the block to execute, we - // wrap the call inside a synchronuous dispatch queue so that it executes on another thread. - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSURL *url = [NSURL URLWithString:assetUrl.toNSString()]; - m_assetLibrary = [[ALAssetsLibrary alloc] init]; - [m_assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) { - - if (!asset) { - // When an asset couldn't be loaded, chances are that it belongs to ALAssetsGroupPhotoStream. - // Such assets can be stored in the cloud and might need to be downloaded first. Unfortunately, - // forcing that to happen is hidden behind private APIs ([ALAsset requestDefaultRepresentation]). - // As a work-around, we search for it instead, since that will give us a pointer to the asset. - QIOSAssetEnumerator e(m_assetLibrary, ALAssetsGroupPhotoStream); - while (e.hasNext()) { - ALAsset *a = e.next(); - QString url = QUrl::fromNSURL([a valueForProperty:ALAssetPropertyAssetURL]).toString(); - if (url == assetUrl) { - asset = a; - break; - } - } - } - - if (!asset) - engine->setError(QFile::OpenError, QLatin1String("could not open image")); - - m_asset = [asset retain]; - dispatch_semaphore_signal(semaphore); - } failureBlock:^(NSError *error) { - engine->setError(QFile::OpenError, QString::fromNSString(error.localizedDescription)); - dispatch_semaphore_signal(semaphore); - }]; - }); - - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); - dispatch_release(semaphore); - - g_assetDataCache.setLocalData(this); - } - - ~QIOSAssetData() - { - [m_assetLibrary release]; - [m_asset release]; - if (g_assetDataCache.localData() == this) - g_assetDataCache.setLocalData(0); - } - - ALAsset *m_asset; - -private: - QString m_assetUrl; - ALAssetsLibrary *m_assetLibrary; -}; - -// ------------------------------------------------------------------------- - -#ifndef QT_NO_FILESYSTEMITERATOR - -class QIOSFileEngineIteratorAssetsLibrary : public QAbstractFileEngineIterator -{ -public: - QIOSAssetEnumerator *m_enumerator; - - QIOSFileEngineIteratorAssetsLibrary( - QDir::Filters filters, const QStringList &nameFilters) - : QAbstractFileEngineIterator(filters, nameFilters) - , m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll)) - { - } - - ~QIOSFileEngineIteratorAssetsLibrary() - { - delete m_enumerator; - g_iteratorCurrentUrl.setLocalData(QString()); - } - - QString next() Q_DECL_OVERRIDE - { - // Cache the URL that we are about to return, since QDir will immediately create a - // new file engine on the file and ask if it exists. Unless we do this, we end up - // creating a new ALAsset just to verify its existence, which will be especially - // costly for assets belonging to ALAssetsGroupPhotoStream. - ALAsset *asset = m_enumerator->next(); - QString url = QUrl::fromNSURL([asset valueForProperty:ALAssetPropertyAssetURL]).toString(); - g_iteratorCurrentUrl.setLocalData(url); - return url; - } - - bool hasNext() const Q_DECL_OVERRIDE - { - return m_enumerator->hasNext(); - } - - QString currentFileName() const Q_DECL_OVERRIDE - { - return g_iteratorCurrentUrl.localData(); - } - - QFileInfo currentFileInfo() const Q_DECL_OVERRIDE - { - return QFileInfo(currentFileName()); - } -}; - -#endif - -// ------------------------------------------------------------------------- - -QIOSFileEngineAssetsLibrary::QIOSFileEngineAssetsLibrary(const QString &fileName) - : m_offset(0) - , m_data(0) -{ - setFileName(fileName); -} - -QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() -{ - close(); -} - -ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const -{ - if (!m_data) - m_data = new QIOSAssetData(m_assetUrl, const_cast(this)); - return m_data->m_asset; -} - -bool QIOSFileEngineAssetsLibrary::open(QIODevice::OpenMode openMode) -{ - if (openMode & (QIODevice::WriteOnly | QIODevice::Text)) - return false; - return loadAsset(); -} - -bool QIOSFileEngineAssetsLibrary::close() -{ - if (m_data) { - // Delete later, so that we can reuse the asset if a QFile is - // opened with the same path during the same event loop cycle. - m_data->deleteLater(); - m_data = 0; - } - return true; -} - -QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractFileEngine::FileFlags type) const -{ - QAbstractFileEngine::FileFlags flags = 0; - const bool isDir = (m_assetUrl == QLatin1String("assets-library://")); - const bool exists = isDir || m_assetUrl == g_iteratorCurrentUrl.localData() || loadAsset(); - - if (!exists) - return flags; - - if (type & FlagsMask) - flags |= ExistsFlag; - if (type & PermsMask) { - ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; - if (status != ALAuthorizationStatusRestricted && status != ALAuthorizationStatusDenied) - flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; - } - if (type & TypesMask) - flags |= isDir ? DirectoryType : FileType; - - return flags; -} - -qint64 QIOSFileEngineAssetsLibrary::size() const -{ - if (ALAsset *asset = loadAsset()) - return [[asset defaultRepresentation] size]; - return 0; -} - -qint64 QIOSFileEngineAssetsLibrary::read(char *data, qint64 maxlen) -{ - ALAsset *asset = loadAsset(); - if (!asset) - return -1; - - qint64 bytesRead = qMin(maxlen, size() - m_offset); - if (!bytesRead) - return 0; - - NSError *error = 0; - [[asset defaultRepresentation] getBytes:(uint8_t *)data fromOffset:m_offset length:bytesRead error:&error]; - - if (error) { - setError(QFile::ReadError, QString::fromNSString(error.localizedDescription)); - return -1; - } - - m_offset += bytesRead; - return bytesRead; -} - -qint64 QIOSFileEngineAssetsLibrary::pos() const -{ - return m_offset; -} - -bool QIOSFileEngineAssetsLibrary::seek(qint64 pos) -{ - if (pos >= size()) - return false; - m_offset = pos; - return true; -} - -QString QIOSFileEngineAssetsLibrary::fileName(FileName file) const -{ - Q_UNUSED(file); - return m_fileName; -} - -void QIOSFileEngineAssetsLibrary::setFileName(const QString &file) -{ - if (m_data) - close(); - m_fileName = file; - // QUrl::fromLocalFile() will remove double slashes. Since the asset url is - // passed around as a file name in the app (and converted to/from a file url, e.g - // in QFileDialog), we need to ensure that m_assetUrl ends up being valid. - int index = file.indexOf(QLatin1String("/asset")); - if (index == -1) - m_assetUrl = QLatin1String("assets-library://"); - else - m_assetUrl = QLatin1String("assets-library:/") + file.mid(index); -} - -QStringList QIOSFileEngineAssetsLibrary::entryList(QDir::Filters filters, const QStringList &filterNames) const -{ - return QAbstractFileEngine::entryList(filters, filterNames); -} - -#ifndef QT_NO_FILESYSTEMITERATOR - -QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::beginEntryList( - QDir::Filters filters, const QStringList &filterNames) -{ - return new QIOSFileEngineIteratorAssetsLibrary(filters, filterNames); -} - -QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList() -{ - return 0; -} - -#endif diff --git a/src/plugins/platforms/ios/qiosfileenginefactory.h b/src/plugins/platforms/ios/qiosfileenginefactory.h deleted file mode 100644 index a8604c77d1..0000000000 --- a/src/plugins/platforms/ios/qiosfileenginefactory.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QIOSFILEENGINEFACTORY_H -#define QIOSFILEENGINEFACTORY_H - -#include -#include -#include "qiosfileengineassetslibrary.h" - -class QIOSFileEngineFactory : public QAbstractFileEngineHandler -{ -public: - QAbstractFileEngine* create(const QString &fileName) const - { - static QLatin1String assetsScheme("assets-library:"); - - if (fileName.toLower().startsWith(assetsScheme)) - return new QIOSFileEngineAssetsLibrary(fileName); - - return 0; - } -}; - -#endif // QIOSFILEENGINEFACTORY_H diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 7d23fe1d62..25eb8990cb 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -38,8 +38,9 @@ #include #include +#include + #include "qiosapplicationstate.h" -#include "qiosfileenginefactory.h" QT_BEGIN_NAMESPACE @@ -91,6 +92,8 @@ public: void setDebugWindowManagement(bool); bool debugWindowManagement() const; + QFactoryLoader *optionalPlugins() { return m_optionalPlugins; } + private: QPlatformFontDatabase *m_fontDatabase; QPlatformClipboard *m_clipboard; @@ -99,7 +102,7 @@ private: QIOSApplicationState m_applicationState; QIOSServices *m_platformServices; mutable QPlatformAccessibility *m_accessibility; - QIOSFileEngineFactory m_fileEngineFactory; + QFactoryLoader *m_optionalPlugins; bool m_debugWindowManagement; }; diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 85b5c477cc..d33c8cf47c 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -43,6 +43,7 @@ #include "qiosinputcontext.h" #include "qiostheme.h" #include "qiosservices.h" +#include "qiosoptionalplugininterface.h" #include @@ -68,6 +69,7 @@ QIOSIntegration::QIOSIntegration() , m_inputContext(0) , m_platformServices(new QIOSServices) , m_accessibility(0) + , m_optionalPlugins(new QFactoryLoader(QIosOptionalPluginInterface_iid, QLatin1String("/platforms/darwin"))) , m_debugWindowManagement(false) { if (![UIApplication sharedApplication]) { @@ -112,6 +114,9 @@ QIOSIntegration::QIOSIntegration() m_touchDevice->setCapabilities(touchCapabilities); QWindowSystemInterface::registerTouchDevice(m_touchDevice); QMacInternalPasteboardMime::initializeMimeTypes(); + + for (int i = 0; i < m_optionalPlugins->metaData().size(); ++i) + qobject_cast(m_optionalPlugins->instance(i))->initPlugin(); } QIOSIntegration::~QIOSIntegration() @@ -134,6 +139,9 @@ QIOSIntegration::~QIOSIntegration() delete m_accessibility; m_accessibility = 0; + + delete m_optionalPlugins; + m_optionalPlugins = 0; } bool QIOSIntegration::hasCapability(Capability cap) const diff --git a/src/plugins/platforms/ios/qiosoptionalplugininterface.h b/src/plugins/platforms/ios/qiosoptionalplugininterface.h new file mode 100644 index 0000000000..bcb8978e02 --- /dev/null +++ b/src/plugins/platforms/ios/qiosoptionalplugininterface.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOPLUGININTERFACE_H +#define QIOPLUGININTERFACE_H + +#include + +#include "qiosfiledialog.h" + +QT_BEGIN_NAMESPACE + +Q_FORWARD_DECLARE_OBJC_CLASS(UIViewController); + +#define QIosOptionalPluginInterface_iid "org.qt-project.Qt.QPA.ios.optional" + +class QIosOptionalPluginInterface +{ +public: + virtual ~QIosOptionalPluginInterface() {} + virtual void initPlugin() const {}; + virtual UIViewController* createImagePickerController(QIOSFileDialog *) const { return Q_NULLPTR; }; +}; + +Q_DECLARE_INTERFACE(QIosOptionalPluginInterface, QIosOptionalPluginInterface_iid) + +QT_END_NAMESPACE + +#endif // QIOPLUGININTERFACE_H -- cgit v1.2.3 From b9af823ef7a4131bc61b07620e7825d757df69db Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 18 Oct 2016 13:09:37 +0200 Subject: qiosfileengineassetslibrary: replace Q_DECL_OVERRIDE with override Change-Id: Iba67e1a1fa86dff3c82543597351b597be69ed1f Reviewed-by: Jake Petroules --- .../qiosfileengineassetslibrary.h | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h index 0e29a1003e..89696751c6 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h @@ -45,20 +45,20 @@ public: QIOSFileEngineAssetsLibrary(const QString &fileName); ~QIOSFileEngineAssetsLibrary(); - bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE; - bool close() Q_DECL_OVERRIDE; - FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE; - qint64 size() const Q_DECL_OVERRIDE; - qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE; - qint64 pos() const Q_DECL_OVERRIDE; - bool seek(qint64 pos) Q_DECL_OVERRIDE; - QString fileName(FileName file) const Q_DECL_OVERRIDE; - void setFileName(const QString &file) Q_DECL_OVERRIDE; - QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE; + bool open(QIODevice::OpenMode openMode) override; + bool close() override; + FileFlags fileFlags(FileFlags type) const override; + qint64 size() const override; + qint64 read(char *data, qint64 maxlen) override; + qint64 pos() const override; + bool seek(qint64 pos) override; + QString fileName(FileName file) const override; + void setFileName(const QString &file) override; + QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override; #ifndef QT_NO_FILESYSTEMITERATOR - Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE; - Iterator *endEntryList() Q_DECL_OVERRIDE; + Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override; + Iterator *endEntryList() override; #endif void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); } -- cgit v1.2.3 From d19f01acbf9547762150a479793b84898f1a115e Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 18 Oct 2016 13:02:34 +0200 Subject: nsphotolibrarysupport: add missing namespace macros Change-Id: Ib2014dc64dfcc1ea8de63a1668907ace6d26c530 Reviewed-by: Jake Petroules --- .../ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h | 5 +++++ .../optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm | 4 ++++ .../ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h | 4 ++++ 3 files changed, 13 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h index 89696751c6..d4dc77b1a3 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h @@ -37,6 +37,9 @@ #include Q_FORWARD_DECLARE_OBJC_CLASS(ALAsset); + +QT_BEGIN_NAMESPACE + class QIOSAssetData; class QIOSFileEngineAssetsLibrary : public QAbstractFileEngine @@ -72,5 +75,7 @@ private: ALAsset *loadAsset() const; }; +QT_END_NAMESPACE + #endif // QIOSFILEENGINEASSETSLIBRARY_H diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm index 2e88c37c01..110348d32b 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm @@ -42,6 +42,8 @@ #include #include +QT_BEGIN_NAMESPACE + static QThreadStorage g_iteratorCurrentUrl; static QThreadStorage > g_assetDataCache; @@ -466,4 +468,6 @@ QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList() return 0; } +QT_END_NAMESPACE + #endif diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h index 29f543caae..f41de5f8ec 100644 --- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h +++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h @@ -38,6 +38,8 @@ #include #include "qiosfileengineassetslibrary.h" +QT_BEGIN_NAMESPACE + class QIOSFileEngineFactory : public QAbstractFileEngineHandler { public: @@ -52,4 +54,6 @@ public: } }; +QT_END_NAMESPACE + #endif // QIOSFILEENGINEFACTORY_H -- cgit v1.2.3 From 8d9c42e36217e14efa69974c2cdc8d90f465a959 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Oct 2016 09:49:24 +0200 Subject: xcb: Avoid crash when requesting non-supported stereo formats Introduced in the 5.7 branch by 5f39a0ef8d037ed8d1fa19d5514308ed4a2ca161. Add also a warning in the GLX backend instead of just dereferencing the null pointer. Task-number: QTBUG-55291 Change-Id: I1f2930768b39a04ee443a68d0ac7dc9ecf26cb9c Reviewed-by: Louai Al-Khanji --- src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp index 8ae83b8084..a8d51d5e8c 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp @@ -59,6 +59,10 @@ const xcb_visualtype_t *QXcbGlxWindow::createVisual() if (!scr) return Q_NULLPTR; XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(scr), scr->screenNumber(), &m_format); + if (!visualInfo) { + qWarning() << "No XVisualInfo for format" << m_format; + return Q_NULLPTR; + } const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid); XFree(visualInfo); return xcb_visualtype; -- cgit v1.2.3 From f577a01f5e8d9678d268917ca727a6e9a3e819a6 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Oct 2016 12:29:26 +0200 Subject: eglfs: Cast to EGLNativeDisplayType in EGLDevice backend When compiling with EGL native types being the Xlib types (uncommon since we disable this both for Mesa and NVIDIA embedded, but can happen with other vendor's headers), the types for EGLDeviceEXT (void*) and EGLNativeDisplayType (Display, i.e. _XDisplay*) won't match, breaking compilation. At runtime we won't hit that path, so all we need to ensure is that the code compiles. Do this via a cast. When the native types are generic, both types are void* so the cast has no effect. Change-Id: Ib54f569d4494906f74107f08b47bd6b521d700db Reviewed-by: Louai Al-Khanji --- .../eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp index 743f714cf0..f6e86bf0bc 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevice.cpp @@ -71,7 +71,7 @@ void QEglFSKmsEglDevice::close() EGLNativeDisplayType QEglFSKmsEglDevice::nativeDisplay() const { - return static_cast(m_integration)->eglDevice(); + return reinterpret_cast(static_cast(m_integration)->eglDevice()); } QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position) -- cgit v1.2.3 From f9280ba45ed6e492871cd25026a1bce7a17042dc Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 24 Oct 2016 13:49:41 -0700 Subject: QNSColorPanelDelegate: Don't restore stolen view on dealloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We may not be playing nice with Cocoa's internals when we decide to reparent NSColorPanel's contents to add QColorDialog's own OK/Cancel buttons. In order to reduce issues, we should avoid poking at things during the application's shutdown sequence. Simply releasing the stolen view should be enough at that point. A similar pattern exists in QNSFontPanelDelegate. Change-Id: I678c236e0c57c4d08a1109a479d965f924288c54 Task-number: QTBUG-56448 Reviewed-by: Tor Arne Vestbø Reviewed-by: Timur Pocheptsov Reviewed-by: Erik Verbruggen --- src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm | 2 +- src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index ed17ef8fe9..3c924bec94 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -116,7 +116,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)dealloc { - [self restoreOriginalContentView]; + [mStolenContentView release]; [mColorPanel setDelegate:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm index d1802fe4f9..5b27dc1da9 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm @@ -144,7 +144,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSFontPanelDelegate); - (void)dealloc { - [self restoreOriginalContentView]; + [mStolenContentView release]; [mFontPanel setDelegate:nil]; [[NSFontManager sharedFontManager] setDelegate:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; -- cgit v1.2.3 From f2f39946d2911fe1157d3f71094cc7acf06e2f46 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 28 Oct 2016 11:57:38 +0200 Subject: Fix a mis-merge in af0d0b9 "-framework AudioToolbox" was lost. Task-number: QTBUG-56784 Change-Id: Ibd536c53e7e1456077559c021a70407339f33971 Reviewed-by: Richard Moe Gustavsen --- src/plugins/platforms/ios/kernel.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro index d8235ee011..955f8d9642 100644 --- a/src/plugins/platforms/ios/kernel.pro +++ b/src/plugins/platforms/ios/kernel.pro @@ -1,7 +1,7 @@ TARGET = qios QT += core-private gui-private platformsupport-private -LIBS += -framework Foundation -framework UIKit -framework QuartzCore +LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AudioToolbox OBJECTIVE_SOURCES = \ plugin.mm \ -- cgit v1.2.3 From f9ec707e4960bf7d5298ee2ba8f22d7506ef54a7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 18 Oct 2016 10:56:11 -0700 Subject: windows: Disable OpenGL proper on Intel 945 Change-Id: I77fbf5bafcd6b0fe5040513ef6b0d049600f9b33 Task-number: QTBUG-40991 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/openglblacklists/default.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index 1e00da52eb..dd99e674ec 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -102,6 +102,18 @@ "features": [ "disable_desktopgl", "disable_d3d11", "disable_d3d9" ] + }, + { + "id": 9, + "description": "Intel 945 crash (QTBUG-40991)", + "vendor_id": "0x8086", + "device_id": [ "0x27A2" ], + "os": { + "type": "win" + }, + "features": [ + "disable_desktopgl" + ] } ] } -- cgit v1.2.3 From ca5d4137aa352d61d796c82b06e2d8f19a07cf10 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 27 Oct 2016 12:37:02 +0200 Subject: minimalegl: Reorder includes to avoid EGL native type clashes Some of the qminimaleglscreen.h includes are not even necessary. With the inclusion of egl.h (or qt_egl_p.h in 5.7 and up) isolated to this header, all we need to ensure is that the sources that include it place the include at a suitable place. This is not the only possible solution, there are alternatives (each with its own caveat), but this is likely the least intrusive. Task-number: QTBUG-56559 Change-Id: I17db031c8e401d9895a417ba3568ad1e4ba30f72 Reviewed-by: Louai Al-Khanji --- src/plugins/platforms/minimalegl/qminimaleglintegration.cpp | 3 ++- src/plugins/platforms/minimalegl/qminimaleglintegration.h | 2 -- src/plugins/platforms/minimalegl/qminimaleglwindow.h | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp index 1bcb22618e..5328a8b353 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp @@ -52,7 +52,8 @@ #include #include -#include +// this is where EGL headers are pulled in, make sure it is last +#include "qminimaleglscreen.h" QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h index 7a2c23ced4..8ceeb7b193 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h @@ -34,8 +34,6 @@ #ifndef QMINIMALEGLINTEGRATION_H #define QMINIMALEGLINTEGRATION_H -#include "qminimaleglscreen.h" - #include #include diff --git a/src/plugins/platforms/minimalegl/qminimaleglwindow.h b/src/plugins/platforms/minimalegl/qminimaleglwindow.h index ba7f999602..4edeaf4da9 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglwindow.h +++ b/src/plugins/platforms/minimalegl/qminimaleglwindow.h @@ -35,7 +35,6 @@ #define QMINIMALEGLWINDOW_H #include "qminimaleglintegration.h" -#include "qminimaleglscreen.h" #include -- cgit v1.2.3