summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r--src/plugins/platforms/ios/ios.pro39
-rw-r--r--src/plugins/platforms/ios/plugin.mm4
-rw-r--r--src/plugins/platforms/ios/plugin.pro36
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm48
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.h60
-rw-r--r--src/plugins/platforms/ios/qiosapplicationstate.mm162
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm2
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h133
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm322
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h1
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm11
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h3
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm10
-rw-r--r--src/plugins/platforms/ios/qiosmain_dummy.mm56
-rw-r--r--src/plugins/platforms/ios/qiosmain_wrapper.mm (renamed from src/plugins/platforms/ios/qtmain.mm)56
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm18
-rw-r--r--src/plugins/platforms/ios/qtmain.pro8
17 files changed, 418 insertions, 551 deletions
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index 842ff17f1c..9b957afd8c 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -1,3 +1,38 @@
-TEMPLATE = subdirs
+TARGET = qios
-SUBDIRS += plugin.pro qtmain.pro
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+LIBS += -framework Foundation -framework UIKit -framework QuartzCore
+
+OBJECTIVE_SOURCES = \
+ plugin.mm \
+ qiosmain_wrapper.mm \
+ qiosmain_dummy.mm \
+ qiosintegration.mm \
+ qioswindow.mm \
+ qiosscreen.mm \
+ qiosbackingstore.mm \
+ qiosapplicationdelegate.mm \
+ qiosapplicationstate.mm \
+ qiosviewcontroller.mm \
+ qioscontext.mm \
+ qiosinputcontext.mm \
+ qiostheme.mm \
+ qiosglobal.mm
+
+HEADERS = \
+ qiosintegration.h \
+ qioswindow.h \
+ qiosscreen.h \
+ qiosbackingstore.h \
+ qiosapplicationdelegate.h \
+ qiosapplicationstate.h \
+ qiosviewcontroller.h \
+ qioscontext.h \
+ qiosinputcontext.h \
+ qiostheme.h \
+ qiosglobal.h
+
+#HEADERS = qiossoftwareinputhandler.h
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm
index a93b6037ad..ca8ec936ae 100644
--- a/src/plugins/platforms/ios/plugin.mm
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -66,4 +66,8 @@ QT_END_NAMESPACE
#include "plugin.moc"
+// Dummy function that we explicitly tell the linker to look for,
+// so that the plugin's static initializer is included and run.
+extern "C" void qt_registerPlatformPlugin() {}
+
Q_IMPORT_PLUGIN(QIOSIntegrationPlugin)
diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro
deleted file mode 100644
index 591a0a67ed..0000000000
--- a/src/plugins/platforms/ios/plugin.pro
+++ /dev/null
@@ -1,36 +0,0 @@
-TARGET = qios
-
-PLUGIN_TYPE = platforms
-load(qt_plugin)
-
-QT += core-private gui-private platformsupport-private
-LIBS += -framework UIKit -framework QuartzCore
-
-OBJECTIVE_SOURCES = \
- plugin.mm \
- qiosintegration.mm \
- qioswindow.mm \
- qiosscreen.mm \
- qioseventdispatcher.mm \
- qiosbackingstore.mm \
- qiosapplicationdelegate.mm \
- qiosviewcontroller.mm \
- qioscontext.mm \
- qiosinputcontext.mm \
- qiostheme.mm \
- qiosglobal.mm
-
-HEADERS = \
- qiosintegration.h \
- qioswindow.h \
- qiosscreen.h \
- qioseventdispatcher.h \
- qiosbackingstore.h \
- qiosapplicationdelegate.h \
- qiosviewcontroller.h \
- qioscontext.h \
- qiosinputcontext.h \
- qiostheme.h \
- qiosglobal.h
-
-#HEADERS = qiossoftwareinputhandler.h
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index 10cbe529c4..571de9ffda 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -39,8 +39,11 @@
**
****************************************************************************/
-#import "qiosapplicationdelegate.h"
+#include "qiosapplicationdelegate.h"
+
+#include "qiosviewcontroller.h"
#include "qioswindow.h"
+
#include <QtCore/QtCore>
@implementation QIOSApplicationDelegate
@@ -93,4 +96,47 @@
@end
+extern int qt_user_main(int argc, char *argv[]);
+
+@implementation QIOSMainWrapperApplicationDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
+ self.qiosViewController = [[[QIOSViewController alloc] init] autorelease];
+ self.window.rootViewController = self.qiosViewController;
+
+#ifdef QT_DEBUG
+ self.window.backgroundColor = [UIColor cyanColor];
+#endif
+
+ [self.window makeKeyAndVisible];
+
+ // We schedule the main-redirection for the next eventloop pass so that we
+ // can return from this function and let UIApplicationMain finish its job.
+ [NSTimer scheduledTimerWithTimeInterval:.01f target:self
+ selector:@selector(runUserMain) userInfo:nil repeats:NO];
+
+ if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd])
+ return [super application:application didFinishLaunchingWithOptions:launchOptions];
+ else
+ return YES;
+}
+
+- (void)runUserMain
+{
+ NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ int argc = arguments.count;
+ char **argv = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ NSString *arg = [arguments objectAtIndex:i];
+ argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
+ strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
+ }
+
+ qt_user_main(argc, argv);
+ delete[] argv;
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.h b/src/plugins/platforms/ios/qiosapplicationstate.h
new file mode 100644
index 0000000000..e726ad895e
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationstate.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSAPPLICATIONSTATE_H
+#define QIOSAPPLICATIONSTATE_H
+
+QT_BEGIN_NAMESPACE
+
+@class QIOSApplicationStateListener;
+
+class QIOSApplicationState
+{
+public:
+ QIOSApplicationState();
+ ~QIOSApplicationState();
+private:
+ QIOSApplicationStateListener *m_listener;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm
new file mode 100644
index 0000000000..df64edf465
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationstate.mm
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+#include <qpa/qwindowsysteminterface.h>
+#include "qiosapplicationstate.h"
+
+@interface QIOSApplicationStateListener : NSObject
+@end
+
+@implementation QIOSApplicationStateListener
+
+- (id) init
+{
+ self = [super init];
+ if (self) {
+ // Listen for application state changes.
+ // Note: We use notifications rather than application delegate callbacks to
+ // also support hybrid applications were QIOSApplicationDelegate is not in use.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationDidBecomeActive)
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationWillResignActive)
+ name:UIApplicationWillResignActiveNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationDidEnterBackground)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:UIApplicationDidBecomeActiveNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:UIApplicationWillResignActiveNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
+ [super dealloc];
+}
+
+- (void) applicationDidBecomeActive
+{
+ [self handleApplicationStateChanged:UIApplicationStateActive];
+}
+
+- (void) applicationWillResignActive
+{
+ // Note that UIApplication is still UIApplicationStateActive at this
+ // point, but since there is no separate notification for the inactive
+ // state, we report UIApplicationStateInactive now:
+ [self handleApplicationStateChanged:UIApplicationStateInactive];
+}
+
+- (void) applicationDidEnterBackground
+{
+ [self handleApplicationStateChanged:UIApplicationStateBackground];
+}
+
+- (void) handleApplicationStateChanged:(UIApplicationState) uiApplicationState
+{
+ Qt::ApplicationState state;
+ switch (uiApplicationState) {
+ case UIApplicationStateActive:
+ // The application is visible in front, and receiving events:
+ state = Qt::ApplicationActive;
+ break;
+ case UIApplicationStateInactive:
+ // The app is running in the foreground but is not receiving events. This
+ // typically happens while transitioning to/from active/background, like
+ // upon app launch or when receiving incoming calls:
+ state = Qt::ApplicationInactive;
+ break;
+ case UIApplicationStateBackground:
+ // Normally the app would enter this state briefly before it gets
+ // suspeded (you have five seconds, according to Apple).
+ // You can request more time and start a background task, which would
+ // normally map closer to Qt::ApplicationHidden. But since we have no
+ // API for doing that yet, we handle this state as "about to be suspended".
+ // Note: A screen-shot for the SpringBoard will also be taken after this
+ // call returns.
+ state = Qt::ApplicationSuspended;
+ break;
+ }
+ QWindowSystemInterface::handleApplicationStateChanged(state);
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+QIOSApplicationState::QIOSApplicationState()
+ : m_listener([[QIOSApplicationStateListener alloc] init])
+{
+ // Update the current state now, since we have missed all the updates
+ // posted from AppKit so far. But let QPA finish initialization first:
+ dispatch_async(dispatch_get_main_queue(), ^{
+ UIApplicationState state = [UIApplication sharedApplication].applicationState;
+ [m_listener handleApplicationStateChanged:state];
+ });
+}
+
+QIOSApplicationState::~QIOSApplicationState()
+{
+ [m_listener release];
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 87bcc01d04..85f560a722 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -200,7 +200,7 @@ void QIOSContext::windowDestroyed(QObject *object)
QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName)
{
- return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData()));
+ return QFunctionPointer(dlsym(RTLD_DEFAULT, functionName.constData()));
}
#include "moc_qioscontext.cpp"
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
deleted file mode 100644
index 53a75618ce..0000000000
--- a/src/plugins/platforms/ios/qioseventdispatcher.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/****************************************************************************
-**
-** Copyright (c) 2007-2008, Apple, Inc.
-**
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are met:
-**
-** * Redistributions of source code must retain the above copyright notice,
-** this list of conditions and the following disclaimer.
-**
-** * Redistributions in binary form must reproduce the above copyright notice,
-** this list of conditions and the following disclaimer in the documentation
-** and/or other materials provided with the distribution.
-**
-** * Neither the name of Apple, Inc. nor the names of its contributors
-** may be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**
-****************************************************************************/
-
-#ifndef QEVENTDISPATCHER_IOS_P_H
-#define QEVENTDISPATCHER_IOS_P_H
-
-#include <QtCore/qabstracteventdispatcher.h>
-#include <QtCore/private/qtimerinfo_unix_p.h>
-#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-QT_BEGIN_NAMESPACE
-
-class QIOSEventDispatcher : public QAbstractEventDispatcher
-{
- Q_OBJECT
-
-public:
- explicit QIOSEventDispatcher(QObject *parent = 0);
- ~QIOSEventDispatcher();
-
- bool processEvents(QEventLoop::ProcessEventsFlags flags);
- bool hasPendingEvents();
-
- void registerSocketNotifier(QSocketNotifier *notifier);
- void unregisterSocketNotifier(QSocketNotifier *notifier);
-
- void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object);
- bool unregisterTimer(int timerId);
- bool unregisterTimers(QObject *object);
- QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const;
-
- int remainingTime(int timerId);
-
- void wakeUp();
- void interrupt();
- void flush();
-
-private:
- bool m_interrupted;
-
- CFRunLoopSourceRef m_postedEventsRunLoopSource;
- CFRunLoopSourceRef m_blockingTimerRunLoopSource;
-
- QTimerInfoList m_timerInfoList;
- CFRunLoopTimerRef m_runLoopTimerRef;
-
- QCFSocketNotifier m_cfSocketNotifier;
-
- void processPostedEvents();
- void maybeStartCFRunLoopTimer();
- void maybeStopCFRunLoopTimer();
-
- static void postedEventsRunLoopCallback(void *info);
- static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info);
- static void blockingTimerRunLoopCallback(void *info);
-};
-
-QT_END_NAMESPACE
-
-#endif // QEVENTDISPATCHER_IOS_P_H
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
deleted file mode 100644
index e9bf039047..0000000000
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ /dev/null
@@ -1,322 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/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 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qioseventdispatcher.h"
-#import "qiosapplicationdelegate.h"
-#include <qdebug.h>
-#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/QThread>
-#include <QtCore/private/qcoreapplication_p.h>
-#include <UIKit/UIApplication.h>
-
-QT_BEGIN_NAMESPACE
-QT_USE_NAMESPACE
-
-static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2)
-{
- return info1 == info2;
-}
-
-void QIOSEventDispatcher::postedEventsRunLoopCallback(void *info)
-{
- QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
- self->processPostedEvents();
-}
-
-void QIOSEventDispatcher::nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info)
-{
- // The (one and only) CFRunLoopTimer has fired, which means that at least
- // one QTimer should now fire as well. Note that CFRunLoopTimer's callback will
- // never recurse. So if the app starts a new QEventLoop within this callback, other
- // timers will stop working. The work-around is to forward the callback to a
- // dedicated CFRunLoopSource that can recurse:
- QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
- CFRunLoopSourceSignal(self->m_blockingTimerRunLoopSource);
-}
-
-void QIOSEventDispatcher::blockingTimerRunLoopCallback(void *info)
-{
- // TODO:
- // We also need to block this new timer source
- // along with the posted event source when calling processEvents()
- // "manually" to prevent livelock deep in CFRunLoop.
-
- QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
- self->m_timerInfoList.activateTimers();
- self->maybeStartCFRunLoopTimer();
-}
-
-void QIOSEventDispatcher::maybeStartCFRunLoopTimer()
-{
- // Find out when the next registered timer should fire, and schedule
- // runLoopTimer accordingly. If the runLoopTimer does not yet exist, and
- // at least one timer is registered, start by creating the timer:
- if (m_timerInfoList.isEmpty()) {
- Q_ASSERT(m_runLoopTimerRef == 0);
- return;
- }
-
- CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
- CFTimeInterval interval;
-
- if (m_runLoopTimerRef == 0) {
- // start the CFRunLoopTimer
- CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
-
- // calculate when the next timer should fire:
- struct timespec tv;
- if (m_timerInfoList.timerWait(tv)) {
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
- } else {
- // this shouldn't really happen, but in case it does, set the timer
- // to fire a some point in the distant future:
- interval = oneyear;
- }
-
- ttf += interval;
- CFRunLoopTimerContext info = { 0, this, 0, 0, 0 };
- // create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate()
- // documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working
- m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info);
- Q_ASSERT(m_runLoopTimerRef != 0);
-
- CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes);
- } else {
- struct timespec tv;
- // Calculate when the next timer should fire:
- if (m_timerInfoList.timerWait(tv)) {
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
- } else {
- // no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
- // point in the distant future (the timer interval is one year)
- interval = CFRunLoopTimerGetInterval(m_runLoopTimerRef);
- }
-
- ttf += interval;
- CFRunLoopTimerSetNextFireDate(m_runLoopTimerRef, ttf);
- }
-}
-
-void QIOSEventDispatcher::maybeStopCFRunLoopTimer()
-{
- if (m_runLoopTimerRef == 0)
- return;
-
- CFRunLoopTimerInvalidate(m_runLoopTimerRef);
- CFRelease(m_runLoopTimerRef);
- m_runLoopTimerRef = 0;
-}
-
-void QIOSEventDispatcher::processPostedEvents()
-{
- QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
-}
-
-QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
- : QAbstractEventDispatcher(parent)
- , m_interrupted(false)
- , m_runLoopTimerRef(0)
-{
- m_cfSocketNotifier.setHostEventDispatcher(this);
-
- CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
- CFRunLoopSourceContext context;
- bzero(&context, sizeof(CFRunLoopSourceContext));
- context.equal = runLoopSourceEqualCallback;
- context.info = this;
-
- // source used to handle timers:
- context.perform = QIOSEventDispatcher::blockingTimerRunLoopCallback;
- m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
- Q_ASSERT(m_blockingTimerRunLoopSource);
- CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
-
- // source used to handle posted events:
- context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback;
- m_postedEventsRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
- Q_ASSERT(m_postedEventsRunLoopSource);
- CFRunLoopAddSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
-}
-
-QIOSEventDispatcher::~QIOSEventDispatcher()
-{
- CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
- CFRunLoopRemoveSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
- CFRelease(m_postedEventsRunLoopSource);
-
- qDeleteAll(m_timerInfoList);
- maybeStopCFRunLoopTimer();
- CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
- CFRelease(m_blockingTimerRunLoopSource);
-
- m_cfSocketNotifier.removeSocketNotifiers();
-}
-
-bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
-{
- m_interrupted = false;
- bool eventsProcessed = false;
-
- bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
- bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec);
- bool useExecMode = execFlagSet && !excludeUserEvents;
-
- if (useExecMode) {
- NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
- while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted);
- eventsProcessed = true;
- } else {
- if (!(flags & QEventLoop::WaitForMoreEvents))
- wakeUp();
- eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- return eventsProcessed;
-}
-
-bool QIOSEventDispatcher::hasPendingEvents()
-{
- qDebug() << __FUNCTION__ << "not implemented";
- return false;
-}
-
-void QIOSEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
-{
- m_cfSocketNotifier.registerSocketNotifier(notifier);
-}
-
-void QIOSEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
-{
- m_cfSocketNotifier.unregisterSocketNotifier(notifier);
-}
-
-void QIOSEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
-{
-#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !obj) {
- qWarning("QIOSEventDispatcher::registerTimer: invalid arguments");
- return;
- } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QIOSEventDispatcher: timers cannot be started from another thread");
- return;
- }
-#endif
-
- m_timerInfoList.registerTimer(timerId, interval, timerType, obj);
- maybeStartCFRunLoopTimer();
-}
-
-bool QIOSEventDispatcher::unregisterTimer(int timerId)
-{
-#ifndef QT_NO_DEBUG
- if (timerId < 1) {
- qWarning("QIOSEventDispatcher::unregisterTimer: invalid argument");
- return false;
- } else if (thread() != QThread::currentThread()) {
- qWarning("QObject::killTimer: timers cannot be stopped from another thread");
- return false;
- }
-#endif
-
- bool returnValue = m_timerInfoList.unregisterTimer(timerId);
- m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
- return returnValue;
-}
-
-bool QIOSEventDispatcher::unregisterTimers(QObject *object)
-{
-#ifndef QT_NO_DEBUG
- if (!object) {
- qWarning("QIOSEventDispatcher::unregisterTimers: invalid argument");
- return false;
- } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QObject::killTimers: timers cannot be stopped from another thread");
- return false;
- }
-#endif
-
- bool returnValue = m_timerInfoList.unregisterTimers(object);
- m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
- return returnValue;
-}
-
-QList<QAbstractEventDispatcher::TimerInfo> QIOSEventDispatcher::registeredTimers(QObject *object) const
-{
-#ifndef QT_NO_DEBUG
- if (!object) {
- qWarning("QIOSEventDispatcher:registeredTimers: invalid argument");
- return QList<TimerInfo>();
- }
-#endif
-
- return m_timerInfoList.registeredTimers(object);
-}
-
-int QIOSEventDispatcher::remainingTime(int timerId)
-{
-#ifndef QT_NO_DEBUG
- if (timerId < 1) {
- qWarning("QIOSEventDispatcher::remainingTime: invalid argument");
- return -1;
- }
-#endif
-
- return m_timerInfoList.timerRemainingTime(timerId);
-}
-
-void QIOSEventDispatcher::wakeUp()
-{
- CFRunLoopSourceSignal(m_postedEventsRunLoopSource);
- CFRunLoopWakeUp(CFRunLoopGetMain());
-}
-
-void QIOSEventDispatcher::interrupt()
-{
- wakeUp();
- m_interrupted = true;
-}
-
-void QIOSEventDispatcher::flush()
-{
- // X11 only.
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
index 176ad05733..78c1b260e6 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.h
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -66,6 +66,7 @@ public:
private:
QIOSKeyboardListener *m_keyboardListener;
UIView *m_focusView;
+ bool m_hasPendingHideRequest;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 1d3ab12de9..d430589037 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -99,6 +99,7 @@ QIOSInputContext::QIOSInputContext()
: QPlatformInputContext()
, m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_focusView(0)
+ , m_hasPendingHideRequest(false)
{
}
@@ -120,12 +121,20 @@ void QIOSInputContext::showInputPanel()
// responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use.
// Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input
// actually came from. So in this respect, we're undermining iOS' responder chain.
+ m_hasPendingHideRequest = false;
[m_focusView becomeFirstResponder];
}
void QIOSInputContext::hideInputPanel()
{
- [m_focusView resignFirstResponder];
+ // Delay hiding the keyboard for cases where the user is transferring focus between
+ // 'line edits'. In that case the 'line edit' that lost focus will close the input
+ // panel, just to see that the new 'line edit' will open it again:
+ m_hasPendingHideRequest = true;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (m_hasPendingHideRequest)
+ [m_focusView resignFirstResponder];
+ });
}
bool QIOSInputContext::isInputPanelVisible() const
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index c352e0f2d2..4aaf98f839 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -46,6 +46,8 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qwindowsysteminterface.h>
+#include "qiosapplicationstate.h"
+
QT_BEGIN_NAMESPACE
class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
@@ -79,6 +81,7 @@ private:
QPlatformInputContext *m_inputContext;
QPlatformScreen *m_screen;
QTouchDevice *m_touchDevice;
+ QIOSApplicationState m_applicationState;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 61fd1c3d60..e31804f428 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -43,12 +43,13 @@
#include "qioswindow.h"
#include "qiosbackingstore.h"
#include "qiosscreen.h"
-#include "qioseventdispatcher.h"
#include "qioscontext.h"
#include "qiosinputcontext.h"
#include "qiostheme.h"
+#include <QtPlatformSupport/private/qioseventdispatcher_p.h>
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
+#include <QDir>
#include <QtDebug>
@@ -71,6 +72,9 @@ QIOSIntegration::QIOSIntegration()
exit(-1);
}
+ // Set current directory to app bundle folder
+ QDir::setCurrent(QString::fromUtf8([[[NSBundle mainBundle] bundlePath] UTF8String]));
+
screenAdded(m_screen);
m_touchDevice = new QTouchDevice;
@@ -86,6 +90,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const
return true;
case MultipleWindows:
return true;
+ case ApplicationState:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -129,6 +135,8 @@ QVariant QIOSIntegration::styleHint(StyleHint hint) const
switch (hint) {
case ShowIsFullScreen:
return true;
+ case SetFocusOnTouchRelease:
+ return true;
default:
return QPlatformIntegration::styleHint(hint);
}
diff --git a/src/plugins/platforms/ios/qiosmain_dummy.mm b/src/plugins/platforms/ios/qiosmain_dummy.mm
new file mode 100644
index 0000000000..28d7e59381
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosmain_dummy.mm
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+/*
+ This file provides a dummy implementation of qt_user_main, so that
+ we don't get an undefined symbol in the hybrid use-case, where we
+ don't rename main() to qt_user_main(). As long as the linker is not
+ passed -all_load, this translation unit is only picked up and used
+ if qt_user_main is not defined by the user's code.
+*/
+
+int qt_user_main(int, char **)
+{
+ qFatal("Hit dummy qt_user_main, this should never happen!");
+ return 0;
+}
diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qiosmain_wrapper.mm
index 19c98f2c59..4533add424 100644
--- a/src/plugins/platforms/ios/qtmain.mm
+++ b/src/plugins/platforms/ios/qiosmain_wrapper.mm
@@ -40,7 +40,17 @@
****************************************************************************/
#include "qiosapplicationdelegate.h"
-#include "qiosviewcontroller.h"
+
+/*
+ This file provides a wrapper implementation of main() for the non-
+ hybrid use-case. The user's main is renamed to qt_user_main by the
+ build rules, and we'll call out to that main at the appropriate time.
+
+ This file purposly only exports a single symbol, _main, so that
+ when the linker considers the translation unit for inclusion it
+ will discard it when main has already been defined in the user's
+ application for the hybrid use-case.
+*/
int main(int argc, char *argv[])
{
@@ -48,47 +58,3 @@ int main(int argc, char *argv[])
return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class]));
}
}
-
-extern int qt_main(int argc, char *argv[]);
-
-@implementation QIOSMainWrapperApplicationDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
- self.qiosViewController = [[[QIOSViewController alloc] init] autorelease];
- self.window.rootViewController = self.qiosViewController;
-
-#ifdef QT_DEBUG
- self.window.backgroundColor = [UIColor cyanColor];
-#endif
-
- [self.window makeKeyAndVisible];
-
- // We schedule the main-redirection for the next eventloop pass so that we
- // can return from this function and let UIApplicationMain finish its job.
- [NSTimer scheduledTimerWithTimeInterval:.01f target:self
- selector:@selector(runUserMain) userInfo:nil repeats:NO];
-
- if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd])
- return [super application:application didFinishLaunchingWithOptions:launchOptions];
- else
- return YES;
-}
-
-- (void)runUserMain
-{
- NSArray *arguments = [[NSProcessInfo processInfo] arguments];
- int argc = arguments.count;
- char **argv = new char*[argc];
- for (int i = 0; i < argc; ++i) {
- NSString *arg = [arguments objectAtIndex:i];
- argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
- strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
- }
-
- qt_main(argc, argv);
- delete[] argv;
-}
-
-@end
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 0c3ae8e834..4c8a16b0bc 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -247,6 +247,23 @@
return YES;
}
+- (BOOL)becomeFirstResponder
+{
+ // On iOS, a QWindow should only have input focus when the input panel is
+ // open. This is to stop cursors and focus rects from being drawn when the
+ // user cannot type. And since the keyboard will open when a view becomes
+ // the first responder, it's now a good time to inform QPA that the QWindow
+ // this view backs became active:
+ QWindowSystemInterface::handleWindowActivated(m_qioswindow->window());
+ return [super becomeFirstResponder];
+}
+
+- (BOOL)resignFirstResponder
+{
+ QWindowSystemInterface::handleWindowActivated(0);
+ return [super resignFirstResponder];
+}
+
- (BOOL)hasText
{
return YES;
@@ -416,7 +433,6 @@ void QIOSWindow::requestActivateWindow()
raise();
QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view);
- QPlatformWindow::requestActivateWindow();
}
void QIOSWindow::raiseOrLower(bool raise)
diff --git a/src/plugins/platforms/ios/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro
deleted file mode 100644
index cbcb272217..0000000000
--- a/src/plugins/platforms/ios/qtmain.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-TARGET = qiosmain
-
-PLUGIN_TYPE = platforms
-load(qt_plugin)
-
-QT += gui-private
-
-OBJECTIVE_SOURCES = qtmain.mm