summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/ios
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@digia.com>2012-11-11 16:32:54 +0100
committerTor Arne Vestbø <tor.arne.vestbo@digia.com>2013-02-27 23:55:42 +0100
commite71ca36161626020f7c641dcc83c0c02dc4d561b (patch)
tree64b211b2091df5f3a5fec9887157ee43354baac1 /src/plugins/platforms/ios
parent3241f37711bd35988c7a21cc8a4833ec2fa3132d (diff)
iOS: Ensure UIApplicationMain is started before QApplication by wrapping main()
For the typical Qt app the developer will have an existing main() that looks something like: int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); return app.exec(); } To support this, we provide our own 'main' function in the qtmain static library that we link into the application, which calls UIApplicationMain and redirects to the 'main' function of the application after the event loop has started spinning. For this to work, the applications 'main' function needs to manually be renamed 'qt_main' for now. In a later patch, this renaming will happen automatically by redefining main from either a header file, or more likely, from the Makefile created by qmake. For the case of an iOS developer wanting to use Qt in their existing app the main will look something like: int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } This is supported right now by just linking in libqios.a without libqiosmain.a. QGuiApplication should then be created e.g inside the native apps application delegate (but QGuiApplication::exec should not be called). In the future, we plan to but use a wrapper library that brings in all the Qt dependencies into one single static library. This library will not link against qtmain, so there won't be a symbol clash if the -ObjC linker option is used. We should then add the required magic to the future Objective-C convenience wrapper for QML to bring up a QGuiApplication, which would allow using Qt from storyboards and NIBs. This would also be the place to inject our own application delegate into the mix, while proxying the delegate callbacks to the user's application delegate. Change-Id: Iba5ade114b27216be8285f36100fd735a08b9d59 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r--src/plugins/platforms/ios/ios.pro30
-rw-r--r--src/plugins/platforms/ios/plugin.mm (renamed from src/plugins/platforms/ios/main.mm)2
-rw-r--r--src/plugins/platforms/ios/plugin.pro30
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h3
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm31
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm14
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm12
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm9
-rw-r--r--src/plugins/platforms/ios/qtmain.mm98
-rw-r--r--src/plugins/platforms/ios/qtmain.pro8
10 files changed, 166 insertions, 71 deletions
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
index 2fe6a4cb3f..842ff17f1c 100644
--- a/src/plugins/platforms/ios/ios.pro
+++ b/src/plugins/platforms/ios/ios.pro
@@ -1,29 +1,3 @@
-TARGET = qios
+TEMPLATE = subdirs
-load(qt_plugin)
-DESTDIR = $$QT.gui.plugins/platforms
-
-QT += core-private gui-private platformsupport-private
-LIBS += -framework UIKit -framework QuartzCore
-
-OBJECTIVE_SOURCES = main.mm \
- qiosintegration.mm \
- qioswindow.mm \
- qiosscreen.mm \
- qioseventdispatcher.mm \
- qiosbackingstore.mm \
- qiosapplicationdelegate.mm \
- qioscontext.mm
-
-HEADERS = qiosintegration.h \
- qioswindow.h \
- qiosscreen.h \
- qioseventdispatcher.h \
- qiosbackingstore.h \
- qiosapplicationdelegate.h \
- qioscontext.h
-
-#HEADERS = qiossoftwareinputhandler.h
-
-target.path += $$[QT_INSTALL_PLUGINS]/platforms
-INSTALLS += target
+SUBDIRS += plugin.pro qtmain.pro
diff --git a/src/plugins/platforms/ios/main.mm b/src/plugins/platforms/ios/plugin.mm
index 6a04770e3e..3701ac7e28 100644
--- a/src/plugins/platforms/ios/main.mm
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -64,6 +64,6 @@ QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, cons
QT_END_NAMESPACE
-#include "main.moc"
+#include "plugin.moc"
Q_IMPORT_PLUGIN(QIOSIntegrationPlugin)
diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro
new file mode 100644
index 0000000000..8a2f63442d
--- /dev/null
+++ b/src/plugins/platforms/ios/plugin.pro
@@ -0,0 +1,30 @@
+TARGET = qios
+
+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 \
+ qioscontext.mm
+
+HEADERS = \
+ qiosintegration.h \
+ qioswindow.h \
+ qiosscreen.h \
+ qioseventdispatcher.h \
+ qiosbackingstore.h \
+ qiosapplicationdelegate.h \
+ qioscontext.h
+
+#HEADERS = qiossoftwareinputhandler.h
+
+target.path += $$[QT_INSTALL_PLUGINS]/platforms
+INSTALLS += target
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
index 10e415831d..442b37f1b3 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.h
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -48,3 +48,6 @@
@end
+@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate
+@end
+
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index 1b3dc18dd7..41a3fff84f 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -45,34 +45,13 @@
@implementation QIOSApplicationDelegate
+@synthesize window;
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Q_UNUSED(application)
Q_UNUSED(launchOptions)
- // If this application delegate is instanciated, it means that
- // this plugin also created UIApplication. We then also create a
- // window with a view controller, and set all QWindow views
- // as children of the controller view:
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- UIViewController *controller = [[UIViewController alloc] init];
- self.window.rootViewController = controller;
- controller.view = [[UIView alloc] init];
-
- QWindowList windows = QGuiApplication::topLevelWindows();
- for (int i=0; i<windows.size(); ++i) {
- if (QIOSWindow *w = static_cast<QIOSWindow *>(windows[i]->handle())) {
- UIView *winView = w->nativeView();
- if (winView && !winView.superview)
- [controller.view addSubview:winView];
- }
- }
-
- // Aid debugging during development
- self.window.backgroundColor = [UIColor cyanColor];
- controller.view.backgroundColor = [UIColor magentaColor];
-
- [self.window makeKeyAndVisible];
return YES;
}
@@ -104,6 +83,12 @@
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
+- (void)dealloc
+{
+ [window release];
+ [super dealloc];
+}
+
@end
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
index 252e375a54..9d455370c0 100644
--- a/src/plugins/platforms/ios/qioseventdispatcher.mm
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -191,23 +191,13 @@ bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
m_interrupted = false;
bool eventsProcessed = false;
- UIApplication *uiApplication = [UIApplication sharedApplication];
bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec);
bool useExecMode = execFlagSet && !excludeUserEvents;
if (useExecMode) {
- if (!uiApplication) {
- // No UIApplication has been started yet. We therefore start it now. Note that application
- // developers are free to call UIApplicationMain themselves instead of QApplication::exec()
- @autoreleasepool {
- QCoreApplicationPrivate *qAppPriv = static_cast<QCoreApplicationPrivate *>(QObjectPrivate::get(qApp));
- return UIApplicationMain(qAppPriv->argc, qAppPriv->argv, nil, NSStringFromClass([QIOSApplicationDelegate class]));
- }
- } else {
- NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
- while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted);
- }
+ NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+ while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted);
eventsProcessed = true;
} else {
if (!(flags & QEventLoop::WaitForMoreEvents))
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index d00d4a077f..fed278bffe 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -56,6 +56,18 @@ QIOSIntegration::QIOSIntegration()
: m_fontDatabase(new QCoreTextFontDatabase)
, m_screen(new QIOSScreen(QIOSScreen::MainScreen))
{
+ if (![UIApplication sharedApplication]) {
+ qWarning()
+ << "Error: You are creating QApplication before calling UIApplicationMain.\n"
+ << "If you are writing a native iOS application, and only want to use Qt for\n"
+ << "parts of the application, a good place to create QApplication is from within\n"
+ << "'applicationDidFinishLaunching' inside your UIApplication delegate.\n"
+ << "If you instead create a cross-platform Qt application and do not intend to call\n"
+ << "UIApplicationMain, you need to link in libqtmain.a, and substitute main with qt_main.\n"
+ << "This is normally done automatically by qmake.\n";
+ exit(-1);
+ }
+
screenAdded(m_screen);
}
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index cccd5ab133..5701ac8aa2 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -198,13 +198,8 @@ QIOSWindow::QIOSWindow(QWindow *window)
: QPlatformWindow(window)
, m_view([[EAGLView alloc] initWithQIOSWindow:this])
{
- UIApplication *uiApplication = [UIApplication sharedApplication];
- if (uiApplication) {
- if ([uiApplication.delegate isMemberOfClass:[QIOSApplicationDelegate class]])
- [uiApplication.delegate.window.rootViewController.view addSubview:m_view];
- }
-
- setWindowState(window->windowState());
+ if ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]])
+ [[UIApplication sharedApplication].delegate.window.rootViewController.view addSubview:m_view];
}
QIOSWindow::~QIOSWindow()
diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm
new file mode 100644
index 0000000000..9b4ce9918e
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.mm
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** 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 "qiosapplicationdelegate.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class]));
+ }
+}
+
+extern int qt_main(int argc, char *argv[]);
+
+@implementation QIOSMainWrapperApplicationDelegate
+
+- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ // We may have a window already from a NIB or storyboard
+ if (!self.window) {
+ // If not, we create one ourselves
+ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ UIViewController *controller = [[UIViewController alloc] init];
+ self.window.rootViewController = controller;
+ controller.view = [[UIView alloc] init];
+
+ // Aid debugging during development
+ self.window.backgroundColor = [UIColor cyanColor];
+ self.window.rootViewController.view.backgroundColor = [UIColor magentaColor];
+
+ [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 willFinishLaunchingWithOptions: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/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro
new file mode 100644
index 0000000000..7835c88eac
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.pro
@@ -0,0 +1,8 @@
+TARGET = qiosmain
+
+load(qt_plugin)
+
+OBJECTIVE_SOURCES = qtmain.mm
+
+target.path += $$[QT_INSTALL_PLUGINS]/platforms
+INSTALLS += target