diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-06-03 10:23:56 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-06-03 10:23:56 +0200 |
commit | e2f66f921594b7be4af4a058c959557489e86879 (patch) | |
tree | cc44931708b57bd5a761906797c7dee0360d1d6b /src/plugins/platforms/ios | |
parent | 933bf178aab88ab5df8a68cbf02611d6d8744b1b (diff) | |
parent | 754efa57d89c62d1796e01b407e9222e67450f52 (diff) |
Merge remote-tracking branch 'origin/5.5' into dev
Conflicts:
src/corelib/global/qnamespace.qdoc
src/corelib/io/qwindowspipereader.cpp
src/corelib/io/qwindowspipereader_p.h
src/corelib/statemachine/qstatemachine.cpp
src/corelib/statemachine/qstatemachine_p.h
src/plugins/platforms/xcb/qxcbconnection.h
tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
tests/auto/tools/qmake/tst_qmake.cpp
tests/manual/touch/main.cpp
Change-Id: I917d694890e79ee3da7d65134b5b085e23e0dd62
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r-- | src/plugins/platforms/ios/plugin.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosbackingstore.h | 8 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosbackingstore.mm | 109 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qioscontext.mm | 6 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosfileengineassetslibrary.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosfileengineassetslibrary.mm | 320 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosintegration.mm | 11 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qioswindow.mm | 6 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview.mm | 10 |
9 files changed, 407 insertions, 72 deletions
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm index 41fe712f60..e68e1dfd6f 100644 --- a/src/plugins/platforms/ios/plugin.mm +++ b/src/plugins/platforms/ios/plugin.mm @@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.2" FILE "ios.json") + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "ios.json") public: QPlatformIntegration *create(const QString&, const QStringList&); }; diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h index 68c77d9900..5d2ae429f1 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.h +++ b/src/plugins/platforms/ios/qiosbackingstore.h @@ -39,6 +39,8 @@ QT_BEGIN_NAMESPACE class QOpenGLPaintDevice; +class QOpenGLFramebufferObject; +class QOffscreenSurface; class QIOSBackingStore : public QPlatformBackingStore { @@ -49,13 +51,19 @@ public: QPaintDevice *paintDevice(); void beginPaint(const QRegion &); + void endPaint(); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size, const QRegion &staticContents); + GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const; + + void makeCurrent(); private: QOpenGLContext *m_context; QOpenGLPaintDevice *m_device; + QOpenGLFramebufferObject *m_fbo; + QOffscreenSurface *m_surface; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index acec95b0d3..875d06dc80 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -36,41 +36,117 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLPaintDevice> +#include <QtGui/QOpenGLFramebufferObject> +#include <QtGui/QOffscreenSurface> +#include <QtGui/private/qwindow_p.h> #include <QtDebug> +class QIOSPaintDevice : public QOpenGLPaintDevice +{ +public: + QIOSPaintDevice(QIOSBackingStore *backingStore) : m_backingStore(backingStore) { } + void ensureActiveTarget() Q_DECL_OVERRIDE; + +private: + QIOSBackingStore *m_backingStore; +}; + +void QIOSPaintDevice::ensureActiveTarget() +{ + m_backingStore->makeCurrent(); +} + QIOSBackingStore::QIOSBackingStore(QWindow *window) : QPlatformBackingStore(window) , m_context(new QOpenGLContext) , m_device(0) + , m_fbo(0) + , m_surface(0) { QSurfaceFormat fmt = window->requestedFormat(); - fmt.setDepthBufferSize(16); - fmt.setStencilBufferSize(8); + // Due to sharing QIOSContext redirects our makeCurrent on window() attempts to + // the global share context. Hence it is essential to have a compatible format. + fmt.setDepthBufferSize(QSurfaceFormat::defaultFormat().depthBufferSize()); + fmt.setStencilBufferSize(QSurfaceFormat::defaultFormat().stencilBufferSize()); + + if (fmt.depthBufferSize() == 0) + qWarning("No depth in default format, expect rendering errors"); - // Needed to prevent QOpenGLContext::makeCurrent() from failing - window->setSurfaceType(QSurface::OpenGLSurface); + if (window->surfaceType() == QSurface::RasterSurface) + window->setSurfaceType(QSurface::OpenGLSurface); m_context->setFormat(fmt); m_context->setScreen(window->screen()); + Q_ASSERT(QOpenGLContext::globalShareContext()); + m_context->setShareContext(QOpenGLContext::globalShareContext()); m_context->create(); } QIOSBackingStore::~QIOSBackingStore() { + delete m_fbo; + delete m_surface; delete m_context; delete m_device; } +void QIOSBackingStore::makeCurrent() +{ + QSurface *surface = m_surface ? m_surface : static_cast<QSurface *>(window()); + if (!m_context->makeCurrent(surface)) + qWarning("QIOSBackingStore: makeCurrent() failed"); + if (m_fbo) + m_fbo->bind(); +} + void QIOSBackingStore::beginPaint(const QRegion &) { - m_context->makeCurrent(window()); + if (qt_window_private(window())->compositing) { + if (!m_fbo) { + delete m_device; + m_device = 0; + } + if (!m_surface) { + m_surface = new QOffscreenSurface; + m_surface->setFormat(m_context->format()); + m_surface->create(); + } + if (!m_context->makeCurrent(m_surface)) + qWarning("QIOSBackingStore: Failed to make offscreen surface current"); + const QSize size = window()->size() * window()->devicePixelRatio(); + if (m_fbo && m_fbo->size() != size) { + delete m_fbo; + m_fbo = 0; + } + if (!m_fbo) + m_fbo = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::CombinedDepthStencil); + } else if (m_fbo) { + delete m_fbo; + m_fbo = 0; + delete m_surface; + m_surface = 0; + delete m_device; + m_device = 0; + } + + makeCurrent(); + + if (!m_device) + m_device = new QIOSPaintDevice(this); +} + +void QIOSBackingStore::endPaint() +{ + if (m_fbo) { + m_fbo->release(); + glFlush(); + } } QPaintDevice *QIOSBackingStore::paintDevice() { - if (!m_device) - m_device = new QOpenGLPaintDevice; + Q_ASSERT(m_device); // Keep paint device size and device pixel ratio in sync with window qreal devicePixelRatio = window()->devicePixelRatio(); @@ -82,6 +158,8 @@ QPaintDevice *QIOSBackingStore::paintDevice() void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { + Q_ASSERT(!qt_window_private(window)->compositing); + Q_UNUSED(region); Q_UNUSED(offset); @@ -111,4 +189,21 @@ void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents) qWarning() << "QIOSBackingStore needs to have the same size as its window"; } +GLuint QIOSBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const +{ + Q_ASSERT(qt_window_private(window())->compositing); + Q_UNUSED(dirtyRegion); + + if (flags) + *flags = TextureFlip; + + if (!m_fbo) + return 0; + + if (textureSize) + *textureSize = m_fbo->size(); + + return m_fbo->texture(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index c7541fc51b..fe0ca33c13 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -116,7 +116,8 @@ static QString fboStatusString(GLenum status) bool QIOSContext::makeCurrent(QPlatformSurface *surface) { - Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface + || surface->surface()->surfaceType() == QSurface::RasterGLSurface)); [EAGLContext setCurrentContext:m_eaglContext]; @@ -141,7 +142,8 @@ void QIOSContext::doneCurrent() void QIOSContext::swapBuffers(QPlatformSurface *surface) { - Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Q_ASSERT(surface && (surface->surface()->surfaceType() == QSurface::OpenGLSurface + || surface->surface()->surfaceType() == QSurface::RasterGLSurface)); if (surface->surface()->surfaceClass() == QSurface::Offscreen) return; // Nothing to do diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/qiosfileengineassetslibrary.h index 043e101a21..37bbc7bf23 100644 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.h +++ b/src/plugins/platforms/ios/qiosfileengineassetslibrary.h @@ -55,10 +55,17 @@ public: 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; diff --git a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm index 73bfc2a87f..44a7901160 100644 --- a/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm +++ b/src/plugins/platforms/ios/qiosfileengineassetslibrary.mm @@ -38,6 +38,145 @@ #include <QtCore/QTimer> #include <QtCore/private/qcoreapplication_p.h> +#include <QtCore/qurl.h> +#include <QtCore/qset.h> +#include <QtCore/qthreadstorage.h> + +static QThreadStorage<QString> g_iteratorCurrentUrl; +static QThreadStorage<QPointer<QIOSAssetData> > g_assetDataCache; + +static const int kBufferSize = 10; +static ALAsset *kNoAsset = 0; + +static void ensureAuthorizationDialogNotBlocked() +{ + if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusNotDetermined) + return; + if (static_cast<QCoreApplicationPrivate *>(QObjectPrivate::get(qApp))->in_exec) + return; + + // Since authorization status has not been determined, the user will be asked + // to authorize the app. But since main has not finished, the dialog will be held + // back until the launch completes. To avoid a dead-lock below, we start an event + // loop to complete the launch. + QEventLoop loop; + QTimer::singleShot(1, &loop, &QEventLoop::quit); + loop.exec(); +} + +// ------------------------------------------------------------------------- + +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<ALAsset *>(kBufferSize)) + , m_readIndex(0) + , m_writeIndex(0) + , m_nextAssetReady(false) + { + ensureAuthorizationDialogNotBlocked(); + 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<ALAsset *> 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 { @@ -47,35 +186,17 @@ public: , m_assetUrl(assetUrl) , m_assetLibrary(0) { - switch ([ALAssetsLibrary authorizationStatus]) { - case ALAuthorizationStatusRestricted: - case ALAuthorizationStatusDenied: - engine->setError(QFile::PermissionsError, QLatin1String("Unauthorized access")); - return; - case ALAuthorizationStatusNotDetermined: - if (!static_cast<QCoreApplicationPrivate *>(QObjectPrivate::get(qApp))->in_exec) { - // Since authorization status has not been determined, the user will be asked - // to authorize the app. But since main has not finished, the dialog will be held - // back until the launch completes. To avoid a dead-lock below, we start an event - // loop to complete the launch. - QEventLoop loop; - QTimer::singleShot(1, &loop, &QEventLoop::quit); - loop.exec(); - } - break; - default: - if (g_currentAssetData) { - // 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. Since QFile is (mostly) reentrant, we need to protect m_currentAssetData - // from being modified by several threads at the same time. - QMutexLocker lock(&g_mutex); - if (g_currentAssetData && g_currentAssetData->m_assetUrl == assetUrl) { - m_assetLibrary = [g_currentAssetData->m_assetLibrary retain]; - m_asset = [g_currentAssetData->m_asset retain]; - return; - } + ensureAuthorizationDialogNotBlocked(); + + 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; } } @@ -90,6 +211,26 @@ public: 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) { @@ -101,17 +242,15 @@ public: dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_release(semaphore); - QMutexLocker lock(&g_mutex); - g_currentAssetData = this; + g_assetDataCache.setLocalData(this); } ~QIOSAssetData() { - QMutexLocker lock(&g_mutex); [m_assetLibrary release]; [m_asset release]; - if (this == g_currentAssetData) - g_currentAssetData = 0; + if (g_assetDataCache.localData() == this) + g_assetDataCache.setLocalData(0); } ALAsset *m_asset; @@ -119,21 +258,67 @@ public: private: QString m_assetUrl; ALAssetsLibrary *m_assetLibrary; +}; + +// ------------------------------------------------------------------------- - static QBasicMutex g_mutex; - static QPointer<QIOSAssetData> g_currentAssetData; +#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 + { + return QFileInfo(currentFileName()); + } }; -QBasicMutex QIOSAssetData::g_mutex; -QPointer<QIOSAssetData> QIOSAssetData::g_currentAssetData = 0; +#endif // ------------------------------------------------------------------------- QIOSFileEngineAssetsLibrary::QIOSFileEngineAssetsLibrary(const QString &fileName) - : m_fileName(fileName) - , m_offset(0) + : m_offset(0) , m_data(0) { + setFileName(fileName); } QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() @@ -143,18 +328,8 @@ QIOSFileEngineAssetsLibrary::~QIOSFileEngineAssetsLibrary() ALAsset *QIOSFileEngineAssetsLibrary::loadAsset() const { - if (!m_data) { - // 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 check if we still - // have two leading slashes after the scheme, and restore the second slash if not. - QString assetUrl = m_fileName; - const int index = 16; // "assets-library://" - if (assetUrl[index] != QLatin1Char('/')) - assetUrl.insert(index, '/'); - - m_data = new QIOSAssetData(assetUrl, const_cast<QIOSFileEngineAssetsLibrary *>(this)); - } - + if (!m_data) + m_data = new QIOSAssetData(m_assetUrl, const_cast<QIOSFileEngineAssetsLibrary *>(this)); return m_data->m_asset; } @@ -179,15 +354,21 @@ bool QIOSFileEngineAssetsLibrary::close() QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractFileEngine::FileFlags type) const { QAbstractFileEngine::FileFlags flags = 0; - if (!loadAsset()) + 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) - flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; + if (type & PermsMask) { + ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus]; + if (status != ALAuthorizationStatusRestricted && status != ALAuthorizationStatusDenied) + flags |= ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm; + } if (type & TypesMask) - flags |= FileType; + flags |= isDir ? DirectoryType : FileType; return flags; } @@ -245,11 +426,32 @@ 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.JPG?")); + if (index == -1) + m_assetUrl = QLatin1String("assets-library://"); + else + m_assetUrl = QLatin1String("assets-library://asset/") + file.mid(index); } QStringList QIOSFileEngineAssetsLibrary::entryList(QDir::Filters filters, const QStringList &filterNames) const { - Q_UNUSED(filters); - Q_UNUSED(filterNames); - return QStringList(); + 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/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 986fef7725..b4050b8f62 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -77,6 +77,15 @@ QIOSIntegration::QIOSIntegration() "'applicationDidFinishLaunching' inside your UIApplication delegate.\n"); } + // The backingstore needs a global share context in order to support composition in + // QPlatformBackingStore. + qApp->setAttribute(Qt::AA_ShareOpenGLContexts, true); + // And that context must match the format used for the backingstore's context. + QSurfaceFormat fmt; + fmt.setDepthBufferSize(16); + fmt.setStencilBufferSize(8); + QSurfaceFormat::setDefaultFormat(fmt); + // Set current directory to app bundle folder QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String])); @@ -137,6 +146,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const return false; case ApplicationState: return true; + case RasterGLSurface: + return true; default: return QPlatformIntegration::hasCapability(cap); } diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 777a3c12c5..80fba00ffb 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -119,7 +119,8 @@ void QIOSWindow::setVisible(bool visible) } if (visible && shouldAutoActivateWindow()) { - requestActivateWindow(); + if (!window()->property("_q_showWithoutActivating").toBool()) + requestActivateWindow(); } else if (!visible && [m_view isActiveWindow]) { // Our window was active/focus window but now hidden, so relinquish // focus to the next possible window in the stack. @@ -145,6 +146,9 @@ void QIOSWindow::setVisible(bool visible) bool QIOSWindow::shouldAutoActivateWindow() const { + if (![m_view canBecomeFirstResponder]) + return false; + // We don't want to do automatic window activation for popup windows // that are unlikely to contain editable controls (to avoid hiding // the keyboard while the popup is showing) diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 3039b89a1a..c6ef843b9f 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -77,7 +77,7 @@ if (QIOSIntegration::instance()->debugWindowManagement()) { static CGFloat hue = 0.0; CGFloat lastHue = hue; - for (CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabsf(hue - lastHue)) + for (CGFloat diff = 0; diff < 0.1 || diff > 0.9; diff = fabs(hue - lastHue)) hue = drand48(); #define colorWithBrightness(br) \ @@ -194,7 +194,7 @@ - (BOOL)canBecomeFirstResponder { - return YES; + return !(m_qioswindow->window()->flags() & Qt::WindowDoesNotAcceptFocus); } - (BOOL)becomeFirstResponder @@ -280,6 +280,12 @@ // ------------------------------------------------------------------------- +-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event +{ + if (m_qioswindow->window()->flags() & Qt::WindowTransparentForInput) + return NO; + return [super pointInside:point withEvent:event]; +} - (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state { |