diff options
95 files changed, 4170 insertions, 1684 deletions
@@ -2512,6 +2512,7 @@ fi case `basename "$XPLATFORM"` in win32-g++*) XPLATFORM_MINGW=yes;; esac case "$XPLATFORM" in *-maemo*) XPLATFORM_MAEMO=yes;; esac case "$XPLATFORM" in *qnx-*|*blackberry-*) XPLATFORM_QNX=yes;; esac +case "$XPLATFORM" in *ios*) XPLATFORM_IOS=yes;; esac if [ -d "$PLATFORM" ]; then QMAKESPEC="$PLATFORM" @@ -2620,6 +2621,11 @@ if [ "$CFG_FORCEDEBUGINFO" = "yes" ]; then QT_CONFIG="$QT_CONFIG force_debug_info" fi +# iOS builds should be static to be able to submit to the App Store +if [ "$XPLATFORM_IOS" = "yes" ]; then + CFG_SHARED="no" +fi + # disable GTK style support auto-detection on Mac if [ "$BUILD_ON_MAC" = "yes" ] && [ "$CFG_QGTKSTYLE" = "auto" ]; then CFG_QGTKSTYLE=no @@ -4026,7 +4032,8 @@ fi # detect neon support if [ "$CFG_ARCH" = "arm" ] && [ "${CFG_NEON}" = "auto" ]; then - if compileTest unix/neon "neon"; then + # The iOS toolchain has trouble building the pixman NEON draw-helpers + if [ "$XPLATFORM_IOS" != "yes" ] && compileTest unix/neon "neon"; then CFG_NEON=yes else CFG_NEON=no diff --git a/mkspecs/common/clang-mac.conf b/mkspecs/common/clang-mac.conf index f7fe50a50b..efe771d24d 100644 --- a/mkspecs/common/clang-mac.conf +++ b/mkspecs/common/clang-mac.conf @@ -3,3 +3,5 @@ QMAKE_OBJCFLAGS_PRECOMPILE = -x objective-c-header -c ${QMAKE_PCH_INPUT} - QMAKE_OBJCFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE QMAKE_OBJCXXFLAGS_PRECOMPILE = -x objective-c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} QMAKE_OBJCXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE + +QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvm.clang.1_0 diff --git a/mkspecs/common/ios.conf b/mkspecs/common/ios.conf index 7420b56daf..5ff2f9b416 100644 --- a/mkspecs/common/ios.conf +++ b/mkspecs/common/ios.conf @@ -3,17 +3,23 @@ # MAKEFILE_GENERATOR = UNIX -CONFIG += ios reduce_exports incremental global_init_link_order lib_version_first plugin_no_soname +CONFIG += app_bundle reduce_exports incremental global_init_link_order lib_version_first plugin_no_soname sdk QMAKE_INCREMENTAL_STYLE = sublib -# Qt can't build iOS app bundle :( -CONFIG -= app_bundle +# FIXME: Transform ios.conf to follow the same inheritance pattern as eg mac.conf and unix.conf +QMAKE_PLATFORM = ios $$QMAKE_PLATFORM # Not deploying to Mac OSX QMAKE_MACOSX_DEPLOYMENT_TARGET = +# But to iOS +QMAKE_IOS_DEPLOYMENT_TARGET = 4.3 + # Add iOS common folder to include path INCLUDEPATH += $$PWD/ios # iOS defines -DEFINES += DARWIN_NO_CARBON Q_OS_IOS QT_NO_CORESERVICES QT_NO_PRINTER QT_NO_PRINTDIALOG +DEFINES += DARWIN_NO_CARBON QT_NO_CORESERVICES QT_NO_PRINTER QT_NO_PRINTDIALOG + +# Universal target (iPhone and iPad) +QMAKE_IOS_TARGETED_DEVICE_FAMILY = 1,2 diff --git a/mkspecs/common/ios/arch.conf b/mkspecs/common/ios/arch.conf deleted file mode 100644 index 4ad96874fe..0000000000 --- a/mkspecs/common/ios/arch.conf +++ /dev/null @@ -1,84 +0,0 @@ -# -# Helper to set CPU architecture flags for iOS configurations -# -# Depends on: -# -# QMAKE_IPHONEOS_DEPLOYMENT_TARGET - set in mkspecs/common/ios/versions.conf -# -# Note: -# -# Must be included after load(qt_config) in mkspec for auto-detection based -# on GL/ES version (GL/ES 2.x implies armv7 on iOS). -# - -# Target architecture for iOS devices (armv6, armv7 or leave blank for default) -QMAKE_IOS_TARGET_ARCH = - -########################################################################### - -# Device? -!*simulator* { - # Let mkspec specify archictecture - *armv6*: QMAKE_IOS_TARGET_ARCH = armv6 - else:*armv7*: QMAKE_IOS_TARGET_ARCH = armv7 - - # ARMv7 architecture device (see below) is required for OpenGL/ES 2.x - isEmpty(QMAKE_IOS_TARGET_ARCH):contains(QT_CONFIG, opengles2): QMAKE_IOS_TARGET_ARCH = armv7 - - # No target architecture specified? - isEmpty(QMAKE_IOS_TARGET_ARCH) { - # iOS versions < 4.3 can be armv6 or armv7, so need armv6 for max. compatibility, - # assume that building for OpenGL/ES 1.x is targeting armv6 - lessThan(QMAKE_IPHONEOS_DEPLOYMENT_TARGET, "4.3")|contains(QT_CONFIG, opengles1) { - QMAKE_IOS_TARGET_ARCH = armv6 - } else: QMAKE_IOS_TARGET_ARCH = armv7 - } - - # Samsung S5PC100, Apple A4, A5, A5X - equals(QMAKE_IOS_TARGET_ARCH, "armv7") { - # iOS CPU architecture (armv7) - QMAKE_IOS_ARM_ARCH = __ARM_ARCH_7__ - - # Thumb2 instructions - QMAKE_IOS_ARM_FLAGS = -mthumb - QMAKE_IOS_ARM_ARCH += __MARM_THUMB__ - - # NEON instructions - *-g++*: QMAKE_IOS_ARM_FLAGS += -mfloat-abi=softfp -mfpu=neon - QMAKE_IOS_ARM_ARCH += __ARM_NEON__ - } else { - # Samsung S5L8900 - if(equals(QMAKE_IOS_TARGET_ARCH, "armv6")) { - # iOS CPU architecture (armv6) - QMAKE_IOS_ARM_ARCH = __ARM_ARCH_6__ - - # ARM instructions - QMAKE_IOS_ARM_FLAGS = -marm -mcpu=arm1176jzf-s - !*clang*: QMAKE_IOS_ARM_FLAGS += -march=armv6 - } else { - # Unsupported architecture - error("Invalid iOS target $${QMAKE_IOS_TARGET_ARCH}! Edit mkspecs/common/ios/arch.conf to specify target architecture.") - } - } -# Simulator is i386 only -} else: QMAKE_IOS_TARGET_ARCH = i386 - -# iOS architecture build flags -QMAKE_IOS_ARCH_FLAGS = -arch $$QMAKE_IOS_TARGET_ARCH -QMAKE_CFLAGS += $$QMAKE_IOS_ARCH_FLAGS -QMAKE_CXXFLAGS += $$QMAKE_IOS_ARCH_FLAGS -QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_IOS_ARCH_FLAGS -QMAKE_LFLAGS += $$QMAKE_IOS_ARCH_FLAGS -QMAKE_IOS_TARGET_ARCH = -QMAKE_IOS_ARCH_FLAGS = - -# Architecture specific defines/flags -!*simulator* { - DEFINES += $$QMAKE_IOS_ARM_ARCH - QMAKE_IOS_ARM_ARCH = - - QMAKE_CFLAGS += $$QMAKE_IOS_ARM_FLAGS - QMAKE_CXXFLAGS += $$QMAKE_IOS_ARM_FLAGS - QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_IOS_ARM_FLAGS - QMAKE_IOS_ARM_FLAGS = -} diff --git a/mkspecs/common/ios/clang.conf b/mkspecs/common/ios/clang.conf index 10d1dbd24e..7513a0a315 100644 --- a/mkspecs/common/ios/clang.conf +++ b/mkspecs/common/ios/clang.conf @@ -3,39 +3,32 @@ # # Depends on: # -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf +# QMAKE_IOS_XCODE_VERSION - set in macx-ios-clang/qmake.conf # # iOS build flags -QMAKE_IOS_CFLAGS = -fvisibility=hidden -fpascal-strings -fmessage-length=0 +QMAKE_IOS_CFLAGS += -fvisibility=hidden -fpascal-strings -fmessage-length=0 QMAKE_IOS_CFLAGS += -Wno-trigraphs -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -Wno-sign-conversion -QMAKE_IOS_CXXFLAGS = -fvisibility-inlines-hidden -QMAKE_IOS_OBJ_CFLAGS = -Wno-arc-abi -Wc++0x-extensions - -# Device or simulator specific flags -*simulator* { - QMAKE_IOS_CFLAGS += -fexceptions -fasm-blocks - QMAKE_IOS_OBJ_CFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch -} - -# Compiler version-specific flags -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - # Clang 3.1 flags (will be used for later versions too) - QMAKE_IOS_CFLAGS += -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-implicit-atomic-properties -Wformat -Wno-missing-braces -Wno-unused-function -Wno-unused-label -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-sign-compare -Wpointer-sign -Wno-newline-eof -Wdeprecated-declarations -Winvalid-offsetof -Wno-conversion - QMAKE_IOS_CXXFLAGS += -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wc++11-extensions - QMAKE_IOS_OBJ_CFLAGS += -Wno-deprecated-implementations -Wprotocol -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector - - # Warn about unsupported (later than 4.5) Xcode versions - !lessThan(QMAKE_IOS_XCODE_VERSION, "4.6"): warning("The version of Xcode installed on this system is not recognised - custom compiler settings may be necessary") -} else { - if (!lessThan(QMAKE_IOS_XCODE_VERSION, "4.2")) { - # Clang 3.0 flags - QMAKE_IOS_CFLAGS += -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits - } else { - # Older Clang versions are not supported - error("Unsupported Xcode version $${QMAKE_IOS_XCODE_VERSION}") - } -} +QMAKE_IOS_CXXFLAGS += -fvisibility-inlines-hidden +QMAKE_IOS_OBJ_CFLAGS += -Wno-arc-abi + +# Based on the following information, http://clang.llvm.org/doxygen/ObjCRuntime_8h_source.html, +# we can conclude that it's safe to always pass the following flags +QMAKE_IOS_OBJ_CFLAGS += -fobjc-nonfragile-abi -fobjc-legacy-dispatch + +# But these only apply to non-ARM targets +!contains(QT_ARCH, arm): QMAKE_IOS_CFLAGS += -fexceptions -fasm-blocks + +# Clang 3.1 (and above) flags +QMAKE_IOS_CFLAGS += -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-implicit-atomic-properties -Wformat -Wno-missing-braces -Wno-unused-function -Wno-unused-label -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-sign-compare -Wpointer-sign -Wno-newline-eof -Wdeprecated-declarations -Winvalid-offsetof -Wno-conversion +QMAKE_IOS_CXXFLAGS += -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors +QMAKE_IOS_OBJ_CFLAGS += -Wno-deprecated-implementations -Wprotocol -Wno-selector -Wno-strict-selector-match -Wno-undeclared-selector + +# We do not yet build with C++11 support, so warn about extensions unless they are used all over Qt +QMAKE_IOS_CXXFLAGS += -Wc++11-extensions -Wc++0x-extensions -Wno-c++11-long-long + +# Warn about unsupported (later than 4.5) Xcode versions +!lessThan(QMAKE_IOS_XCODE_VERSION, "4.7"): warning("The version of Xcode installed on this system is not recognised - custom compiler settings may be necessary") # Set build flags QMAKE_CFLAGS += $$QMAKE_IOS_CFLAGS diff --git a/mkspecs/common/ios/g++.conf b/mkspecs/common/ios/g++.conf deleted file mode 100644 index 8a1e0b20c0..0000000000 --- a/mkspecs/common/ios/g++.conf +++ /dev/null @@ -1,21 +0,0 @@ -# -# compiler settings for iOS g++ compilers -# - -# iOS build flags -QMAKE_IOS_CFLAGS = -fvisibility=hidden -fexceptions -fmessage-length=0 -QMAKE_IOS_CFLAGS += -Wno-trigraphs -Wreturn-type -Wunused-variable -QMAKE_IOS_CXXFLAGS = -fvisibility-inlines-hidden - -# Device or simulator specific flags -!*simulator*: QMAKE_IOS_OBJ_CFLAGS = -else: QMAKE_IOS_OBJ_CFLAGS = -fobjc-abi-version=2 -fobjc-legacy-dispatch - -# Set build flags -QMAKE_CFLAGS += $$QMAKE_IOS_CFLAGS -QMAKE_CXXFLAGS += $$QMAKE_IOS_CFLAGS $$QMAKE_IOS_CXXFLAGS -QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_IOS_CFLAGS $$QMAKE_IOS_CXXFLAGS $$QMAKE_IOS_OBJ_CFLAGS - -QMAKE_IOS_CFLAGS = -QMAKE_IOS_CXXFLAGS = -QMAKE_IOS_OBJ_CFLAGS = diff --git a/mkspecs/common/ios/llvm.conf b/mkspecs/common/ios/llvm.conf deleted file mode 100644 index fa2e519dd9..0000000000 --- a/mkspecs/common/ios/llvm.conf +++ /dev/null @@ -1,31 +0,0 @@ -# -# compiler settings for iOS llvm-g++ compilers -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -# iOS build flags -QMAKE_IOS_CFLAGS = -fvisibility=hidden -fpascal-strings -fmessage-length=0 -QMAKE_IOS_CFLAGS += -Wno-trigraphs -Wreturn-type -Wunused-variable -QMAKE_IOS_CXXFLAGS = -fvisibility-inlines-hidden - -# Device or simulator specific flags -!*simulator*: QMAKE_IOS_OBJ_CFLAGS = -else: QMAKE_IOS_OBJ_CFLAGS = -fobjc-abi-version=2 -fobjc-legacy-dispatch - -# Compiler version specific flags -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - # Xcode 4.3+ specific flags - QMAKE_IOS_CFLAGS += -Wuninitialized -} - -# Set build flags -QMAKE_CFLAGS += $$QMAKE_IOS_CFLAGS -QMAKE_CXXFLAGS += $$QMAKE_IOS_CFLAGS $$QMAKE_IOS_CXXFLAGS -QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_IOS_CFLAGS $$QMAKE_IOS_CXXFLAGS $$QMAKE_IOS_OBJ_CFLAGS - -QMAKE_IOS_CFLAGS = -QMAKE_IOS_CXXFLAGS = -QMAKE_IOS_OBJ_CFLAGS = diff --git a/mkspecs/common/ios/qmake.conf b/mkspecs/common/ios/qmake.conf index 6d38e16581..5164c48e12 100644 --- a/mkspecs/common/ios/qmake.conf +++ b/mkspecs/common/ios/qmake.conf @@ -3,63 +3,39 @@ # # Depends on: # -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# QMAKE_IOS_SDK_VERSION - set in mkspecs/common/ios/versions.conf -# QMAKE_IOSSIMULATOR_SDK_VERSION - set in mkspecs/common/ios/versions.conf -# - -# iOS SDK device type -!*simulator*: QMAKE_IOS_DEVICE_TYPE = iPhoneOS -else { - QMAKE_IOS_DEVICE_TYPE = iPhoneSimulator +# QMAKE_XCODE_DEVELOPER_PATH - set in mkspecs/common/xcode.conf - # Use simulator SDK version - QMAKE_IOS_SDK_VERSION = $$QMAKE_IOS_SIMULATOR_SDK_VERSION - QMAKE_IOS_SIMULATOR_SDK_VERSION = -} +QT_QPA_DEFAULT_PLATFORM = ios -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - # Xcode 4.3+ is stored in /Applications - QMAKE_IOS_XCODE_PATH = /Applications/Xcode.app/Contents -} else: QMAKE_IOS_XCODE_PATH = +QMAKE_XCODE_TOOLCHAIN_BIN_PATH = $$QMAKE_XCODE_DEVELOPER_PATH/Toolchains/XcodeDefault.xctoolchain/usr/bin -# iOS platform /Developer path -QMAKE_IOS_DEV_PATH = $$QMAKE_IOS_XCODE_PATH/Developer/Platforms/$${QMAKE_IOS_DEVICE_TYPE}.platform/Developer -QMAKE_IOS_XCODE_PATH = +QMAKE_XCODE_CODE_SIGN_IDENTITY = "iPhone Developer" -# iOS platform SDK path -QMAKE_IOS_SDK = $$QMAKE_IOS_DEV_PATH/SDKs/$${QMAKE_IOS_DEVICE_TYPE}$${QMAKE_IOS_SDK_VERSION}.sdk -QMAKE_IOS_DEV_PATH = -QMAKE_IOS_DEVICE_TYPE = +# iOS build tools +QMAKE_CC = $$QMAKE_XCODE_TOOLCHAIN_BIN_PATH/clang +QMAKE_CXX = $$QMAKE_XCODE_TOOLCHAIN_BIN_PATH/clang++ +QMAKE_FIX_RPATH = $$QMAKE_XCODE_TOOLCHAIN_BIN_PATH/install_name_tool -id +QMAKE_AR = $$QMAKE_XCODE_TOOLCHAIN_BIN_PATH/ar cq +QMAKE_RANLIB = $$QMAKE_XCODE_TOOLCHAIN_BIN_PATH/ranlib -s +QMAKE_LINK = $$QMAKE_CXX +QMAKE_LINK_SHLIB = $$QMAKE_CXX -QMAKE_CFLAGS += -isysroot $$QMAKE_IOS_SDK -QMAKE_CXXFLAGS += -isysroot $$QMAKE_IOS_SDK -QMAKE_OBJECTIVE_CFLAGS += -isysroot $$QMAKE_IOS_SDK -QMAKE_LFLAGS += -Wl,-syslibroot,$$QMAKE_IOS_SDK -QMAKE_IOS_SDK = +# Check that compiler is valid +!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the clang compiler") # Basic iOS frameworks needed for any GUI app QMAKE_LFLAGS += -framework Foundation -framework UIKit -framework QuartzCore -lz -# OpenGL ES1 -QMAKE_INCDIR_OPENGL_ES1 = $$QMAKE_IOS_SDK/System/Library/Frameworks/OpenGLES.framework/Headers +# No OpenGL ES1 +QMAKE_INCDIR_OPENGL_ES1 = QMAKE_LIBDIR_OPENGL_ES1 = -QMAKE_LIBS_OPENGL_ES1 = -framework OpenGLES +QMAKE_LIBS_OPENGL_ES1 = # OpenGL ES2 -QMAKE_INCDIR_OPENGL_ES2 = $$QMAKE_IOS_SDK/System/Library/Frameworks/OpenGLES.framework/Headers +QMAKE_INCDIR_OPENGL_ES2 = QMAKE_LIBDIR_OPENGL_ES2 = QMAKE_LIBS_OPENGL_ES2 = -framework OpenGLES # No desktop OpenGL QMAKE_INCDIR_OPENGL = QMAKE_LIBS_OPENGL = - -# Compiler-specific flags -!*-g++* { - # Objective-C/C++ precompile flags - QMAKE_OBJCFLAGS_PRECOMPILE = -x objective-c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} - QMAKE_OBJCFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE - QMAKE_OBJCXXFLAGS_PRECOMPILE = -x objective-c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} - QMAKE_OBJCXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE -} diff --git a/mkspecs/common/ios/versions.conf b/mkspecs/common/ios/versions.conf deleted file mode 100644 index b755068769..0000000000 --- a/mkspecs/common/ios/versions.conf +++ /dev/null @@ -1,184 +0,0 @@ -# -# Helper to set build tool & SDK versions for iOS configurations -# -# This file sets up the following configuration variables: -# -# QMAKE_IOS_XCODE_VERSION - version number of Xcode being used -# QMAKE_IOS_SDK_VERSION - version number of iOS device SDK -# QMAKE_IOS_SIMULATOR_SDK_VERSION - version number of iOS simulator SDK -# -# Used in: -# -# mkspecs/common/ios/clang.conf -# mkspecs/common/ios/llvm.conf -# mkspecs/common/ios/qmake.conf -# mkspecs/unsupported/macx-iosdevice-clang-legacy/qmake.conf -# mkspecs/unsupported/macx-iosdevice-clang/qmake.conf -# mkspecs/unsupported/macx-iosdevice-llvm-legacy/qmake.conf -# mkspecs/unsupported/macx-iosdevice-llvm/qmake.conf -# mkspecs/unsupported/macx-iosdevice-g++-legacy/qmake.conf -# mkspecs/unsupported/macx-iossimulator-llvm-legacy/qmake.conf -# mkspecs/unsupported/macx-iossimulator-llvm/qmake.conf -# mkspecs/unsupported/macx-iossimulator-g++-legacy/qmake.conf -# - -# -# IMPORTANT: -# -# Xcode versions <= 4.2.x must be installed in /Developer. -# Xcode versions >= 4.3.x must be installed in /Applications -# -# Xcode versions >= 4.10 & < 5.0 and versions >= 10.0 are not supported due to -# the way the version checks are done here. As Apple (so far) has not used -# minor version numbers greater than 3 for Xcode, and the Xcode major version -# has only changed three times in the period 2003-2012, this is viewed as an -# acceptable limitation. -# - -# -# Edit values below to match iOS build environment, or leave blank for -# autodetection (slower!) -# - -# Xcode version used for cross-compiling -QMAKE_IOS_XCODE_VERSION = - -# iOS SDK version used for cross-compiling for iOS devices -QMAKE_IOS_SDK_VERSION = - -# iOS SDK version used for cross-compiling for the iOS simulator -QMAKE_IOS_SIMULATOR_SDK_VERSION = - -# -# Do not edit values below here if using a pre-built SDK -# - -# Minimum iOS version required on deployment target (if not specified, will -# default to minimum version that guarantees ARMv7 & OpenGL/ES 2.x). -# -# No part of Qt or any known plugin uses features that require iOS versions -# later than 4.0. -QMAKE_IPHONEOS_DEPLOYMENT_TARGET = 4.0 - -########################################################################### - -# No Xcode version specified? -isEmpty(QMAKE_IOS_XCODE_VERSION) { - # Get version string from installed Xcode - exists(/Applications/Xcode.app/Contents/Developer) { - QMAKE_IOS_XCODE_INFO = $$system(/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -version) - } else: QMAKE_IOS_XCODE_INFO = $$system(/Developer/usr/bin/xcodebuild -version) - - # Extract Xcode version number from output - QMAKE_IOS_XCODE_VERSION = $$member(QMAKE_IOS_XCODE_INFO, 1) - QMAKE_IOS_XCODE_INFO = -} - -# Make sure Xcode version is valid -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - # Xcode 4.3+ is stored in /Applications - QMAKE_IOS_PLATFORM_PATH = /Applications/Xcode.app/Contents/Developer/Platforms - - # Make sure Xcode path is valid - !exists($$QMAKE_IOS_PLATFORM_PATH): error("Xcode is not installed in /Applications/Xcode.app! Edit mkspecs/common/ios/versions.conf to specify version installed.") -} else { - # Older Xcode versions are stored in /Developer - QMAKE_IOS_PLATFORM_PATH = /Developer/Platforms - - # Make sure Xcode path is valid - !exists($$QMAKE_IOS_PLATFORM_PATH): error("Xcode is not installed in /Developer! Edit mkspecs/common/ios/versions.conf to specify version installed.") -} - -# iOS 4.3 is the preferred version as it is the earliest version that is armv7/gles2 only -QMAKE_IPHONEOS_PREFERRED_TARGET = 4.3 - -# Building for iOS device? -!*simulator* { - # No iOS SDK version specified? - isEmpty(QMAKE_IOS_SDK_VERSION) { - # Get version string from installed Xcode - !lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - QMAKE_IOS_SDK_INFO = $$system(/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -showsdks) - } else: QMAKE_IOS_SDK_INFO = $$system(/Developer/usr/bin/xcodebuild -showsdks) - - # Get names of installed device SDKs - QMAKE_IOS_SDK_INFO = $$find(QMAKE_IOS_SDK_INFO, ^iphoneos) - for(v, QMAKE_IOS_SDK_INFO): { - # Extract SDK version number from output - v = $$replace(v,iphoneos,) - - # Use latest SDK version - greaterThan(v, $$QMAKE_IOS_SDK_VERSION): QMAKE_IOS_SDK_VERSION = $$v - } - QMAKE_IOS_SDK_INFO = - } - - # Make sure iOS SDK version is valid - !exists($$QMAKE_IOS_PLATFORM_PATH/iPhoneOS.platform/Developer/SDKs/iPhoneOS$${QMAKE_IOS_SDK_VERSION}.sdk) { - error("iOS $$QMAKE_IOS_SDK_VERSION SDK not found! Edit mkspecs/common/ios/versions.conf to specify version installed.") - } - - # No deployment target specified? - isEmpty(QMAKE_IPHONEOS_DEPLOYMENT_TARGET) { - # Use SDK version for iOS versions < preferred - lessThan(QMAKE_IOS_SDK_VERSION, $$QMAKE_IPHONEOS_PREFERRED_TARGET) { - QMAKE_IPHONEOS_DEPLOYMENT_TARGET = $$QMAKE_IOS_SDK_VERSION - } else: QMAKE_IPHONEOS_DEPLOYMENT_TARGET = $$QMAKE_IPHONEOS_PREFERRED_TARGET - } - - # Make sure iOS SDK version is >= iOS target version - !lessThan(QMAKE_IPHONEOS_DEPLOYMENT_TARGET, $$QMAKE_IOS_SDK_VERSION) { - error("Target iOS version is greater that iOS SDK version $$QMAKE_IOS_SDK_VERSION! Edit mkspecs/common/ios/versions.conf to specify target iOS version.") - } -# Building for iOS simulator -} else { - # No iOS simulator SDK version specified? - isEmpty(QMAKE_IOS_SIMULATOR_SDK_VERSION) { - # Get version string from installed Xcode - !lessThan(QMAKE_IOS_XCODE_VERSION, "4.3") { - QMAKE_IOS_SDK_INFO = $$system(/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -showsdks) - } else: QMAKE_IOS_SDK_INFO = $$system(/Developer/usr/bin/xcodebuild -showsdks) - - # Get names of installed device SDKs - QMAKE_IOS_SDK_INFO = $$find(QMAKE_IOS_SDK_INFO, ^iphonesimulator) - for(v, QMAKE_IOS_SDK_INFO): { - # Extract SDK version number from output - v = $$replace(v,iphonesimulator,) - - # Use latest SDK version - greaterThan(v, $$QMAKE_IOS_SIMULATOR_SDK_VERSION): QMAKE_IOS_SIMULATOR_SDK_VERSION = $$v - } - QMAKE_IOS_SDK_INFO = - } - - # Make sure iOS simulator SDK version is valid - !exists($$QMAKE_IOS_PLATFORM_PATH/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$${QMAKE_IOS_SIMULATOR_SDK_VERSION}.sdk) { - error("iOS $$QMAKE_IOS_SIMULATOR_SDK_VERSION simulator SDK not found! Edit mkspecs/common/ios/versions.conf to specify version installed.") - } - - # No deployment target specified? - isEmpty(QMAKE_IPHONEOS_DEPLOYMENT_TARGET) { - # Use SDK version for iOS versions < preferred - lessThan(QMAKE_IOS_SIMULATOR_SDK_VERSION, $$QMAKE_IPHONEOS_PREFERRED_TARGET) { - QMAKE_IPHONEOS_DEPLOYMENT_TARGET = $$QMAKE_IOS_SIMULATOR_SDK_VERSION - } else: QMAKE_IPHONEOS_DEPLOYMENT_TARGET = $$QMAKE_IPHONEOS_PREFERRED_TARGET - } - - # Make sure iOS simulator SDK version is >= iOS target version - !lessThan(QMAKE_IPHONEOS_DEPLOYMENT_TARGET, $$QMAKE_IOS_SIMULATOR_SDK_VERSION) { - error("Target iOS version is greater that iOS simulator SDK version $$QMAKE_IOS_SIMULATOR_SDK_VERSION! Edit mkspecs/common/ios/versions.conf to specify target iOS version.") - } -} - -QMAKE_IPHONEOS_PREFERRED_TARGET = -QMAKE_IOS_PLATFORM_PATH = - -# Set deployment target -QMAKE_IOS_VERSION_FLAGS = -miphoneos-version-min=$$QMAKE_IPHONEOS_DEPLOYMENT_TARGET - -# Set build flags -QMAKE_CFLAGS += $$QMAKE_IOS_VERSION_FLAGS -QMAKE_CXXFLAGS += $$QMAKE_IOS_VERSION_FLAGS -QMAKE_OBJECTIVE_CFLAGS += $$QMAKE_IOS_VERSION_FLAGS -QMAKE_LFLAGS += $$QMAKE_IOS_VERSION_FLAGS -QMAKE_IOS_VERSION_FLAGS = diff --git a/mkspecs/common/mac/qplatformdefs.h b/mkspecs/common/mac/qplatformdefs.h index 7d4b6a2427..7ee337cce4 100644 --- a/mkspecs/common/mac/qplatformdefs.h +++ b/mkspecs/common/mac/qplatformdefs.h @@ -42,8 +42,6 @@ #ifndef QPLATFORMDEFS_H #define QPLATFORMDEFS_H -#define QT_QPA_DEFAULT_PLATFORM_NAME "cocoa" - // Get Qt defines/settings #include "qglobal.h" diff --git a/mkspecs/common/xcode.conf b/mkspecs/common/xcode.conf new file mode 100644 index 0000000000..800e2e849c --- /dev/null +++ b/mkspecs/common/xcode.conf @@ -0,0 +1,13 @@ +# +# qmake configuration for Xcode +# + +# Get path of Xcode's Developer directory +QMAKE_XCODE_DEVELOPER_PATH = $$system(xcode-select --print-path) +isEmpty(QMAKE_XCODE_DEVELOPER_PATH): \ + error("Xcode path is not set. Please use xcode-select to choose Xcode installation path.") + +# Make sure Xcode path is valid +!exists($$QMAKE_XCODE_DEVELOPER_PATH): \ + error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.") + diff --git a/mkspecs/features/configure.prf b/mkspecs/features/configure.prf index 39144e7216..b4569df6d5 100644 --- a/mkspecs/features/configure.prf +++ b/mkspecs/features/configure.prf @@ -7,6 +7,9 @@ equals(MAKEFILE_GENERATOR, UNIX) { QMAKE_MAKE = mingw32-make } else:if(equals(MAKEFILE_GENERATOR, MSVC.NET)|equals(MAKEFILE_GENERATOR, MSBUILD)) { QMAKE_MAKE = nmake +} else:ios { + # iOS unsets MAKEFILE_GENERATOR in its default_pre.prf + QMAKE_MAKE = make } else { error("Configure tests are not supported with the $$MAKEFILE_GENERATOR Makefile generator.") } diff --git a/mkspecs/features/ios.prf b/mkspecs/features/ios.prf new file mode 100644 index 0000000000..841378e8dd --- /dev/null +++ b/mkspecs/features/ios.prf @@ -0,0 +1,25 @@ +isEmpty(QT_ARCH) { + # The iPhoneOS and iPhoneSimulator targets share the same toolchain, + # so when configure runs the arch tests it passes the correct sysroot, + # but we fail to pick up the architecture since we're not passing -arch + # yet. Xcode does not seem to have a way to run the shared toolchain + # in a way that will automatically do this (for example xcrun -sdk). + contains(QMAKE_MAC_SDK, iphoneos.*): QT_ARCH = armv7 + else: QT_ARCH = i386 # Simulator +} else { + # Fix up the QT_ARCH to be more specific + equals(QT_ARCH, arm) { + # Samsung S5PC100, Apple A4, A5, A5X + QT_ARCH = armv7 + + # FIXME: How do we support armv7s when Qt can't do universal builds? + } +} + +!equals(MAKEFILE_GENERATOR, XCODE) { + arch_flag = -arch $$QT_ARCH + QMAKE_CFLAGS += $$arch_flag + QMAKE_CXXFLAGS += $$arch_flag + QMAKE_OBJECTIVE_CFLAGS += $$arch_flag + QMAKE_LFLAGS += $$arch_flag +} diff --git a/mkspecs/features/ios/default_post.prf b/mkspecs/features/ios/default_post.prf new file mode 100644 index 0000000000..f5e7b3c02d --- /dev/null +++ b/mkspecs/features/ios/default_post.prf @@ -0,0 +1,43 @@ + +CONFIG(qt):contains(QT, gui):equals(TEMPLATE, app): CONFIG += gui_app + +isEmpty(MAKEFILE_GENERATOR) { + gui_app:app_bundle: \ + # For applications we want Xcode project files + MAKEFILE_GENERATOR = XCODE + else: \ + # For libs, etc we still want regular Makefiles + MAKEFILE_GENERATOR = UNIX +} + +gui_app { + # We have to do the link and dependency resolution for the platform plugin + # manually, since QTPLUGIN and the prl lookup logic does not support + # the -force_load link style. The -force_load option ensures that all + # symbols from the static library are included, not just the ones the + # linker have seen a use for so far. We need this because we load the platform + # plugin from the platform plugin itself, using Q_IMPORT_PLUGIN. + lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/libqios$$qtPlatformTargetSuffix() + LIBS += "-force_load $${lib_path_and_base}.$${QMAKE_EXTENSION_STATICLIB}" + LIBS += $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS) + + # Which means we don't want the auto-generated import for the platform plugin + CONFIG -= import_qpa_plugin + + !no_main_wrapper { + # We link the iosmain library manually as well, since it's not really a plugin + lib_name = qiosmain + lib_path_and_base = $$[QT_INSTALL_PLUGINS/get]/platforms/lib$${lib_name}$$qtPlatformTargetSuffix() + LIBS += -L$$[QT_INSTALL_PLUGINS/get]/platforms -l$${lib_name}$$qtPlatformTargetSuffix() + LIBS += $$fromfile($${lib_path_and_base}.prl, QMAKE_PRL_LIBS) + DEFINES += main=qt_main + } +} + +contains(MAKEFILE_GENERATOR, XCODE) { + ios_device_family.name = TARGETED_DEVICE_FAMILY + ios_device_family.value = $$QMAKE_IOS_TARGETED_DEVICE_FAMILY + QMAKE_MAC_XCODE_SETTINGS += ios_device_family +} + +load(default_post) diff --git a/mkspecs/features/ios/default_pre.prf b/mkspecs/features/ios/default_pre.prf new file mode 100644 index 0000000000..e2956bd77d --- /dev/null +++ b/mkspecs/features/ios/default_pre.prf @@ -0,0 +1,4 @@ +# Unset makefile generator, so we can auto-detect value in default_post +unset(MAKEFILE_GENERATOR) + +load(default_pre) diff --git a/mkspecs/features/mac/sdk.prf b/mkspecs/features/mac/sdk.prf index 4c3e2d2b5a..57dcf7f5eb 100644 --- a/mkspecs/features/mac/sdk.prf +++ b/mkspecs/features/mac/sdk.prf @@ -36,7 +36,15 @@ } !equals(MAKEFILE_GENERATOR, XCODE) { - version_min_flag = -m$${QMAKE_MAC_PLATFORM_NAME}-version-min=$$QMAKE_MACOSX_DEPLOYMENT_TARGET + # FIXME: Get the version_min_flag out of the platform's 'Native Build System.xcspec' + version_identifier = $$replace(QMAKE_MAC_PLATFORM_NAME, iphonesimulator, ios-simulator) + + ios:!host_build: \ + deployment_target = $$QMAKE_IOS_DEPLOYMENT_TARGET + else: \ + deployment_target = $$QMAKE_MACOSX_DEPLOYMENT_TARGET + + version_min_flag = -m$${version_identifier}-version-min=$$deployment_target QMAKE_CFLAGS += $$version_min_flag QMAKE_CXXFLAGS += $$version_min_flag QMAKE_OBJECTIVE_CFLAGS += $$version_min_flag diff --git a/mkspecs/macx-llvm/qmake.conf b/mkspecs/macx-llvm/qmake.conf index 43db8d850c..96e02dc913 100644 --- a/mkspecs/macx-llvm/qmake.conf +++ b/mkspecs/macx-llvm/qmake.conf @@ -16,6 +16,8 @@ include(../common/llvm.conf) QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 +QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42 + QMAKE_OBJCFLAGS_PRECOMPILE = -x objective-c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} QMAKE_OBJCFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE QMAKE_OBJCXXFLAGS_PRECOMPILE = -x objective-c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} diff --git a/mkspecs/unsupported/macx-ios-clang/Info.plist.app b/mkspecs/unsupported/macx-ios-clang/Info.plist.app new file mode 100755 index 0000000000..bcf7f41f27 --- /dev/null +++ b/mkspecs/unsupported/macx-ios-clang/Info.plist.app @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> +<plist version="0.9"> +<dict> + <key>CFBundleIconFile</key> + <string>@ICON@</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleSignature</key> + <string>@TYPEINFO@</string> + <key>CFBundleExecutable</key> + <string>@EXECUTABLE@</string> + <key>CFBundleIdentifier</key> + <string>com.yourcompany.@BUNDLEIDENTIFIER@</string> + <key>NOTE</key> + <string>This file was generated by Qt/QMake.</string> +</dict> +</plist> diff --git a/mkspecs/unsupported/macx-ios-clang/Info.plist.lib b/mkspecs/unsupported/macx-ios-clang/Info.plist.lib new file mode 100644 index 0000000000..97609ed0ce --- /dev/null +++ b/mkspecs/unsupported/macx-ios-clang/Info.plist.lib @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> +<plist version="0.9"> +<dict> + <key>CFBundlePackageType</key> + <string>FMWK</string> + <key>CFBundleShortVersionString</key> + <string>@SHORT_VERSION@</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleSignature</key> + <string>@TYPEINFO@</string> + <key>CFBundleExecutable</key> + <string>@LIBRARY@</string> + <key>NOTE</key> + <string>Please, do NOT change this file -- It was generated by Qt/QMake.</string> +</dict> +</plist> diff --git a/mkspecs/unsupported/macx-ios-clang/qmake.conf b/mkspecs/unsupported/macx-ios-clang/qmake.conf new file mode 100644 index 0000000000..8f176f3f83 --- /dev/null +++ b/mkspecs/unsupported/macx-ios-clang/qmake.conf @@ -0,0 +1,30 @@ +# +# qmake configuration for macx-ios-clang +# + +!load(device_config): error("Could not successfully load device configuration.") + +isEmpty(QMAKE_MAC_SDK): QMAKE_MAC_SDK = iphoneos + +# iOS is considered a variant of MacOS by Apple. We follow this to +# keep things simple, e.g. by defining Q_OS_MAC _and_ Q_OS_IOS. +include(../../common/mac.conf) + +include(../../common/gcc-base-ios.conf) +include(../../common/xcode.conf) +include(../../common/clang.conf) +include(../../common/clang-mac.conf) + +# Extract Xcode version using xcodebuild +version_info = $$system("$${QMAKE_XCODE_DEVELOPER_PATH}/usr/bin/xcodebuild -version") +QMAKE_IOS_XCODE_VERSION = $$member(version_info, 1) +unset(version_info) + +# Version check +lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") + +include(../../common/ios.conf) +include(../../common/ios/clang.conf) +include(../../common/ios/qmake.conf) + +load(qt_config) diff --git a/mkspecs/unsupported/macx-iosdevice-clang-legacy/qplatformdefs.h b/mkspecs/unsupported/macx-ios-clang/qplatformdefs.h index 5f80a17860..5f80a17860 100644 --- a/mkspecs/unsupported/macx-iosdevice-clang-legacy/qplatformdefs.h +++ b/mkspecs/unsupported/macx-ios-clang/qplatformdefs.h diff --git a/mkspecs/unsupported/macx-iosdevice-clang-legacy/qmake.conf b/mkspecs/unsupported/macx-iosdevice-clang-legacy/qmake.conf deleted file mode 100644 index ff8e0b6aa9..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-clang-legacy/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-clang -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/clang.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/clang.conf) -include(../../common/ios/qmake.conf) - -# Version check -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.2.x or earlier") - -# iOS build tools -QMAKE_CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang -QMAKE_CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang++ -QMAKE_FIX_RPATH = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the clang compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-clang/qmake.conf b/mkspecs/unsupported/macx-iosdevice-clang/qmake.conf deleted file mode 100644 index 777b5ab6e2..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-clang/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-clang -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/clang.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/clang.conf) -include(../../common/ios/qmake.conf) - -# Version check -lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") - -# iOS build tools -QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -QMAKE_FIX_RPATH = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool -id -QMAKE_AR = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar cq -QMAKE_RANLIB = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the clang compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-g++-legacy/qmake.conf b/mkspecs/unsupported/macx-iosdevice-g++-legacy/qmake.conf deleted file mode 100644 index 5fcfb4a51d..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-g++-legacy/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-g++ -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/g++-macx.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/g++.conf) -include(../../common/ios/qmake.conf) - -# Version check (g++ was discontinued at version 4.2, but user may have added it themselves) -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.2.x or earlier") - -# iOS build tools -QMAKE_CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -QMAKE_CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2 -QMAKE_FIX_RPATH = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the g++ 4.2 compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-g++/qmake.conf b/mkspecs/unsupported/macx-iosdevice-g++/qmake.conf deleted file mode 100644 index 2a29335334..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-g++/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-g++ -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/g++-macx.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/g++.conf) -include(../../common/ios/qmake.conf) - -# Version check (g++ was discontinued at version 4.2, but user may have added it themselves) -lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") - -# iOS build tools -QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.2 -QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2 -QMAKE_FIX_RPATH = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the g++ 4.2 compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-g++/qplatformdefs.h b/mkspecs/unsupported/macx-iosdevice-g++/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-g++/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qmake.conf b/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qmake.conf deleted file mode 100644 index 4554843610..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-llvm -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/llvm.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/llvm.conf) -include(../../common/ios/qmake.conf) - -# Version check -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.2.x or earlier") - -# iOS build tools -QMAKE_CC = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-gcc-4.2 -QMAKE_CXX = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-g++-4.2 -QMAKE_FIX_RPATH = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the llvm-g++ 4.2 compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qplatformdefs.h b/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-llvm-legacy/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iosdevice-llvm/qmake.conf b/mkspecs/unsupported/macx-iosdevice-llvm/qmake.conf deleted file mode 100644 index 335c68fd42..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-llvm/qmake.conf +++ /dev/null @@ -1,35 +0,0 @@ -# -# qmake configuration for ios-device-llvm -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/llvm.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/llvm.conf) -include(../../common/ios/qmake.conf) - -# Version check -lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") - -# iOS build tools -QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-gcc-4.2 -QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/llvm-g++-4.2 -QMAKE_FIX_RPATH = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the llvm-g++ 4.2 compiler") - -load(qt_config) - -# Include after config is loaded to allow autodetection on GL/ES version -include(../../common/ios/arch.conf) diff --git a/mkspecs/unsupported/macx-iosdevice-llvm/qplatformdefs.h b/mkspecs/unsupported/macx-iosdevice-llvm/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iosdevice-llvm/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-clang-legacy/qmake.conf b/mkspecs/unsupported/macx-iossimulator-clang-legacy/qmake.conf deleted file mode 100644 index b042766a39..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-clang-legacy/qmake.conf +++ /dev/null @@ -1,6 +0,0 @@ -# -# qmake configuration for ios-simulator-clang -# - -# All differences between device and simulator are handled in iOS include files -include(../macx-iosdevice-clang-legacy/qmake.conf) diff --git a/mkspecs/unsupported/macx-iossimulator-clang-legacy/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-clang-legacy/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-clang-legacy/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-clang/qmake.conf b/mkspecs/unsupported/macx-iossimulator-clang/qmake.conf deleted file mode 100644 index 11301cb72f..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-clang/qmake.conf +++ /dev/null @@ -1,6 +0,0 @@ -# -# qmake configuration for ios-simulator-clang -# - -# All differences between device and simulator are handled in iOS include files -include(../macx-iosdevice-clang/qmake.conf) diff --git a/mkspecs/unsupported/macx-iossimulator-clang/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-clang/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-clang/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-g++-legacy/qmake.conf b/mkspecs/unsupported/macx-iossimulator-g++-legacy/qmake.conf deleted file mode 100644 index abc695231e..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-g++-legacy/qmake.conf +++ /dev/null @@ -1,33 +0,0 @@ -# -# qmake configuration for ios-simulator-g++ -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/g++-macx.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/arch.conf) -include(../../common/ios/g++.conf) -include(../../common/ios/qmake.conf) - -# Version check (g++ was discontinued at version 4.2) -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.2"): error("This mkspec requires Xcode 4.1.x or earlier") - -# iOS build tools -QMAKE_CC = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -QMAKE_CXX = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/g++-4.2 -QMAKE_FIX_RPATH = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the g++ 4.2 compiler") - -load(qt_config) diff --git a/mkspecs/unsupported/macx-iossimulator-g++-legacy/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-g++-legacy/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-g++-legacy/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-g++/qmake.conf b/mkspecs/unsupported/macx-iossimulator-g++/qmake.conf deleted file mode 100644 index 99848be410..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-g++/qmake.conf +++ /dev/null @@ -1,33 +0,0 @@ -# -# qmake configuration for ios-simulator-g++ -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/g++-macx.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/arch.conf) -include(../../common/ios/g++.conf) -include(../../common/ios/qmake.conf) - -# Version check (g++ was discontinued at version 4.2, but user may have added it themselves) -lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") - -# iOS build tools -QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc-4.2 -QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/g++-4.2 -QMAKE_FIX_RPATH = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the g++ 4.2 compiler") - -load(qt_config) diff --git a/mkspecs/unsupported/macx-iossimulator-g++/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-g++/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-g++/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qmake.conf b/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qmake.conf deleted file mode 100644 index 95d530cc18..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qmake.conf +++ /dev/null @@ -1,33 +0,0 @@ -# -# qmake configuration for ios-simulator-llvm -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/llvm.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/arch.conf) -include(../../common/ios/llvm.conf) -include(../../common/ios/qmake.conf) - -# Version check -!lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.2.x or earlier") - -# iOS build tools -QMAKE_CC = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-gcc-4.2 -QMAKE_CXX = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-g++-4.2 -QMAKE_FIX_RPATH = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the llvm-g++ 4.2 compiler") - -load(qt_config) diff --git a/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-llvm-legacy/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/mkspecs/unsupported/macx-iossimulator-llvm/qmake.conf b/mkspecs/unsupported/macx-iossimulator-llvm/qmake.conf deleted file mode 100644 index 7e3d4b5710..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-llvm/qmake.conf +++ /dev/null @@ -1,33 +0,0 @@ -# -# qmake configuration for ios-simulator-llvm -# -# Depends on: -# -# QMAKE_IOS_XCODE_VERSION - set in mkspecs/common/ios/versions.conf -# - -include(../../common/mac.conf) -include(../../common/gcc-base-ios.conf) -include(../../common/llvm.conf) -include(../../common/ios.conf) -include(../../common/ios/versions.conf) -include(../../common/ios/arch.conf) -include(../../common/ios/llvm.conf) -include(../../common/ios/qmake.conf) - -# Version check -lessThan(QMAKE_IOS_XCODE_VERSION, "4.3"): error("This mkspec requires Xcode 4.3 or later") - -# iOS build tools -QMAKE_CC = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-gcc-4.2 -QMAKE_CXX = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-g++-4.2 -QMAKE_FIX_RPATH = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/install_name_tool -id -QMAKE_AR = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ar cq -QMAKE_RANLIB = /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/ranlib -s -QMAKE_LINK = $$QMAKE_CXX -QMAKE_LINK_SHLIB = $$QMAKE_CXX - -# Check that compiler is valid -!exists($$QMAKE_CXX): error("The version of Xcode installed on this system does not include the llvm-g++ 4.2 compiler") - -load(qt_config) diff --git a/mkspecs/unsupported/macx-iossimulator-llvm/qplatformdefs.h b/mkspecs/unsupported/macx-iossimulator-llvm/qplatformdefs.h deleted file mode 100644 index 5f80a17860..0000000000 --- a/mkspecs/unsupported/macx-iossimulator-llvm/qplatformdefs.h +++ /dev/null @@ -1,42 +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 qmake spec 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 "../../common/ios/qplatformdefs.h" diff --git a/qmake/generators/mac/pbuilder_pbx.cpp b/qmake/generators/mac/pbuilder_pbx.cpp index 9893a7a7a4..923639d89d 100644 --- a/qmake/generators/mac/pbuilder_pbx.cpp +++ b/qmake/generators/mac/pbuilder_pbx.cpp @@ -46,6 +46,7 @@ #include <qregexp.h> #include <qcryptographichash.h> #include <qdebug.h> +#include <qstring.h> #include <stdlib.h> #include <time.h> #ifdef Q_OS_UNIX @@ -222,7 +223,6 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) << "\t\t\t" << writeSettings("lastKnownFileType", "wrapper.pb-project") << ";" << "\n" << "\t\t\t" << writeSettings("name", escapeFilePath(tmp_proj.first("TARGET") + projectSuffix())) << ";" << "\n" << "\t\t\t" << writeSettings("path", pbxproj) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<absolute>") << ";" << "\n" << "\t\t" << "};" << "\n"; //WRAPPER @@ -235,8 +235,7 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) t << "\t\t\t" << writeSettings("fileType", "compiled.mach-o.dylib") << ";" << "\n" << "\t\t\t" << writeSettings("path", tmp_proj.first("TARGET") + ".dylib") << ";" << "\n"; } - t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("remoteRef", keyFor(pbxproj + "_WRAPPERREF")) << ";" << "\n" + t << "\t\t\t" << writeSettings("remoteRef", keyFor(pbxproj + "_WRAPPERREF")) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n" << "\t\t" << "};" << "\n"; t << "\t\t" << keyFor(pbxproj + "_WRAPPERREF") << " = {" << "\n" @@ -252,7 +251,6 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) << "\t\t\t" << writeSettings("children", project->values(ProKey(pbxproj + "_WRAPPER")), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } @@ -291,14 +289,13 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER - //BUILDSTYLE - QString active_buildstyle; + //BUILDCONFIGURATIONS + QString defaultConfig; for(int as_release = 0; as_release < 2; as_release++) { QMap<QString, QString> settings; @@ -320,6 +317,8 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) } QString name = (as_release ? "Release" : "Debug"); + if (project->isActiveConfig("debug") != (bool)as_release) + defaultConfig = name; QString key = keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_" + name); project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS").append(key); t << "\t\t" << key << " = {" << "\n" @@ -330,26 +329,12 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) t << "\t\t\t" << "};" << "\n" << "\t\t\t" << writeSettings("name", name) << ";" << "\n" << "\t\t" << "};" << "\n"; - - key = keyFor("QMAKE_SUBDIR_PBX_BUILDSTYLE_" + name); - project->values("QMAKE_SUBDIR_PBX_BUILDSTYLES").append(key); - if (project->isActiveConfig("debug") != (bool)as_release) - active_buildstyle = name; - t << "\t\t" << key << " = {" << "\n" - << "\t\t\t" << writeSettings("buildRules", ProStringList(), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << "buildSettings = {" << "\n"; - for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it) - t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n"; - t << "\t\t\t" << "};" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXBuildStyle", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", name) << ";" << "\n" - << "\t\t" << "};" << "\n"; } t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_BUILDCONFIG_LIST") << " = {" << "\n" << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("buildConfigurations", project->values("QMAKE_SUBDIR_PBX_BUILDCONFIGS"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n" + << "\t\t\t" << writeSettings("defaultConfigurationName", defaultConfig, SettingsNoQuote) << ";" << "\n" << "\t\t" << "};" << "\n"; #ifdef GENERATE_AGGREGRATE_SUBDIR @@ -376,7 +361,6 @@ ProjectBuilderMakefileGenerator::writeSubDirs(QTextStream &t) t << "\t\t" << keyFor("QMAKE_SUBDIR_PBX_ROOT_GROUP") << " = {" << "\n" << "\t\t\t" << writeSettings("children", project->values("QMAKE_SUBDIR_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<group>") << ";" << "\n" << "\t\t" << "};" << "\n"; @@ -451,18 +435,17 @@ public: ProjectBuilderSources::ProjectBuilderSources(const QString &k, bool b, const QString &g, const QString &c, bool o) : buildable(b), object_output(o), key(k), group(g), compiler(c) { - if(group.isNull()) { - if(k == "SOURCES") - group = "Sources"; - else if(k == "HEADERS") - group = "Headers"; - else if(k == "QMAKE_INTERNAL_INCLUDED_FILES") - group = "Sources [qmake]"; - else if(k == "GENERATED_SOURCES" || k == "GENERATED_FILES") - group = "Temporary Sources"; - else - fprintf(stderr, "No group available for %s!\n", k.toLatin1().constData()); - } + // Override group name for a few common keys + if (k == "SOURCES" || k == "OBJECTIVE_SOURCES" || k == "HEADERS") + group = "Sources"; + else if (k == "QMAKE_INTERNAL_INCLUDED_FILES") + group = "Supporting Files"; + else if (k == "GENERATED_SOURCES" || k == "GENERATED_FILES") + group = "Generated Sources"; + else if (k == "RESOURCES") + group = "Resources"; + else if (group.isNull()) + group = QString("Sources [") + c + "]"; } QStringList @@ -470,7 +453,6 @@ ProjectBuilderSources::files(QMakeProject *project) const { QStringList ret = project->values(ProKey(key)).toQStringList(); if(key == "QMAKE_INTERNAL_INCLUDED_FILES") { - ret.prepend(project->projectFile()); for(int i = 0; i < ret.size(); ++i) { QStringList newret; if(!ret.at(i).endsWith(Option::prf_ext)) @@ -483,10 +465,48 @@ ProjectBuilderSources::files(QMakeProject *project) const return ret; } +static QString xcodeFiletypeForFilename(const QString &filename) +{ + foreach (const QString &ext, Option::cpp_ext) { + if (filename.endsWith(ext)) + return QStringLiteral("sourcecode.cpp.cpp"); + } + + foreach (const QString &ext, Option::c_ext) { + if (filename.endsWith(ext)) + return QStringLiteral("sourcecode.c.c"); + } + + foreach (const QString &ext, Option::h_ext) { + if (filename.endsWith(ext)) + return "sourcecode.c.h"; + } + + if (filename.endsWith(QStringLiteral(".mm"))) + return QStringLiteral("sourcecode.cpp.objcpp"); + if (filename.endsWith(QStringLiteral(".m"))) + return QStringLiteral("sourcecode.c.objc"); + if (filename.endsWith(QStringLiteral(".framework"))) + return QStringLiteral("wrapper.framework"); + if (filename.endsWith(QStringLiteral(".a"))) + return QStringLiteral("archive.ar"); + if (filename.endsWith(QStringLiteral(".pro")) || filename.endsWith(QStringLiteral(".qrc"))) + return QStringLiteral("text"); + + return QString(); +} bool ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) { + // The code in this function assumes that the current directory matches + // the output directory, which is not actually the case when we are called + // from the generic generator code. Instead of changing every single + // assumption and fileFixify we cheat by moving into the output directory + // for the duration of this function. + QString input_dir = qmake_getpwd(); + qmake_setpwd(Option::output_dir); + ProStringList tmp; bool did_preprocess = false; @@ -508,6 +528,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) QFile mkf(mkfile); if(mkf.open(QIODevice::WriteOnly | QIODevice::Text)) { writingUnixMakefileGenerator = true; + qmake_setpwd(input_dir); // Makefile generation assumes input_dir as pwd debug_msg(1, "pbuilder: Creating file: %s", mkfile.toLatin1().constData()); QTextStream mkt(&mkf); writeHeader(mkt); @@ -516,6 +537,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) mkt.flush(); mkf.close(); writingUnixMakefileGenerator = false; + qmake_setpwd(Option::output_dir); } QString phase_key = keyFor("QMAKE_PBX_MAKEQMAKE_BUILDPHASE"); mkfile = fileFixify(mkfile, qmake_getpwd()); @@ -523,15 +545,18 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t" << phase_key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("files", ProStringList(), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("generatedFileNames", ProStringList(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", "Qt Qmake") << ";" << "\n" - << "\t\t\t" << writeSettings("neededFileNames", ProStringList(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n" << "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";" << "\n" << "\t\t" << "};" << "\n"; } + // FIXME: Move all file resolving logic out of ProjectBuilderSources::files(), as it + // doesn't have access to any of the information it needs to resolve relative paths. + project->values("QMAKE_INTERNAL_INCLUDED_FILES").prepend(fileFixify(project->projectFile(), qmake_getpwd(), input_dir)); + //DUMP SOURCES QMap<QString, ProStringList> groups; QList<ProjectBuilderSources> sources; @@ -545,14 +570,13 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { if (project->isEmpty(ProKey(*it + ".output"))) continue; - ProString name = *it; - const ProKey nkey(*it + ".name"); - if (!project->isEmpty(nkey)) - name = project->first(nkey); - const ProStringList &inputs = project->values(ProKey(*it + ".input")); - for(int input = 0; input < inputs.size(); ++input) { - if (project->isEmpty(inputs.at(input).toKey())) + ProStringList &inputs = project->values(ProKey(*it + ".input")); + int input = 0; + while (input < inputs.size()) { + if (project->isEmpty(inputs.at(input).toKey())) { + ++input; continue; + } bool duplicate = false; bool isObj = project->values(ProKey(*it + ".CONFIG")).indexOf("no_link") == -1; if (!isObj) { @@ -572,8 +596,15 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) } } sources.append(ProjectBuilderSources(inputs.at(input).toQString(), true, - QString("Sources [") + name + "]", (*it).toQString(), isObj)); + QString(), (*it).toQString(), isObj)); + + if (isObj) { + inputs.removeAt(input); + continue; + } } + + ++input; } } } @@ -618,30 +649,29 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) } last_grp = new_grp; } + if (groups[last_grp].contains(src_key)) + continue; groups[last_grp] += src_key; in_root = false; } } - if(in_root) + if (in_root) { + if (src_list.contains(src_key)) + continue; src_list.append(src_key); + } //source reference t << "\t\t" << src_key << " = {" << "\n" << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n" - << "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(file)), SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("sourceTree", sourceTreeForFile(file)) << ";" << "\n"; - QString filetype; - for (QStringList::Iterator cppit = Option::cpp_ext.begin(); cppit != Option::cpp_ext.end(); ++cppit) { - if (file.endsWith((*cppit))) { - filetype = "sourcecode.cpp.cpp"; - break; - } - } + << "\t\t\t" << writeSettings("path", escapeFilePath(file)) << ";" << "\n"; + if (name != file) + t << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n"; + t << "\t\t\t" << writeSettings("sourceTree", sourceTreeForFile(file)) << ";" << "\n"; + QString filetype = xcodeFiletypeForFilename(file); if (!filetype.isNull()) t << "\t\t\t" << writeSettings("lastKnownFileType", filetype) << ";" << "\n"; t << "\t\t" << "};" << "\n"; - if(sources.at(source).isBuildable()) { //build reference + if (sources.at(source).isBuildable() && sources.at(source).isObjectOutput(file)) { //build reference QString build_key = keyFor(file + ".BUILDABLE"); t << "\t\t" << build_key << " = {" << "\n" << "\t\t\t" << writeSettings("fileRef", src_key) << ";" << "\n" @@ -650,8 +680,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t\t" << writeSettings("ATTRIBUTES", ProStringList(), SettingsAsList, 5) << ";" << "\n" << "\t\t\t" << "};" << "\n" << "\t\t" << "};" << "\n"; - if(sources.at(source).isObjectOutput(file)) - project->values("QMAKE_PBX_OBJ").append(build_key); + project->values("QMAKE_PBX_OBJ").append(build_key); } } if(!src_list.isEmpty()) { @@ -671,7 +700,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("children", grp_it.value(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("name", escapeFilePath(grp_it.key().section(Option::dir_sep, -1))) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } @@ -775,10 +803,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t" << phase_key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("files", ProStringList(), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("generatedFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", "Qt Preprocessors") << ";" << "\n" - << "\t\t\t" << writeSettings("neededFileNames", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << ";" << "\n" << "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";" << "\n" << "\t\t" << "};" << "\n"; @@ -786,12 +813,13 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) //SOURCE BUILDPHASE if(!project->isEmpty("QMAKE_PBX_OBJ")) { - QString grp = "Build Sources", key = keyFor(grp); + QString grp = "Compile Sources", key = keyFor(grp); project->values("QMAKE_PBX_BUILDPHASES").append(key); t << "\t\t" << key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("files", fixListForOutput("QMAKE_PBX_OBJ"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXSourcesBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", grp) << ";" << "\n" << "\t\t" << "};" << "\n"; } @@ -899,24 +927,25 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) libdirs += path; } library = fileFixify(library); + QString filetype = xcodeFiletypeForFilename(library); QString key = keyFor(library); - bool is_frmwrk = (library.endsWith(".framework")); - t << "\t\t" << key << " = {" << "\n" - << "\t\t\t" << writeSettings("isa", (is_frmwrk ? "PBXFrameworkReference" : "PBXFileReference"), SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n" - << "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(library)), SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("sourceTree", sourceTreeForFile(library)) << ";" << "\n" - << "\t\t" << "};" << "\n"; - project->values("QMAKE_PBX_LIBRARIES").append(key); - QString build_key = keyFor(library + ".BUILDABLE"); - t << "\t\t" << build_key << " = {" << "\n" - << "\t\t\t" << writeSettings("fileRef", key) << ";" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << "settings = {" << "\n" - << "\t\t\t" << "};" << "\n" - << "\t\t" << "};" << "\n"; - project->values("QMAKE_PBX_BUILD_LIBRARIES").append(build_key); + if (!project->values("QMAKE_PBX_LIBRARIES").contains(key)) { + t << "\t\t" << key << " = {" << "\n" + << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("name", escapeFilePath(name)) << ";" << "\n" + << "\t\t\t" << writeSettings("path", escapeFilePath(library)) << ";" << "\n" + << "\t\t\t" << writeSettings("sourceTree", sourceTreeForFile(library)) << ";" << "\n"; + if (!filetype.isNull()) + t << "\t\t\t" << writeSettings("lastKnownFileType", filetype) << ";" << "\n"; + t << "\t\t" << "};" << "\n"; + project->values("QMAKE_PBX_LIBRARIES").append(key); + QString build_key = keyFor(library + ".BUILDABLE"); + t << "\t\t" << build_key << " = {" << "\n" + << "\t\t\t" << writeSettings("fileRef", key) << ";" << "\n" + << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n" + << "\t\t" << "};" << "\n"; + project->values("QMAKE_PBX_BUILD_LIBRARIES").append(build_key); + } } if(remove) tmp.removeAt(x); @@ -955,10 +984,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t" << phase_key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("files", ProStringList(), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("generatedFileNames", ProStringList(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXShellScriptBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", "Qt Sublibs") << ";" << "\n" - << "\t\t\t" << writeSettings("neededFileNames", ProStringList(), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("shellPath", "/bin/sh") << "\n" << "\t\t\t" << writeSettings("shellScript", "make -C " + IoUtils::shellQuoteUnix(qmake_getpwd()) + " -f " + IoUtils::shellQuoteUnix(mkfile)) << ";" << "\n" << "\t\t" << "};" << "\n"; @@ -967,42 +995,24 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) if(!project->isEmpty("QMAKE_PBX_LIBRARIES")) { tmp = project->values("QMAKE_PBX_LIBRARIES"); if(!tmp.isEmpty()) { - QString grp("External Frameworks and Libraries"), key = keyFor(grp); + QString grp("Frameworks"), key = keyFor(grp); project->values("QMAKE_PBX_GROUPS").append(key); t << "\t\t" << key << " = {" << "\n" << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_LIBRARIES"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n" - << "\t\t\t" << writeSettings("path", ProStringList()) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } } { - QString grp("Frameworks & Libraries"), key = keyFor(grp); + QString grp("Link Binary With Libraries"), key = keyFor(grp); project->values("QMAKE_PBX_BUILDPHASES").append(key); t << "\t\t" << key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("files", project->values("QMAKE_PBX_BUILD_LIBRARIES"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXFrameworksBuildPhase", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n" - << "\t\t" << "};" << "\n"; - } - if(project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app") { //BUNDLE RESOURCES - QString grp("Bundle Resources"), key = keyFor(grp); - project->values("QMAKE_PBX_BUILDPHASES").append(key); - t << "\t\t" << key << " = {" << "\n" - << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << "files = (" << "\n"; - if(!project->isEmpty("ICON")) { - ProString icon = project->first("ICON"); - if (icon.length() >= 2 && (icon.at(0) == '"' || icon.at(0) == '\'') && icon.endsWith(icon.at(0))) - icon = icon.mid(1, icon.length()-2); - t << "\t\t\t\t" << keyFor(icon + ".BUILDABLE") << ",\n"; - } - t << "\t\t\t" << ");" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n" << "\t\t" << "};" << "\n"; } @@ -1024,78 +1034,96 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << writeSettings("shellScript", fixForOutput("cp -r $BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME " + escapeFilePath(destDir))) << ";" << "\n" << "\t\t" << "};\n"; } - //BUNDLE_DATA BUILDPHASE (copy) - if(!project->isEmpty("QMAKE_BUNDLE_DATA")) { + // Copy Bundle Resources + if (!project->isEmpty("QMAKE_BUNDLE_DATA")) { ProStringList bundle_file_refs; + ProStringList bundle_resources_files; + + bool useCopyResourcesPhase = project->isActiveConfig("app_bundle") && project->first("TEMPLATE") == "app"; + //all bundle data const ProStringList &bundle_data = project->values("QMAKE_BUNDLE_DATA"); for(int i = 0; i < bundle_data.count(); i++) { - ProStringList pbx_files; + ProStringList bundle_files; + ProString path = project->first(ProKey(bundle_data[i] + ".path")); //all files const ProStringList &files = project->values(ProKey(bundle_data[i] + ".files")); for(int file = 0; file < files.count(); file++) { QString fn = files[file].toQString(); - QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE_REF." + bundle_data[i] + "-" + fn); + QString file_ref_key = keyFor("QMAKE_PBX_BUNDLE_DATA_FILE_REF." + bundle_data[i] + "-" + fn); bundle_file_refs += file_ref_key; t << "\t\t" << file_ref_key << " = {" << "\n" << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("path", escapeFilePath(fn)) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", QString::number(reftypeForFile(fn)), SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", sourceTreeForFile(fn)) << ";" << "\n" << "\t\t" << "};" << "\n"; - QString copy_file_key = keyFor("QMAKE_PBX_BUNDLE_COPY_FILE." + bundle_data[i] + "-" + fn); - pbx_files += copy_file_key; - t << "\t\t" << copy_file_key << " = {\n" + QString file_key = keyFor("QMAKE_PBX_BUNDLE_DATA_FILE." + bundle_data[i] + "-" + fn); + bundle_files += file_key; + t << "\t\t" << file_key << " = {\n" << "\t\t\t" << writeSettings("fileRef", file_ref_key) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXBuildFile", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << "settings = {\n" - << "\t\t\t" << "}" << ";" << "\n" << "\t\t" << "}" << ";" << "\n"; } - //the phase - QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]); - QString path; - if (!project->isEmpty(ProKey(bundle_data[i] + ".version"))) { - //### + + if (!useCopyResourcesPhase || !path.isEmpty()) { + // The resource copy phase doesn't support paths, so we have to use + // a regular file copy phase (which doesn't optimize the resources). + QString phase_key = keyFor("QMAKE_PBX_BUNDLE_COPY." + bundle_data[i]); + if (!project->isEmpty(ProKey(bundle_data[i] + ".version"))) { + //### + } + + project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key); + t << "\t\t" << phase_key << " = {\n" + << "\t\t\t" << writeSettings("name", "Copy '" + bundle_data[i] + "' Files to Bundle") << ";" << "\n" + << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";" << "\n" + << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("files", bundle_files, SettingsAsList, 4) << ";" << "\n" + << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" + << "\t\t" << "}" << ";" << "\n"; + } else { + // Otherwise we leave it to the resource copy phase below + bundle_resources_files += bundle_files; + } + } + + if (useCopyResourcesPhase) { + if (!project->isEmpty("ICON")) { + ProString icon = project->first("ICON"); + if (icon.length() >= 2 && (icon.at(0) == '"' || icon.at(0) == '\'') && icon.endsWith(icon.at(0))) { + icon = icon.mid(1, icon.length() - 2); + bundle_resources_files += keyFor(icon + ".BUILDABLE"); + } } - path += project->first(ProKey(bundle_data[i] + ".path")); - project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES").append(phase_key); - t << "\t\t" << phase_key << " = {\n" - << "\t\t\t" << writeSettings("name", "Bundle Copy [" + bundle_data[i] + "]") << ";" << "\n" + + QString grp("Copy Bundle Resources"), key = keyFor(grp); + project->values("QMAKE_PBX_BUILDPHASES").append(key); + t << "\t\t" << key << " = {" << "\n" << "\t\t\t" << writeSettings("buildActionMask", "2147483647", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("dstPath", escapeFilePath(path)) << ";" << "\n" - << "\t\t\t" << writeSettings("dstSubfolderSpec", "1", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("files", pbx_files, SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXCopyFilesBuildPhase", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("files", bundle_resources_files, SettingsAsList, 4) << ";" << "\n" + << "\t\t\t" << writeSettings("isa", "PBXResourcesBuildPhase", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("runOnlyForDeploymentPostprocessing", "0", SettingsNoQuote) << ";" << "\n" - << "\t\t" << "}" << ";" << "\n"; + << "\t\t\t" << writeSettings("name", escapeFilePath(grp)) << ";" << "\n" + << "\t\t" << "};" << "\n"; } - QString bundle_copy_key = keyFor("QMAKE_PBX_BUNDLE_COPY"); - project->values("QMAKE_PBX_GROUPS").append(bundle_copy_key); - t << "\t\t" << bundle_copy_key << " = {" << "\n" + + QString bundle_data_key = keyFor("QMAKE_PBX_BUNDLE_DATA"); + project->values("QMAKE_PBX_GROUPS").append(bundle_data_key); + t << "\t\t" << bundle_data_key << " = {" << "\n" << "\t\t\t" << writeSettings("children", bundle_file_refs, SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", "Source [bundle data]") << ";" << "\n" - << "\t\t\t" << writeSettings("path", ProStringList()) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("name", "Bundle Resources") << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } - //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER - //ROOT_GROUP - t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n" - << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n" - << "\t\t\t" << writeSettings("path", ProStringList()) << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" - << "\t\t" << "};" << "\n"; //REFERENCE project->values("QMAKE_PBX_PRODUCTS").append(keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")); t << "\t\t" << keyFor(pbx_dir + "QMAKE_PBX_REFERENCE") << " = {" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n"; + << "\t\t\t" << writeSettings("isa", "PBXFileReference", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("includeInIndex", "0", SettingsNoQuote) << ";" << "\n"; if(project->first("TEMPLATE") == "app") { ProString targ = project->first("QMAKE_ORIG_TARGET"); if(project->isActiveConfig("bundle") && !project->isEmpty("QMAKE_BUNDLE_EXTENSION")) { @@ -1110,7 +1138,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) targ += ".app"; t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.application") << ";" << "\n"; } else { - t << "\t\t\t" << writeSettings("explicitFileType", "wrapper.executable") << ";" << "\n"; + t << "\t\t\t" << writeSettings("explicitFileType", "compiled.mach-o.executable") << ";" << "\n"; } QString app = (!project->isEmpty("DESTDIR") ? project->first("DESTDIR") + project->first("QMAKE_ORIG_TARGET") : qmake_getpwd()) + Option::dir_sep + targ; @@ -1144,8 +1172,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) } t << "\t\t\t" << writeSettings("path", escapeFilePath(lib)) << ";" << "\n"; } - t << "\t\t\t" << writeSettings("refType", "3", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n" + t << "\t\t\t" << writeSettings("sourceTree", "BUILT_PRODUCTS_DIR", SettingsNoQuote) << ";" << "\n" << "\t\t" << "};" << "\n"; { //Products group QString grp("Products"), key = keyFor(grp); @@ -1154,177 +1181,38 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_PRODUCTS"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("name", "Products") << ";" << "\n" - << "\t\t\t" << writeSettings("refType", "4", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" << "\t\t" << "};" << "\n"; } + + //DUMP EVERYTHING THAT TIES THE ABOVE TOGETHER + //ROOT_GROUP + t << "\t\t" << keyFor("QMAKE_PBX_ROOT_GROUP") << " = {" << "\n" + << "\t\t\t" << writeSettings("children", project->values("QMAKE_PBX_GROUPS"), SettingsAsList, 4) << ";" << "\n" + << "\t\t\t" << writeSettings("isa", "PBXGroup", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n" + << "\t\t\t" << writeSettings("sourceTree", "<Group>") << ";" << "\n" + << "\t\t" << "};" << "\n"; + //TARGET QString target_key = keyFor(pbx_dir + "QMAKE_PBX_TARGET"); project->values("QMAKE_PBX_TARGETS").append(target_key); t << "\t\t" << target_key << " = {" << "\n" << "\t\t\t" << writeSettings("buildPhases", project->values("QMAKE_PBX_PRESCRIPT_BUILDPHASES") + project->values("QMAKE_PBX_BUILDPHASES"), - SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << "buildSettings = {" << "\n"; - ProString cCompiler = project->first("QMAKE_CC"); - if (!cCompiler.isEmpty()) { - t << "\t\t\t\t" << writeSettings("CC", fixForOutput(findProgram(cCompiler))) << ";" << "\n"; - } - cCompiler = project->first("QMAKE_CXX"); - if (!cCompiler.isEmpty()) { - t << "\t\t\t\t" << writeSettings("CPLUSPLUS", fixForOutput(findProgram(cCompiler))) << ";" << "\n"; - } - - t << "\t\t\t\t" << writeSettings("LEXFLAGS", fixListForOutput("QMAKE_LEXFLAGS")) << ";" << "\n" - << "\t\t\t\t" << writeSettings("YACCFLAGS", fixListForOutput("QMAKE_YACCFLAGS")) << ";" << "\n" - << "\t\t\t\t" << writeSettings("OTHER_REZFLAGS", ProStringList()) << ";" << "\n" - << "\t\t\t\t" << writeSettings("SECTORDER_FLAGS", ProStringList()) << ";" << "\n" - << "\t\t\t\t" << writeSettings("WARNING_CFLAGS", ProStringList()) << ";" << "\n" - << "\t\t\t\t" << writeSettings("PREBINDING", ProStringList((project->isEmpty("QMAKE_DO_PREBINDING") ? "NO" : "YES")), SettingsNoQuote) << ";" << "\n"; - if((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) || - (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && - project->isActiveConfig("lib_bundle"))) { - QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString()); - if(plist.isEmpty()) - plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE"); - if(exists(plist)) { - QFile plist_in_file(plist); - if(plist_in_file.open(QIODevice::ReadOnly)) { - QTextStream plist_in(&plist_in_file); - QString plist_in_text = plist_in.readAll(); - plist_in_text = plist_in_text.replace("@ICON@", - (project->isEmpty("ICON") ? QString("") : project->first("ICON").toQString().section(Option::dir_sep, -1))); - if(project->first("TEMPLATE") == "app") { - plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET").toQString()); - } else { - plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET").toQString()); - } - if (!project->values("VERSION").isEmpty()) { - plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." + - project->first("VER_MIN")); - } - plist_in_text = plist_in_text.replace("@TYPEINFO@", - (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : - project->first("QMAKE_PKGINFO_TYPEINFO").left(4).toQString())); - QFile plist_out_file("Info.plist"); - if(plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream plist_out(&plist_out_file); - plist_out << plist_in_text; - t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n"; - } - } - } - } -#if 1 - t << "\t\t\t\t" << writeSettings("BUILD_ROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n"; -#endif - if(!project->isActiveConfig("staticlib")) { - t << "\t\t\t\t" << writeSettings("OTHER_LDFLAGS", - fixListForOutput("SUBLIBS") - + fixListForOutput("QMAKE_LFLAGS") - + fixListForOutput("QMAKE_LIBS") - + fixListForOutput("QMAKE_LIBS_PRIVATE"), - SettingsAsList, 6) << ";" << "\n"; - } - if(!project->isEmpty("DESTDIR")) { - ProString dir = project->first("DESTDIR"); - if (QDir::isRelativePath(dir.toQString())) - dir.prepend(qmake_getpwd() + Option::dir_sep); - t << "\t\t\t\t" << writeSettings("INSTALL_DIR", dir) << ";" << "\n"; - } - if (project->first("TEMPLATE") == "lib") { - t << "\t\t\t\t" << writeSettings("INSTALL_PATH", ProStringList()) << ";" << "\n"; - } - if(!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") { - t << "\t\t\t\t" << writeSettings("DYLIB_CURRENT_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")+"."+project->first("VER_PAT")) << ";" << "\n"; - if(project->isEmpty("COMPAT_VERSION")) - t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")) << ";" << "\n"; - if(project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && - project->isActiveConfig("lib_bundle")) - t << "\t\t\t\t" << writeSettings("FRAMEWORK_VERSION", project->first("QMAKE_FRAMEWORK_VERSION")) << ";" << "\n"; - } - if(!project->isEmpty("COMPAT_VERSION")) - t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("COMPAT_VERSION")) << ";" << "\n"; - if(!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET")) - t << "\t\t\t\t" << writeSettings("MACOSX_DEPLOYMENT_TARGET", project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET")) << ";" << "\n"; - if(project->first("TEMPLATE") == "app") { - t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", fixForOutput(project->first("QMAKE_ORIG_TARGET").toQString())) << ";" << "\n"; - } else { - if(!project->isActiveConfig("plugin") && project->isActiveConfig("staticlib")) { - t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "STATIC") << ";" << "\n"; - } else { - t << "\t\t\t\t" << writeSettings("LIBRARY_STYLE", "DYNAMIC") << ";" << "\n"; - } - ProString lib = project->first("QMAKE_ORIG_TARGET"); - if(!project->isActiveConfig("lib_bundle") && !project->isActiveConfig("staticlib")) - lib.prepend("lib"); - t << "\t\t\t\t" << writeSettings("PRODUCT_NAME", escapeFilePath(lib)) << ";" << "\n"; - } - tmp = project->values("QMAKE_PBX_VARS"); - for(int i = 0; i < tmp.count(); i++) { - QString var = tmp[i].toQString(), val = QString::fromLocal8Bit(qgetenv(var.toLatin1().constData())); - if(val.isEmpty() && var == "TB") - val = "/usr/bin/"; - t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";" << "\n"; - } - t << "\t\t\t" << "};" << "\n" - << "\t\t\t" << "conditionalBuildSettings = {" << "\n" - << "\t\t\t" << "};" << "\n" - << "\t\t\t" << writeSettings("dependencies", project->values("QMAKE_PBX_TARGET_DEPENDS"), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << writeSettings("productReference", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n" - << "\t\t\t" << writeSettings("shouldUseHeadermap", "1", SettingsNoQuote) << ";" << "\n"; + SettingsAsList, 4) << ";" << "\n"; + t << "\t\t\t" << writeSettings("dependencies", project->values("QMAKE_PBX_TARGET_DEPENDS"), SettingsAsList, 4) << ";" << "\n" + << "\t\t\t" << writeSettings("productReference", keyFor(pbx_dir + "QMAKE_PBX_REFERENCE")) << ";" << "\n"; t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_PBX_BUILDCONFIG_LIST_TARGET"), SettingsNoQuote) << ";" << "\n"; t << "\t\t\t" << writeSettings("isa", "PBXNativeTarget", SettingsNoQuote) << ";" << "\n"; + t << "\t\t\t" << writeSettings("buildRules", ProStringList(), SettingsAsList) << ";" << "\n"; if(project->first("TEMPLATE") == "app") { - if(!project->isActiveConfig("app_bundle")) { - if (!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE")) - t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n"; - else - t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n"; + if (!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE")) { + t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n"; } else { - if (!project->isEmpty("QMAKE_PBX_PRODUCT_TYPE")) - t << "\t\t\t" << writeSettings("productType", project->first("QMAKE_PBX_PRODUCT_TYPE")) << ";" << "\n"; - else + if (project->isActiveConfig("app_bundle")) t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.application") << ";" << "\n"; - t << "\t\t\t" << "productSettingsXML = \""; - bool read_plist = false; - if(exists("Info.plist")) { - QFile plist("Info.plist"); - if (plist.open(QIODevice::ReadOnly)) { - read_plist = true; - QTextStream stream(&plist); - while(!stream.atEnd()) - t << stream.readLine().replace('"', "\\\"") << endl; - } - } - if(!read_plist) { - t << "<?xml version=" - << "\\\"1.0\\\" encoding=" << "\\\"UTF-8\\\"" << "?>" << "\n" - << "\t\t\t\t" << "<!DOCTYPE plist SYSTEM \\\"file://localhost/System/" - << "Library/DTDs/PropertyList.dtd\\\">" << "\n" - << "\t\t\t\t" << "<plist version=\\\"0.9\\\">" << "\n" - << "\t\t\t\t" << "<dict>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleDevelopmentRegion</key>" << "\n" - << "\t\t\t\t\t" << "<string>English</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleExecutable</key>" << "\n" - << "\t\t\t\t\t" << "<string>" << project->first("QMAKE_ORIG_TARGET") << "</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleIconFile</key>" << "\n" - << "\t\t\t\t\t" << "<string>" << var("ICON").section(Option::dir_sep, -1) << "</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleInfoDictionaryVersion</key>" << "\n" - << "\t\t\t\t\t" << "<string>6.0</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundlePackageType</key>" << "\n" - << "\t\t\t\t\t" << "<string>APPL</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleSignature</key>" << "\n" - << "\t\t\t\t\t" << "<string>" - << (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") ? QString::fromLatin1("????") : - project->first("QMAKE_PKGINFO_TYPEINFO").left(4)) << "</string>" << "\n" - << "\t\t\t\t\t" << "<key>CFBundleVersion</key>" << "\n" - << "\t\t\t\t\t" << "<string>0.1</string>" << "\n" - << "\t\t\t\t\t" << "<key>CSResourcesFileMapped</key>" << "\n" - << "\t\t\t\t\t" << "<true/>" << "\n" - << "\t\t\t\t" << "</dict>" << "\n" - << "\t\t\t\t" << "</plist>"; - } - t << "\";" << "\n"; + else + t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.tool") << ";" << "\n"; } t << "\t\t\t" << writeSettings("name", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n" << "\t\t\t" << writeSettings("productName", escapeFilePath(project->first("QMAKE_ORIG_TARGET"))) << ";" << "\n"; @@ -1343,12 +1231,11 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) else t << "\t\t\t" << writeSettings("productType", "com.apple.product-type.library.dynamic") << ";" << "\n"; } - t << "\t\t\t" << writeSettings("startupPath", "<<ProjectDirectory>>") << ";" << "\n"; if(!project->isEmpty("DESTDIR")) t << "\t\t\t" << writeSettings("productInstallPath", escapeFilePath(project->first("DESTDIR"))) << ";" << "\n"; t << "\t\t" << "};" << "\n"; //DEBUG/RELEASE - QString active_buildstyle; + QString defaultConfig; for(int as_release = 0; as_release < 2; as_release++) { QMap<QString, QString> settings; @@ -1379,6 +1266,8 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) } QString name = (as_release ? "Release" : "Debug"); + if (project->isActiveConfig("debug") != (bool)as_release) + defaultConfig = name; for (int i = 0; i < buildConfigGroups.size(); i++) { QString key = keyFor("QMAKE_PBX_BUILDCONFIG_" + name + buildConfigGroups.at(i)); project->values(ProKey("QMAKE_PBX_BUILDCONFIGS_" + buildConfigGroups.at(i))).append(key); @@ -1387,15 +1276,104 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << "buildSettings = {" << "\n"; for (QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it) t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";\n"; - if (!project->isEmpty("PRECOMPILED_HEADER")) { - t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n" - << "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n"; - } if (buildConfigGroups.at(i) == QLatin1String("PROJECT")) { + if (!project->isEmpty("QMAKE_XCODE_GCC_VERSION")) + t << "\t\t\t\t" << writeSettings("GCC_VERSION", project->first("QMAKE_XCODE_GCC_VERSION"), SettingsNoQuote) << ";" << "\n"; + ProString program = project->first("QMAKE_CC"); + if (!program.isEmpty()) + t << "\t\t\t\t" << writeSettings("CC", fixForOutput(findProgram(program))) << ";" << "\n"; + program = project->first("QMAKE_CXX"); + // Xcode will automatically take care of using CC with the right -x option, + // and will actually break if we pass CPLUSPLUS, by adding an additional set of "++" + if (!program.isEmpty() && !program.contains("clang++")) + t << "\t\t\t\t" << writeSettings("CPLUSPLUS", fixForOutput(findProgram(program))) << ";" << "\n"; + program = project->first("QMAKE_LINK"); + if (!program.isEmpty()) + t << "\t\t\t\t" << writeSettings("LDPLUSPLUS", fixForOutput(findProgram(program))) << ";" << "\n"; + + if ((project->first("TEMPLATE") == "app" && project->isActiveConfig("app_bundle")) || + (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && + project->isActiveConfig("lib_bundle"))) { + QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString()); + if (plist.isEmpty()) + plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE"); + if (exists(plist)) { + QFile plist_in_file(plist); + if (plist_in_file.open(QIODevice::ReadOnly)) { + QTextStream plist_in(&plist_in_file); + QString plist_in_text = plist_in.readAll(); + plist_in_text = plist_in_text.replace("@ICON@", + (project->isEmpty("ICON") ? QString("") : project->first("ICON").toQString().section(Option::dir_sep, -1))); + if (project->first("TEMPLATE") == "app") { + plist_in_text = plist_in_text.replace("@EXECUTABLE@", project->first("QMAKE_ORIG_TARGET").toQString()); + } else { + plist_in_text = plist_in_text.replace("@LIBRARY@", project->first("QMAKE_ORIG_TARGET").toQString()); + } + plist_in_text = plist_in_text.replace("@BUNDLEIDENTIFIER@", QLatin1String("${PRODUCT_NAME:rfc1034identifier}")); + if (!project->values("VERSION").isEmpty()) { + plist_in_text = plist_in_text.replace("@SHORT_VERSION@", project->first("VER_MAJ") + "." + + project->first("VER_MIN")); + } + plist_in_text = plist_in_text.replace("@TYPEINFO@", + (project->isEmpty("QMAKE_PKGINFO_TYPEINFO") + ? QString::fromLatin1("????") : project->first("QMAKE_PKGINFO_TYPEINFO").left(4).toQString())); + QFile plist_out_file("Info.plist"); + if (plist_out_file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream plist_out(&plist_out_file); + plist_out << plist_in_text; + t << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n"; + } + } + } + } + + t << "\t\t\t\t" << writeSettings("SYMROOT", escapeFilePath(qmake_getpwd())) << ";" << "\n"; + + if (!project->isEmpty("DESTDIR")) { + ProString dir = project->first("DESTDIR"); + if (QDir::isRelativePath(dir.toQString())) + dir.prepend(qmake_getpwd() + Option::dir_sep); + t << "\t\t\t\t" << writeSettings("TARGET_BUILD_DIR", dir) << ";" << "\n"; + } + + if (project->first("TEMPLATE") == "lib") + t << "\t\t\t\t" << writeSettings("INSTALL_PATH", ProStringList()) << ";" << "\n"; + + if (!project->isEmpty("VERSION") && project->first("VERSION") != "0.0.0") { + t << "\t\t\t\t" << writeSettings("DYLIB_CURRENT_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")+"."+project->first("VER_PAT")) << ";" << "\n"; + if (project->isEmpty("COMPAT_VERSION")) + t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("VER_MAJ")+"."+project->first("VER_MIN")) << ";" << "\n"; + if (project->first("TEMPLATE") == "lib" && !project->isActiveConfig("staticlib") && + project->isActiveConfig("lib_bundle")) + t << "\t\t\t\t" << writeSettings("FRAMEWORK_VERSION", project->first("QMAKE_FRAMEWORK_VERSION")) << ";" << "\n"; + } + if (!project->isEmpty("COMPAT_VERSION")) + t << "\t\t\t\t" << writeSettings("DYLIB_COMPATIBILITY_VERSION", project->first("COMPAT_VERSION")) << ";" << "\n"; + + if (!project->isEmpty("QMAKE_MACOSX_DEPLOYMENT_TARGET")) + t << "\t\t\t\t" << writeSettings("MACOSX_DEPLOYMENT_TARGET", project->first("QMAKE_MACOSX_DEPLOYMENT_TARGET")) << ";" << "\n"; + if (!project->isEmpty("QMAKE_IOS_DEPLOYMENT_TARGET")) + t << "\t\t\t\t" << writeSettings("IPHONEOS_DEPLOYMENT_TARGET", project->first("QMAKE_IOS_DEPLOYMENT_TARGET")) << ";" << "\n"; + + if (!project->isEmpty("QMAKE_XCODE_CODE_SIGN_IDENTITY")) + t << "\t\t\t\t" << writeSettings("CODE_SIGN_IDENTITY", project->first("QMAKE_XCODE_CODE_SIGN_IDENTITY")) << ";" << "\n"; + + tmp = project->values("QMAKE_PBX_VARS"); + for (int i = 0; i < tmp.count(); i++) { + QString var = tmp[i].toQString(), val = QString::fromLocal8Bit(qgetenv(var.toLatin1().constData())); + if (val.isEmpty() && var == "TB") + val = "/usr/bin/"; + t << "\t\t\t\t" << writeSettings(var, escapeFilePath(val)) << ";" << "\n"; + } + if (!project->isEmpty("PRECOMPILED_HEADER")) { + t << "\t\t\t\t" << writeSettings("GCC_PRECOMPILE_PREFIX_HEADER", "YES") << ";" << "\n" + << "\t\t\t\t" << writeSettings("GCC_PREFIX_HEADER", escapeFilePath(project->first("PRECOMPILED_HEADER"))) << ";" << "\n"; + } t << "\t\t\t\t" << writeSettings("HEADER_SEARCH_PATHS", fixListForOutput("INCLUDEPATH") + ProStringList(fixForOutput(specdir())), SettingsAsList, 5) << ";" << "\n" << "\t\t\t\t" << writeSettings("LIBRARY_SEARCH_PATHS", fixListForOutput("QMAKE_PBX_LIBPATHS"), SettingsAsList, 5) << ";" << "\n" - << "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"), SettingsAsList, 5) << ";" << "\n" - << "\t\t\t\t" << writeSettings("INFOPLIST_FILE", "Info.plist") << ";" << "\n"; + << "\t\t\t\t" << writeSettings("FRAMEWORK_SEARCH_PATHS", fixListForOutput("QMAKE_FRAMEWORKPATH"), + !project->values("QMAKE_FRAMEWORKPATH").isEmpty() ? SettingsAsList : 0, 5) << ";" << "\n"; + { ProStringList cflags = fixListForOutput("QMAKE_CFLAGS"); const ProStringList &prl_defines = project->values("PRL_EXPORT_DEFINES"); @@ -1446,20 +1424,6 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) t << "\t\t\t" << "};" << "\n" << "\t\t\t" << writeSettings("name", name) << ";" << "\n" << "\t\t" << "};" << "\n"; - - key = keyFor("QMAKE_PBX_BUILDSTYLE_" + name); - project->values("QMAKE_PBX_BUILDSTYLES").append(key); - if (project->isActiveConfig("debug") != (bool)as_release) - active_buildstyle = name; - t << "\t\t" << key << " = {" << "\n" - << "\t\t\t" << writeSettings("buildRules", ProStringList(), SettingsAsList, 4) << ";" << "\n" - << "\t\t\t" << "buildSettings = {" << "\n"; - for(QMap<QString, QString>::Iterator set_it = settings.begin(); set_it != settings.end(); ++set_it) - t << "\t\t\t\t" << writeSettings(set_it.key(), set_it.value()) << ";" << "\n"; - t << "\t\t\t" << "};" << "\n" - << "\t\t\t" << writeSettings("isa", "PBXBuildStyle") << ";" << "\n" - << "\t\t\t" << writeSettings("name", name) << ";" << "\n" - << "\t\t" << "};" << "\n"; } } for (int i = 0; i < buildConfigGroups.size(); i++) { @@ -1467,20 +1431,24 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) << "\t\t\t" << writeSettings("isa", "XCConfigurationList", SettingsNoQuote) << ";" << "\n" << "\t\t\t" << writeSettings("buildConfigurations", project->values(ProKey("QMAKE_PBX_BUILDCONFIGS_" + buildConfigGroups.at(i))), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("defaultConfigurationIsVisible", "0", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("defaultConfigurationIsName", active_buildstyle) << ";" << "\n" + << "\t\t\t" << writeSettings("defaultConfigurationName", defaultConfig) << ";" << "\n" << "\t\t" << "};" << "\n"; } //ROOT t << "\t\t" << keyFor("QMAKE_PBX_ROOT") << " = {" << "\n" - << "\t\t\t" << writeSettings("buildStyles", project->values("QMAKE_PBX_BUILDSTYLES"), SettingsAsList, 4) << ";" << "\n" << "\t\t\t" << writeSettings("hasScannedForEncodings", "1", SettingsNoQuote) << ";" << "\n" + << "\t\t\t" << writeSettings("compatibilityVersion", "Xcode 3.2") << ";" << "\n" << "\t\t\t" << writeSettings("isa", "PBXProject", SettingsNoQuote) << ";" << "\n" - << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_PBX_ROOT_GROUP")) << ";" << "\n"; + << "\t\t\t" << writeSettings("mainGroup", keyFor("QMAKE_PBX_ROOT_GROUP")) << ";" << "\n" + << "\t\t\t" << writeSettings("productRefGroup", keyFor("Products")) << ";" << "\n"; t << "\t\t\t" << writeSettings("buildConfigurationList", keyFor("QMAKE_PBX_BUILDCONFIG_LIST_PROJECT")) << ";" << "\n"; t << "\t\t\t" << writeSettings("projectDirPath", ProStringList()) << ";" << "\n" + << "\t\t\t" << writeSettings("projectRoot", "") << ";" << "\n" << "\t\t\t" << writeSettings("targets", project->values("QMAKE_PBX_TARGETS"), SettingsAsList, 4) << ";" << "\n" << "\t\t" << "};" << "\n"; + // FIXME: Deal with developmentRegion and knownRegions for QMAKE_PBX_ROOT + //FOOTER t << "\t" << "};" << "\n" << "\t" << writeSettings("rootObject", keyFor("QMAKE_PBX_ROOT")) << ";" << "\n" @@ -1511,6 +1479,9 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t) writingUnixMakefileGenerator = false; } } + + qmake_setpwd(input_dir); + return true; } @@ -1724,10 +1695,9 @@ ProjectBuilderMakefileGenerator::reftypeForFile(const QString &where) QString ProjectBuilderMakefileGenerator::sourceTreeForFile(const QString &where) { - QString ret = "<absolute>"; - if (QDir::isRelativePath(unescapeFilePath(where))) - ret = "SOURCE_ROOT"; //relative - return ret; + // We always use absolute paths, instead of maintaining the SRCROOT + // build variable and making files relative to that. + return QLatin1String("<absolute>"); } QString diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index 41e40e0bb6..8ad603580c 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -1218,7 +1218,7 @@ void UnixMakefileGenerator::init2() } if(!project->isEmpty("QMAKE_BUNDLE")) { - QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString()); + QString plist = fileFixify(project->first("QMAKE_INFO_PLIST").toQString(), qmake_getpwd()); if(plist.isEmpty()) plist = specdir() + QDir::separator() + "Info.plist." + project->first("TEMPLATE"); if(exists(Option::fixPathToLocalOS(plist))) { diff --git a/qmake/main.cpp b/qmake/main.cpp index 5f9fb05449..6ef0707da9 100644 --- a/qmake/main.cpp +++ b/qmake/main.cpp @@ -116,6 +116,11 @@ int runQMake(int argc, char **argv) if(!tmp_dir.isEmpty() && QFile::exists(tmp_dir)) dir = tmp_dir; } +#ifdef Q_OS_MAC + if (fi.fileName().endsWith(QStringLiteral(".pbxproj")) + && dir.endsWith(QStringLiteral(".xcodeproj"))) + dir += QStringLiteral("/.."); +#endif if(!dir.isNull() && dir != ".") Option::output_dir = dir; if(QDir::isRelativePath(Option::output_dir)) diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index eb7aa2e64f..6062dc7b7b 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -50,6 +50,8 @@ The operating system, must be one of: (Q_OS_x) DARWIN - Darwin OS (synonym for Q_OS_MAC) + MAC - Mac OS X or iOS (iPhoneOS) + IOS - iOS (treated as a variant of Mac OS) MSDOS - MS-DOS and Windows OS2 - OS/2 OS2EMX - XFree86 on OS/2 (not PM) @@ -166,6 +168,10 @@ # elif defined(Q_OS_DARWIN32) # define Q_OS_MAC32 # endif +# include <TargetConditionals.h> +# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE +# define Q_OS_IOS +# endif #endif #if defined(Q_OS_WIN) @@ -202,6 +208,22 @@ # define MAC_OS_X_VERSION_10_8 1080 # endif # +# if !defined(__IPHONE_4_3) +# define __IPHONE_4_3 40300 +# endif +# if !defined(__IPHONE_5_0) +# define __IPHONE_5_0 50000 +# endif +# if !defined(__IPHONE_5_1) +# define __IPHONE_5_1 50100 +# endif +# if !defined(__IPHONE_6_0) +# define __IPHONE_6_0 60000 +# endif +# if !defined(__IPHONE_6_1) +# define __IPHONE_6_1 60100 +# endif +# # if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_8) # warning "This version of Mac OS X is unsupported" # endif diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index b833eb4962..361a6c2c67 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -63,6 +63,8 @@ #include <CoreFoundation/CoreFoundation.h> #endif +#include "qglobal.h" + #ifndef Q_OS_IOS #include <CoreServices/CoreServices.h> #endif diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 058cfe92ec..f21c7a5ce7 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -18,9 +18,7 @@ testcocoon { load(testcocoon) } -mac { - LIBS_PRIVATE += -framework Cocoa -} +mac:!ios: LIBS_PRIVATE += -framework Cocoa CONFIG += simd diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp index 0b3d9dc46d..d55d6a91bf 100644 --- a/src/gui/opengl/qopenglpaintdevice.cpp +++ b/src/gui/opengl/qopenglpaintdevice.cpp @@ -116,6 +116,7 @@ public: qreal dpmx; qreal dpmy; + qreal devicePixelRatio; bool flipped; @@ -178,6 +179,7 @@ QOpenGLPaintDevicePrivate::QOpenGLPaintDevicePrivate(const QSize &sz) , ctx(QOpenGLContext::currentContext()) , dpmx(qt_defaultDpiX() * 100. / 2.54) , dpmy(qt_defaultDpiY() * 100. / 2.54) + , devicePixelRatio(1.0) , flipped(false) , engine(0) { @@ -249,6 +251,14 @@ void QOpenGLPaintDevice::setSize(const QSize &size) } /*! + Sets the device pixel ratio for the paint device to \a devicePixelRatio. +*/ +void QOpenGLPaintDevice::setDevicePixelRatio(qreal devicePixelRatio) +{ + d_ptr->devicePixelRatio = devicePixelRatio; +} + +/*! \reimp */ @@ -272,9 +282,9 @@ int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const case PdmDpiY: return qRound(d_ptr->dpmy * 0.0254); case PdmPhysicalDpiX: - return qRound(d_ptr->dpmx * 0.0254); + return qRound(d_ptr->dpmx * 0.0254 * d_ptr->devicePixelRatio); case PdmPhysicalDpiY: - return qRound(d_ptr->dpmy * 0.0254); + return qRound(d_ptr->dpmy * 0.0254 * d_ptr->devicePixelRatio); default: qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric); return 0; diff --git a/src/gui/opengl/qopenglpaintdevice.h b/src/gui/opengl/qopenglpaintdevice.h index 731000f131..5868a5740a 100644 --- a/src/gui/opengl/qopenglpaintdevice.h +++ b/src/gui/opengl/qopenglpaintdevice.h @@ -68,6 +68,7 @@ public: QOpenGLContext *context() const; QSize size() const; void setSize(const QSize &size); + void setDevicePixelRatio(qreal devicePixelRatio); qreal dotsPerMeterX() const; qreal dotsPerMeterY() const; diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 57df8c8bc8..580e0b31b3 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -39,7 +39,11 @@ win32: { } integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp -mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation -framework CoreServices +mac { + LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation + !ios: LIBS_PRIVATE += -framework CoreServices +} + mac:!ios:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp else:blackberry:SOURCES += kernel/qnetworkproxy_blackberry.cpp diff --git a/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri b/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri new file mode 100644 index 0000000000..9a19d3c278 --- /dev/null +++ b/src/platformsupport/cfsocketnotifier/cfsocketnotifier.pri @@ -0,0 +1,4 @@ +mac { + HEADERS += $$PWD/qcfsocketnotifier_p.h + SOURCES += $$PWD/qcfsocketnotifier.cpp +} diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp new file mode 100644 index 0000000000..5dcd6a4ffd --- /dev/null +++ b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier.cpp @@ -0,0 +1,255 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 "qcfsocketnotifier_p.h" +#include <QtGui/qguiapplication.h> +#include <QtCore/qsocketnotifier.h> +#include <QtCore/qthread.h> + + +/************************************************************************** + Socket Notifiers + *************************************************************************/ +void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, + const void *, void *info) +{ + + QCFSocketNotifier *cfSocketNotifier = static_cast<QCFSocketNotifier *>(info); + int nativeSocket = CFSocketGetNative(s); + MacSocketInfo *socketInfo = cfSocketNotifier->macSockets.value(nativeSocket); + QEvent notifierEvent(QEvent::SockAct); + + // There is a race condition that happen where we disable the notifier and + // the kernel still has a notification to pass on. We then get this + // notification after we've successfully disabled the CFSocket, but our Qt + // notifier is now gone. The upshot is we have to check the notifier + // every time. + if (callbackType == kCFSocketReadCallBack) { + if (socketInfo->readNotifier) + QGuiApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); + } else if (callbackType == kCFSocketWriteCallBack) { + if (socketInfo->writeNotifier) + QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); + } + + if (cfSocketNotifier->maybeCancelWaitForMoreEvents) + cfSocketNotifier->maybeCancelWaitForMoreEvents(cfSocketNotifier->eventDispatcher); +} + +/* + Adds a loop source for the given socket to the current run loop. +*/ +CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket) +{ + CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0); + if (!loopSource) + return 0; + + CFRunLoopAddSource(CFRunLoopGetMain(), loopSource, kCFRunLoopCommonModes); + return loopSource; +} + +/* + Removes the loop source for the given socket from the current run loop. +*/ +void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop) +{ + Q_ASSERT(runloop); + CFRunLoopRemoveSource(CFRunLoopGetMain(), runloop, kCFRunLoopCommonModes); + CFSocketDisableCallBacks(socket, kCFSocketReadCallBack); + CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack); + CFRunLoopSourceInvalidate(runloop); +} + +QCFSocketNotifier::QCFSocketNotifier() +:eventDispatcher(0) +{ + +} + +QCFSocketNotifier::~QCFSocketNotifier() +{ + +} + +void QCFSocketNotifier::setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher) +{ + eventDispatcher = hostEventDispacher; +} + +void QCFSocketNotifier::setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack) +{ + maybeCancelWaitForMoreEvents = callBack; +} + +void QCFSocketNotifier::registerSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != eventDispatcher->thread() + || eventDispatcher->thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); + return; + } +#endif + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on iOS"); + return; + } + + // Check if we have a CFSocket for the native socket, create one if not. + MacSocketInfo *socketInfo = macSockets.value(nativeSocket); + if (!socketInfo) { + socketInfo = new MacSocketInfo(); + + // Create CFSocket, specify that we want both read and write callbacks (the callbacks + // are enabled/disabled later on). + const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; + CFSocketContext context = {0, this, 0, 0, 0}; + socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); + if (CFSocketIsValid(socketInfo->socket) == false) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); + return; + } + + CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); + flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write + flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation + CFSocketSetSocketFlags(socketInfo->socket, flags); + + // Add CFSocket to runloop. + if (!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { + qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + return; + } + + // Disable both callback types by default. This must be done after + // we add the CFSocket to the runloop, or else these calls will have + // no effect. + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + + macSockets.insert(nativeSocket, socketInfo); + } + + // Increment read/write counters and select enable callbacks if necessary. + if (type == QSocketNotifier::Read) { + Q_ASSERT(socketInfo->readNotifier == 0); + socketInfo->readNotifier = notifier; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(socketInfo->writeNotifier == 0); + socketInfo->writeNotifier = notifier; + CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } +} + +void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) +{ + Q_ASSERT(notifier); + int nativeSocket = notifier->socket(); + int type = notifier->type(); +#ifndef QT_NO_DEBUG + if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { + qWarning("QSocketNotifier: Internal error"); + return; + } else if (notifier->thread() != eventDispatcher->thread() || eventDispatcher->thread() != QThread::currentThread()) { + qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); + return; + } +#endif + + if (type == QSocketNotifier::Exception) { + qWarning("QSocketNotifier::Exception is not supported on iOS"); + return; + } + MacSocketInfo *socketInfo = macSockets.value(nativeSocket); + if (!socketInfo) { + qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); + return; + } + + // Decrement read/write counters and disable callbacks if necessary. + if (type == QSocketNotifier::Read) { + Q_ASSERT(notifier == socketInfo->readNotifier); + socketInfo->readNotifier = 0; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); + } else if (type == QSocketNotifier::Write) { + Q_ASSERT(notifier == socketInfo->writeNotifier); + socketInfo->writeNotifier = 0; + CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); + } + + // Remove CFSocket from runloop if this was the last QSocketNotifier. + if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) { + if (CFSocketIsValid(socketInfo->socket)) + qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); + CFRunLoopSourceInvalidate(socketInfo->runloop); + CFRelease(socketInfo->runloop); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + delete socketInfo; + macSockets.remove(nativeSocket); + } +} + +void QCFSocketNotifier::removeSocketNotifiers() +{ + // Remove CFSockets from the runloop. + for (MacSocketHash::ConstIterator it = macSockets.constBegin(); it != macSockets.constEnd(); ++it) { + MacSocketInfo *socketInfo = (*it); + if (CFSocketIsValid(socketInfo->socket)) { + qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); + CFRunLoopSourceInvalidate(socketInfo->runloop); + CFRelease(socketInfo->runloop); + CFSocketInvalidate(socketInfo->socket); + CFRelease(socketInfo->socket); + } + } +} diff --git a/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h new file mode 100644 index 0000000000..cd1eb8e4ca --- /dev/null +++ b/src/platformsupport/cfsocketnotifier/qcfsocketnotifier_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module 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 QCFSOCKETNOTIFIER_P_H +#define QCFSOCKETNOTIFIER_P_H + +#include <QtCore/qabstracteventdispatcher.h> +#include <QtCore/qhash.h> + +#include <CoreFoundation/CoreFoundation.h> + +QT_BEGIN_NAMESPACE + +struct MacSocketInfo { + MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {} + CFSocketRef socket; + CFRunLoopSourceRef runloop; + QObject *readNotifier; + QObject *writeNotifier; +}; +typedef QHash<int, MacSocketInfo *> MacSocketHash; + +typedef void (*MaybeCancelWaitForMoreEventsFn)(QAbstractEventDispatcher *hostEventDispacher); + +// The CoreFoundationSocketNotifier class implements socket notifiers support using +// CFSocket for event dispatchers running on top of the Core Foundation run loop system. +// (currently Mac and iOS) +// +// The principal functions are registerSocketNotifier() and unregisterSocketNotifier(). +// +// setHostEventDispatcher() should be called at startup. +// removeSocketNotifiers() should be called at shutdown. +// +class QCFSocketNotifier +{ +public: + QCFSocketNotifier(); + ~QCFSocketNotifier(); + void setHostEventDispatcher(QAbstractEventDispatcher *hostEventDispacher); + void setMaybeCancelWaitForMoreEventsCallback(MaybeCancelWaitForMoreEventsFn callBack); + void registerSocketNotifier(QSocketNotifier *notifier); + void unregisterSocketNotifier(QSocketNotifier *notifier); + void removeSocketNotifiers(); + + MacSocketHash macSockets; + QAbstractEventDispatcher *eventDispatcher; + MaybeCancelWaitForMoreEventsFn maybeCancelWaitForMoreEvents; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri index f7977964fe..d1abf123aa 100644 --- a/src/platformsupport/fontdatabases/mac/coretext.pri +++ b/src/platformsupport/fontdatabases/mac/coretext.pri @@ -1,2 +1,10 @@ HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm + +ios: \ + # On iOS CoreText and CoreGraphics are stand-alone frameworks + LIBS += -framework CoreText -framework CoreGraphics +else: \ + # On Mac OS they are part of the ApplicationServices umbrella framework, + # even in 10.8 where they were also made available stand-alone. + LIBS += -framework ApplicationServices diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index ef5bdbbf0d..fbd836f763 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "qglobal.h" + #ifndef Q_OS_IOS #import <Cocoa/Cocoa.h> #import <IOKit/graphics/IOGraphicsLib.h> diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 57d9b422f4..8e0f396993 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -2,13 +2,14 @@ TARGET = QtPlatformSupport QT = core-private gui-private CONFIG += static internal_module -mac:LIBS += -lz -framework CoreFoundation -framework Carbon +mac:LIBS += -lz load(qt_module) DEFINES += QT_NO_CAST_FROM_ASCII PRECOMPILED_HEADER = ../corelib/global/qt_pch.h +include(cfsocketnotifier/cfsocketnotifier.pri) include(cglconvenience/cglconvenience.pri) include(dnd/dnd.pri) include(eglconvenience/eglconvenience.pri) diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 83e2a88e6a..6ed26f9e6c 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -78,7 +78,7 @@ HEADERS += qcocoaintegration.h \ RESOURCES += qcocoaresources.qrc -LIBS += -framework Cocoa -framework IOKit +LIBS += -framework Cocoa -framework Carbon -framework IOKit QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index f63ac0d205..93476ee1b4 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -93,6 +93,7 @@ #include <QtGui/qwindowdefs.h> #include <QtCore/private/qabstracteventdispatcher_p.h> #include <QtCore/private/qtimerinfo_unix_p.h> +#include <QtPlatformSupport/private/qcfsocketnotifier_p.h> #include <CoreFoundation/CoreFoundation.h> @@ -132,16 +133,9 @@ public: void wakeUp(); void interrupt(); void flush(); -}; -struct MacSocketInfo { - MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {} - CFSocketRef socket; - CFRunLoopSourceRef runloop; - QObject *readNotifier; - QObject *writeNotifier; + friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher); }; -typedef QHash<int, MacSocketInfo *> MacSocketHash; class QCocoaEventDispatcherPrivate : public QAbstractEventDispatcherPrivate { @@ -183,7 +177,7 @@ public: void maybeCancelWaitForMoreEvents(); void ensureNSAppInitialized(); - MacSocketHash macSockets; + QCFSocketNotifier cfSocketNotifier; QList<void *> queuedUserInputEvents; // NSEvent * CFRunLoopSourceRef postedEventsSource; CFRunLoopObserverRef waitingObserver; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 987600c6b4..ed4f8cd1fb 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -270,58 +270,6 @@ QCocoaEventDispatcher::registeredTimers(QObject *object) const return d->timerInfoList.registeredTimers(object); } -/************************************************************************** - Socket Notifiers - *************************************************************************/ -void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef, - const void *, void *info) { - QCocoaEventDispatcherPrivate *const eventDispatcher - = static_cast<QCocoaEventDispatcherPrivate *>(info); - int nativeSocket = CFSocketGetNative(s); - MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket); - QEvent notifierEvent(QEvent::SockAct); - - // There is a race condition that happen where we disable the notifier and - // the kernel still has a notification to pass on. We then get this - // notification after we've successfully disabled the CFSocket, but our Qt - // notifier is now gone. The upshot is we have to check the notifier - // everytime. - if (callbackType == kCFSocketReadCallBack) { - if (socketInfo->readNotifier) - QGuiApplication::sendEvent(socketInfo->readNotifier, ¬ifierEvent); - } else if (callbackType == kCFSocketWriteCallBack) { - if (socketInfo->writeNotifier) - QGuiApplication::sendEvent(socketInfo->writeNotifier, ¬ifierEvent); - } - - eventDispatcher->maybeCancelWaitForMoreEvents(); -} - -/* - Adds a loop source for the given socket to the current run loop. -*/ -CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket) -{ - CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0); - if (!loopSource) - return 0; - - CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes); - return loopSource; -} - -/* - Removes the loop source for the given socket from the current run loop. -*/ -void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop) -{ - Q_ASSERT(runloop); - CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes); - CFSocketDisableCallBacks(socket, kCFSocketReadCallBack); - CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack); - CFRunLoopSourceInvalidate(runloop); -} - /* Register a QSocketNotifier with the mac event system by creating a CFSocket with with a read/write callback. @@ -331,130 +279,14 @@ void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSource */ void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier) { - Q_ASSERT(notifier); - int nativeSocket = notifier->socket(); - int type = notifier->type(); -#ifndef QT_NO_DEBUG - if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != thread() - || thread() != QThread::currentThread()) { - qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread"); - return; - } -#endif - Q_D(QCocoaEventDispatcher); - - if (type == QSocketNotifier::Exception) { - qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); - return; - } - - // Check if we have a CFSocket for the native socket, create one if not. - MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); - if (!socketInfo) { - socketInfo = new MacSocketInfo(); - - // Create CFSocket, specify that we want both read and write callbacks (the callbacks - // are enabled/disabled later on). - const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack; - CFSocketContext context = {0, d, 0, 0, 0}; - socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context); - if (CFSocketIsValid(socketInfo->socket) == false) { - qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket"); - return; - } - - CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket); - flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write - flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation - CFSocketSetSocketFlags(socketInfo->socket, flags); - - // Add CFSocket to runloop. - if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) { - qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop"); - CFSocketInvalidate(socketInfo->socket); - CFRelease(socketInfo->socket); - return; - } - - // Disable both callback types by default. This must be done after - // we add the CFSocket to the runloop, or else these calls will have - // no effect. - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - - d->macSockets.insert(nativeSocket, socketInfo); - } - - // Increment read/write counters and select enable callbacks if necessary. - if (type == QSocketNotifier::Read) { - Q_ASSERT(socketInfo->readNotifier == 0); - socketInfo->readNotifier = notifier; - CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - } else if (type == QSocketNotifier::Write) { - Q_ASSERT(socketInfo->writeNotifier == 0); - socketInfo->writeNotifier = notifier; - CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - } + d->cfSocketNotifier.registerSocketNotifier(notifier); } -/* - Unregister QSocketNotifer. The CFSocket correspoding to this notifier is - removed from the runloop of this is the last notifier that users - that CFSocket. -*/ void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier) { - Q_ASSERT(notifier); - int nativeSocket = notifier->socket(); - int type = notifier->type(); -#ifndef QT_NO_DEBUG - if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) { - qWarning("QSocketNotifier: Internal error"); - return; - } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) { - qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread"); - return; - } -#endif - Q_D(QCocoaEventDispatcher); - - if (type == QSocketNotifier::Exception) { - qWarning("QSocketNotifier::Exception is not supported on Mac OS X"); - return; - } - MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket); - if (!socketInfo) { - qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier"); - return; - } - - // Decrement read/write counters and disable callbacks if necessary. - if (type == QSocketNotifier::Read) { - Q_ASSERT(notifier == socketInfo->readNotifier); - socketInfo->readNotifier = 0; - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack); - } else if (type == QSocketNotifier::Write) { - Q_ASSERT(notifier == socketInfo->writeNotifier); - socketInfo->writeNotifier = 0; - CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack); - } - - // Remove CFSocket from runloop if this was the last QSocketNotifier. - if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) { - if (CFSocketIsValid(socketInfo->socket)) - qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); - CFRunLoopSourceInvalidate(socketInfo->runloop); - CFRelease(socketInfo->runloop); - CFSocketInvalidate(socketInfo->socket); - CFRelease(socketInfo->socket); - delete socketInfo; - d->macSockets.remove(nativeSocket); - } + d->cfSocketNotifier.unregisterSocketNotifier(notifier); } bool QCocoaEventDispatcher::hasPendingEvents() @@ -940,11 +772,19 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() { } +void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher) +{ + static_cast<QCocoaEventDispatcher *>(eventDispatcher)->d_func()->maybeCancelWaitForMoreEvents(); +} + QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent) : QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent) { Q_D(QCocoaEventDispatcher); + d->cfSocketNotifier.setHostEventDispatcher(this); + d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder); + // keep our sources running when modal loops are running CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode); @@ -1127,17 +967,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher() [nsevent release]; } - // Remove CFSockets from the runloop. - for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) { - MacSocketInfo *socketInfo = (*it); - if (CFSocketIsValid(socketInfo->socket)) { - qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop); - CFRunLoopSourceInvalidate(socketInfo->runloop); - CFRelease(socketInfo->runloop); - CFSocketInvalidate(socketInfo->socket); - CFRelease(socketInfo->socket); - } - } + d->cfSocketNotifier.removeSocketNotifiers(); + CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes); CFRelease(d->postedEventsSource); diff --git a/src/plugins/platforms/ios/ios.json b/src/plugins/platforms/ios/ios.json new file mode 100644 index 0000000000..f0b766dae1 --- /dev/null +++ b/src/plugins/platforms/ios/ios.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "ios" ] +} diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro new file mode 100644 index 0000000000..842ff17f1c --- /dev/null +++ b/src/plugins/platforms/ios/ios.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += plugin.pro qtmain.pro diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm new file mode 100644 index 0000000000..a93b6037ad --- /dev/null +++ b/src/plugins/platforms/ios/plugin.mm @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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 <qpa/qplatformintegrationplugin.h> +#include <qpa/qplatformthemeplugin.h> +#include "qiosintegration.h" + +QT_BEGIN_NAMESPACE + +class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "ios.json") + public: + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + Q_UNUSED(paramList); + if (system.toLower() == "ios") + return new QIOSIntegration; + + return 0; +} + +QT_END_NAMESPACE + +#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..591a0a67ed --- /dev/null +++ b/src/plugins/platforms/ios/plugin.pro @@ -0,0 +1,36 @@ +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/mkspecs/unsupported/macx-iosdevice-g++-legacy/qplatformdefs.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h index 5f80a17860..442b37f1b3 100644 --- a/mkspecs/unsupported/macx-iosdevice-g++-legacy/qplatformdefs.h +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the qmake spec of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,4 +39,15 @@ ** ****************************************************************************/ -#include "../../common/ios/qplatformdefs.h" +#import <UIKit/UIKit.h> +#import <QtGui/QtGui> + +@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate> + +@property (strong, nonatomic) UIWindow *window; + +@end + +@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate +@end + diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm new file mode 100644 index 0000000000..41a3fff84f --- /dev/null +++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 "qiosapplicationdelegate.h" +#include "qioswindow.h" +#include <QtCore/QtCore> + +@implementation QIOSApplicationDelegate + +@synthesize window; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + Q_UNUSED(application) + Q_UNUSED(launchOptions) + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + Q_UNUSED(application) +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + Q_UNUSED(application) +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + Q_UNUSED(application) + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + Q_UNUSED(application) + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + Q_UNUSED(application) + // 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/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h new file mode 100644 index 0000000000..c110f0e4d1 --- /dev/null +++ b/src/plugins/platforms/ios/qiosbackingstore.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 QIOSBACKINGSTORE_H +#define QIOSBACKINGSTORE_H + +#include <qpa/qplatformbackingstore.h> + +QT_BEGIN_NAMESPACE + +class QIOSBackingStore : public QPlatformBackingStore +{ +public: + QIOSBackingStore(QWindow *window); + ~QIOSBackingStore(); + + 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); + +private: + QOpenGLContext *m_context; + QPaintDevice *m_device; +}; + +QT_END_NAMESPACE + +#endif // QIOSBACKINGSTORE_H diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm new file mode 100644 index 0000000000..566ff3a672 --- /dev/null +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 "qiosbackingstore.h" +#include "qioswindow.h" + +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLPaintDevice> + +#include <QtDebug> + +QIOSBackingStore::QIOSBackingStore(QWindow *window) + : QPlatformBackingStore(window) + , m_context(new QOpenGLContext) + , m_device(0) +{ + m_context->setFormat(window->requestedFormat()); + m_context->setScreen(window->screen()); + m_context->create(); +} + +QIOSBackingStore::~QIOSBackingStore() +{ + delete m_context; + delete m_device; +} + +void QIOSBackingStore::beginPaint(const QRegion &) +{ + // Needed to prevent QOpenGLContext::makeCurrent() from failing + window()->setSurfaceType(QSurface::OpenGLSurface); + + m_context->makeCurrent(window()); + + static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size()); + QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle()); + static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size() * iosWindow->devicePixelRatio()); +} + +QPaintDevice *QIOSBackingStore::paintDevice() +{ + if (!m_device) { + QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle()); + QOpenGLPaintDevice *openGLDevice = new QOpenGLPaintDevice(window()->size() * iosWindow->devicePixelRatio()); + openGLDevice->setDevicePixelRatio(iosWindow->devicePixelRatio()); + m_device = openGLDevice; + } + + return m_device; +} + +void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + + if (window != this->window()) { + // We skip flushing raster-based child windows, to avoid the extra cost of copying from the + // parent FBO into the child FBO. Since the child is already drawn inside the parent FBO, it + // will become visible when flushing the parent. The only case we end up not supporting is if + // the child window overlaps a sibling window that's draws using a separate QOpenGLContext. + return; + } + m_context->swapBuffers(window); +} + +void QIOSBackingStore::endPaint() +{ + // Calling makeDone() on the context here would be an option, + // but is not needed, and would actually add some overhead. +} + +void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); + + // Resizing the backing store would in our case mean resizing the QWindow, + // as we cheat and use an QOpenGLPaintDevice that we target at the window. + // That's probably not what the user intended, so we ignore resizes of the + // backing store and always keep the paint device's size in sync with the + // window size in beginPaint(). + + if (size != window()->size()) + qWarning() << "QIOSBackingStore needs to have the same size as its window"; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h new file mode 100644 index 0000000000..082ec4794c --- /dev/null +++ b/src/plugins/platforms/ios/qioscontext.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 QIOSCONTEXT_H +#define QIOSCONTEXT_H + +#include <qpa/qplatformopenglcontext.h> + +@class EAGLContext; + +QT_BEGIN_NAMESPACE + +class QIOSContext : public QObject, public QPlatformOpenGLContext +{ + Q_OBJECT + +public: + QIOSContext(QOpenGLContext *context); + ~QIOSContext(); + + QSurfaceFormat format() const; + + void swapBuffers(QPlatformSurface *surface); + + bool makeCurrent(QPlatformSurface *surface); + void doneCurrent(); + + GLuint defaultFramebufferObject(QPlatformSurface *) const; + QFunctionPointer getProcAddress(const QByteArray &procName); + +private Q_SLOTS: + void windowDestroyed(QObject *object); + +private: + EAGLContext *m_eaglContext; + QSurfaceFormat m_format; + + struct FramebufferObject { + GLuint handle; + GLuint colorRenderbuffer; + GLuint depthRenderbuffer; + GLint renderbufferWidth; + GLint renderbufferHeight; + }; + + static void deleteBuffers(const FramebufferObject &framebufferObject); + + mutable QHash<QWindow *, FramebufferObject> m_framebufferObjects; +}; + +QT_END_NAMESPACE + +#endif // QIOSCONTEXT_H diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm new file mode 100644 index 0000000000..d3966964e0 --- /dev/null +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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 "qioscontext.h" +#include "qioswindow.h" + +#include <dlfcn.h> + +#include <QtGui/QOpenGlContext> + +#import <OpenGLES/EAGL.h> +#import <QuartzCore/CAEAGLLayer.h> + +QIOSContext::QIOSContext(QOpenGLContext *context) + : QPlatformOpenGLContext() + , m_eaglContext([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]) +{ + // Start out with the requested format + QSurfaceFormat format = context->format(); + + format.setRenderableType(QSurfaceFormat::OpenGLES); + format.setMajorVersion(2); + format.setMinorVersion(0); + + // Even though iOS internally double-buffers its rendering, we + // report single-buffered here since the buffer remains unchanged + // when swapping unlesss you manually clear it yourself. + format.setSwapBehavior(QSurfaceFormat::SingleBuffer); + + m_format = format; +} + +QIOSContext::~QIOSContext() +{ + [EAGLContext setCurrentContext:m_eaglContext]; + + foreach (const FramebufferObject &framebufferObject, m_framebufferObjects) + deleteBuffers(framebufferObject); + + [EAGLContext setCurrentContext:nil]; + [m_eaglContext release]; +} + +void QIOSContext::deleteBuffers(const FramebufferObject &framebufferObject) +{ + if (framebufferObject.handle) + glDeleteFramebuffers(1, &framebufferObject.handle); + if (framebufferObject.colorRenderbuffer) + glDeleteRenderbuffers(1, &framebufferObject.colorRenderbuffer); + if (framebufferObject.depthRenderbuffer) + glDeleteRenderbuffers(1, &framebufferObject.depthRenderbuffer); +} + +QSurfaceFormat QIOSContext::format() const +{ + return m_format; +} + +bool QIOSContext::makeCurrent(QPlatformSurface *surface) +{ + Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + + [EAGLContext setCurrentContext:m_eaglContext]; + glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject(surface)); + + return true; +} + +void QIOSContext::doneCurrent() +{ + [EAGLContext setCurrentContext:nil]; +} + +void QIOSContext::swapBuffers(QPlatformSurface *surface) +{ + Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface); + Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window); + QWindow *window = static_cast<QWindow *>(surface->surface()); + Q_ASSERT(m_framebufferObjects.contains(window)); + + [EAGLContext setCurrentContext:m_eaglContext]; + glBindRenderbuffer(GL_RENDERBUFFER, m_framebufferObjects[window].colorRenderbuffer); + [m_eaglContext presentRenderbuffer:GL_RENDERBUFFER]; +} + +GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const +{ + Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window); + QWindow *window = static_cast<QWindow *>(surface->surface()); + + FramebufferObject &framebufferObject = m_framebufferObjects[window]; + + // Set up an FBO for the window if it hasn't been created yet + if (!framebufferObject.handle) { + [EAGLContext setCurrentContext:m_eaglContext]; + + glGenFramebuffers(1, &framebufferObject.handle); + glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle); + + glGenRenderbuffers(1, &framebufferObject.colorRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + framebufferObject.colorRenderbuffer); + + if (m_format.depthBufferSize() > 0 || m_format.stencilBufferSize() > 0) { + glGenRenderbuffers(1, &framebufferObject.depthRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + framebufferObject.depthRenderbuffer); + + if (m_format.stencilBufferSize() > 0) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + framebufferObject.depthRenderbuffer); + } + + connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*))); + } + + // Ensure that the FBO's buffers match the size of the window + QIOSWindow *platformWindow = static_cast<QIOSWindow *>(surface); + if (framebufferObject.renderbufferWidth != platformWindow->effectiveWidth() || + framebufferObject.renderbufferHeight != platformWindow->effectiveHeight()) { + + glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer); + UIView *view = reinterpret_cast<UIView *>(platformWindow->winId()); + CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer); + [m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]; + + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferObject.renderbufferWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferObject.renderbufferHeight); + + if (framebufferObject.depthRenderbuffer) { + glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer); + + // FIXME: Support more fine grained control over depth/stencil buffer sizes + if (m_format.stencilBufferSize() > 0) + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, + framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight); + } + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + } + + return framebufferObject.handle; +} + +void QIOSContext::windowDestroyed(QObject *object) +{ + QWindow *window = static_cast<QWindow *>(object); + if (m_framebufferObjects.contains(window)) { + deleteBuffers(m_framebufferObjects[window]); + m_framebufferObjects.remove(window); + } +} + +QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName) +{ + return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData())); +} + +#include "moc_qioscontext.cpp" + diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h new file mode 100644 index 0000000000..53a75618ce --- /dev/null +++ b/src/plugins/platforms/ios/qioseventdispatcher.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 new file mode 100644 index 0000000000..e9bf039047 --- /dev/null +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** 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/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h new file mode 100644 index 0000000000..3be9f8bb21 --- /dev/null +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 QIOSGLOBAL_H +#define QIOSGLOBAL_H + +#import <UIKit/UIKit.h> +#include <QtCore/QtCore> + +@class QIOSViewController; + +QT_BEGIN_NAMESPACE + +class QPlatformScreen; + +bool isQtApplication(); +QIOSViewController *rootViewController(); + +CGRect toCGRect(const QRect &rect); +QRect fromCGRect(const CGRect &rect); +CGPoint toCGPoint(const QPoint &point); +QPoint fromCGPoint(const CGPoint &point); +Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation); +UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation); +QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen); + +QT_END_NAMESPACE + +#endif // QIOSGLOBAL_H diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm new file mode 100644 index 0000000000..5860078372 --- /dev/null +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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 "qiosglobal.h" +#include "qiosapplicationdelegate.h" +#include "qiosviewcontroller.h" +#include "qiosscreen.h" + +QT_BEGIN_NAMESPACE + +bool isQtApplication() +{ + // Returns true if the plugin is in full control of the whole application. This means + // that we control the application delegate and the top view controller, and can take + // actions that impacts all parts of the application. The opposite means that we are + // embedded inside a native iOS application, and should be more focused on playing along + // with native UIControls, and less inclined to change structures that lies outside the + // scope of our QWindows/UIViews. + static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]); + return isQt; +} + +QIOSViewController *rootViewController() +{ + static QIOSViewController *c = isQtApplication() ? + static_cast<QIOSViewController *>([UIApplication sharedApplication].delegate.window.rootViewController) : nil; + return c; +} + +CGRect toCGRect(const QRect &rect) +{ + return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); +} + +QRect fromCGRect(const CGRect &rect) +{ + return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); +} + +CGPoint toCGPoint(const QPoint &point) +{ + return CGPointMake(point.x(), point.y()); +} + +QPoint fromCGPoint(const CGPoint &point) +{ + return QPoint(point.x, point.y); +} + +Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation) +{ + Qt::ScreenOrientation qtOrientation; + switch (uiDeviceOrientation) { + case UIDeviceOrientationPortraitUpsideDown: + qtOrientation = Qt::InvertedPortraitOrientation; + break; + case UIDeviceOrientationLandscapeLeft: + qtOrientation = Qt::InvertedLandscapeOrientation; + break; + case UIDeviceOrientationLandscapeRight: + qtOrientation = Qt::LandscapeOrientation; + break; + case UIDeviceOrientationFaceUp: + case UIDeviceOrientationFaceDown: + qtOrientation = static_cast<Qt::ScreenOrientation>(-1); // not supported ATM. + break; + default: + qtOrientation = Qt::PortraitOrientation; + break; + } + return qtOrientation; +} + +UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation) +{ + UIDeviceOrientation uiOrientation; + switch (qtOrientation) { + case Qt::LandscapeOrientation: + uiOrientation = UIDeviceOrientationLandscapeRight; + break; + case Qt::InvertedLandscapeOrientation: + uiOrientation = UIDeviceOrientationLandscapeLeft; + break; + case Qt::InvertedPortraitOrientation: + uiOrientation = UIDeviceOrientationPortraitUpsideDown; + break; + case Qt::PrimaryOrientation: + case Qt::PortraitOrientation: + default: + uiOrientation = UIDeviceOrientationPortrait; + break; + } + return uiOrientation; +} + +QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen) +{ + // UIScreen is always in portrait. Use this function to convert CGRects + // aligned with UIScreen into whatever is the current orientation of QScreen. + QRect geometry = screen->geometry(); + return geometry.width() < geometry.height() ? rect + : QRect(rect.y(), geometry.width() - rect.width() - rect.x(), rect.height(), rect.width()); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h new file mode 100644 index 0000000000..176ad05733 --- /dev/null +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 QIOSINPUTCONTEXT_H +#define QIOSINPUTCONTEXT_H + +#include <UIKit/UIKit.h> + +#include <qpa/qplatforminputcontext.h> + +QT_BEGIN_NAMESPACE + +@class QIOSKeyboardListener; + +class QIOSInputContext : public QPlatformInputContext +{ +public: + QIOSInputContext(); + ~QIOSInputContext(); + + QRectF keyboardRect() const; + void showInputPanel(); + void hideInputPanel(); + bool isInputPanelVisible() const; + + void focusViewChanged(UIView *view); + +private: + QIOSKeyboardListener *m_keyboardListener; + UIView *m_focusView; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm new file mode 100644 index 0000000000..1d3ab12de9 --- /dev/null +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 "qiosglobal.h" +#include "qiosinputcontext.h" +#include "qioswindow.h" +#include <QGuiApplication> + +@interface QIOSKeyboardListener : NSObject { +@public + QIOSInputContext *m_context; + BOOL m_keyboardVisible; + QRectF m_keyboardRect; +} +@end + +@implementation QIOSKeyboardListener + +- (id)initWithQIOSInputContext:(QIOSInputContext *)context +{ + self = [super init]; + if (self) { + m_context = context; + m_keyboardVisible = NO; + // After the keyboard became undockable (iOS5), UIKeyboardWillShow/UIKeyboardWillHide + // no longer works for all cases. So listen to keyboard frame changes instead: + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(keyboardDidChangeFrame:) + name:@"UIKeyboardDidChangeFrameNotification" object:nil]; + } + return self; +} + +- (void) dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIKeyboardDidChangeFrameNotification" object:nil]; + [super dealloc]; +} + +- (void) keyboardDidChangeFrame:(NSNotification *)notification +{ + CGRect frame; + [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame]; + + m_keyboardRect = fromPortraitToPrimary(fromCGRect(frame), QGuiApplication::primaryScreen()->handle()); + m_context->emitKeyboardRectChanged(); + + BOOL visible = CGRectIntersectsRect(frame, [UIScreen mainScreen].bounds); + if (m_keyboardVisible != visible) { + m_keyboardVisible = visible; + m_context->emitInputPanelVisibleChanged(); + } +} + +@end + +QIOSInputContext::QIOSInputContext() + : QPlatformInputContext() + , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) + , m_focusView(0) +{ +} + +QIOSInputContext::~QIOSInputContext() +{ + [m_keyboardListener release]; + [m_focusView release]; +} + +QRectF QIOSInputContext::keyboardRect() const +{ + return m_keyboardListener->m_keyboardRect; +} + +void QIOSInputContext::showInputPanel() +{ + // Documentation tells that one should call (and recall, if necessary) becomeFirstResponder/resignFirstResponder + // to show/hide the keyboard. This is slightly inconvenient, since there exist no API to get the current first + // 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_focusView becomeFirstResponder]; +} + +void QIOSInputContext::hideInputPanel() +{ + [m_focusView resignFirstResponder]; +} + +bool QIOSInputContext::isInputPanelVisible() const +{ + return m_keyboardListener->m_keyboardVisible; +} + +void QIOSInputContext::focusViewChanged(UIView *view) +{ + if ([m_focusView isFirstResponder]) + [view becomeFirstResponder]; + [m_focusView release]; + m_focusView = [view retain]; +} diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h new file mode 100644 index 0000000000..329a0a3d9b --- /dev/null +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 QPLATFORMINTEGRATION_UIKIT_H +#define QPLATFORMINTEGRATION_UIKIT_H + +#include <qpa/qplatformintegration.h> +#include <qpa/qplatformnativeinterface.h> +#include <qpa/qwindowsysteminterface.h> + +QT_BEGIN_NAMESPACE + +class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface +{ +public: + QIOSIntegration(); + ~QIOSIntegration(); + + bool hasCapability(Capability cap) const; + + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + + QPlatformFontDatabase *fontDatabase() const; + QPlatformInputContext *inputContext() const; + + QVariant styleHint(StyleHint hint) const; + + QStringList themeNames() const; + QPlatformTheme *createPlatformTheme(const QString &name) const; + + QAbstractEventDispatcher *guiThreadEventDispatcher() const; + QPlatformNativeInterface *nativeInterface() const; + + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); + + QTouchDevice *touchDevice(); +private: + QPlatformFontDatabase *m_fontDatabase; + QPlatformInputContext *m_inputContext; + QPlatformScreen *m_screen; + QTouchDevice *m_touchDevice; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm new file mode 100644 index 0000000000..c7541c3e38 --- /dev/null +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** 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 "qiosintegration.h" +#include "qioswindow.h" +#include "qiosbackingstore.h" +#include "qiosscreen.h" +#include "qioseventdispatcher.h" +#include "qioscontext.h" +#include "qiosinputcontext.h" +#include "qiostheme.h" + +#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> + +#include <QtDebug> + +QT_BEGIN_NAMESPACE + +QIOSIntegration::QIOSIntegration() + : m_fontDatabase(new QCoreTextFontDatabase) + , m_inputContext(new QIOSInputContext) + , 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); + + m_touchDevice = new QTouchDevice; + m_touchDevice->setType(QTouchDevice::TouchScreen); + m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(m_touchDevice); +} + +QIOSIntegration::~QIOSIntegration() +{ + delete m_touchDevice; +} + +bool QIOSIntegration::hasCapability(Capability cap) const +{ + switch (cap) { + case OpenGL: + return true; + case MultipleWindows: + return true; + default: + return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const +{ + return new QIOSWindow(window); +} + +// Used when the QWindow's surface type is set by the client to QSurface::RasterSurface +QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QIOSBackingStore(window); +} + +// Used when the QWindow's surface type is set by the client to QSurface::OpenGLSurface +QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + Q_UNUSED(context); + return new QIOSContext(context); +} + +QAbstractEventDispatcher *QIOSIntegration::guiThreadEventDispatcher() const +{ + return new QIOSEventDispatcher(); +} + +QPlatformFontDatabase * QIOSIntegration::fontDatabase() const +{ + return m_fontDatabase; +} + +QPlatformInputContext *QIOSIntegration::inputContext() const +{ + return m_inputContext; +} + +QVariant QIOSIntegration::styleHint(StyleHint hint) const +{ + switch (hint) { + case ShowIsFullScreen: + return true; + default: + return QPlatformIntegration::styleHint(hint); + } +} + +QStringList QIOSIntegration::themeNames() const +{ + return QStringList(QLatin1String(QIOSTheme::name)); +} + +QPlatformTheme *QIOSIntegration::createPlatformTheme(const QString &name) const +{ + if (name == QLatin1String(QIOSTheme::name)) + return new QIOSTheme; + + return QPlatformIntegration::createPlatformTheme(name); +} + +QPlatformNativeInterface *QIOSIntegration::nativeInterface() const +{ + return const_cast<QIOSIntegration *>(this); +} + +void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + if (!window || !window->handle()) + return 0; + + QByteArray lowerCaseResource = resource.toLower(); + + QIOSWindow *platformWindow = static_cast<QIOSWindow *>(window->handle()); + + if (lowerCaseResource == "uiview") + return reinterpret_cast<void *>(platformWindow->winId()); + + return 0; +} + +QTouchDevice *QIOSIntegration::touchDevice() +{ + return m_touchDevice; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h new file mode 100644 index 0000000000..40c7a3ccf7 --- /dev/null +++ b/src/plugins/platforms/ios/qiosscreen.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 QIOSSCREEN_H +#define QIOSSCREEN_H + +#include <UIKit/UIKit.h> + +#include <qpa/qplatformscreen.h> + +@class QIOSOrientationListener; + +QT_BEGIN_NAMESPACE + +class QIOSScreen : public QPlatformScreen +{ +public: + QIOSScreen(unsigned int screenIndex); + ~QIOSScreen(); + + enum ScreenIndex { MainScreen = 0 }; + + QRect geometry() const; + QRect availableGeometry() const; + int depth() const; + QImage::Format format() const; + QSizeF physicalSize() const; + QDpi logicalDpi() const; + qreal devicePixelRatio() const; + + Qt::ScreenOrientation nativeOrientation() const; + Qt::ScreenOrientation orientation() const; + void setOrientationUpdateMask(Qt::ScreenOrientations mask); + + UIScreen *uiScreen() const; + + void setPrimaryOrientation(Qt::ScreenOrientation orientation); + +private: + UIScreen *m_uiScreen; + QRect m_geometry; + QRect m_availableGeometry; + int m_depth; + QSizeF m_physicalSize; + QIOSOrientationListener *m_orientationListener; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm new file mode 100644 index 0000000000..3265ed8e37 --- /dev/null +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** 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 "qiosglobal.h" +#include "qiosscreen.h" +#include "qioswindow.h" +#include <qpa/qwindowsysteminterface.h> +#include "qiosapplicationdelegate.h" +#include "qiosviewcontroller.h" + +#include <sys/sysctl.h> + +@interface QIOSOrientationListener : NSObject { + @public + QIOSScreen *m_screen; +} +- (id) initWithQIOSScreen:(QIOSScreen *)screen; +@end + +@implementation QIOSOrientationListener + +- (id) initWithQIOSScreen:(QIOSScreen *)screen +{ + self = [super init]; + if (self) { + m_screen = screen; + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(orientationChanged:) + name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + } + return self; +} + +- (void) dealloc +{ + [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + [super dealloc]; +} + +- (void) orientationChanged:(NSNotification *)notification +{ + Q_UNUSED(notification); + Qt::ScreenOrientation orientation = toQtScreenOrientation([UIDevice currentDevice].orientation); + if (orientation != -1) + QWindowSystemInterface::handleScreenOrientationChange(m_screen->screen(), orientation); +} + +@end + +/*! + Returns the model identifier of the device. + + When running under the simulator, the identifier will not + match the simulated device, but will be x86_64 or i386. +*/ +static QString deviceModelIdentifier() +{ + static const char key[] = "hw.machine"; + + size_t size; + sysctlbyname(key, NULL, &size, NULL, 0); + + char value[size]; + sysctlbyname(key, &value, &size, NULL, 0); + + return QString::fromLatin1(value); +} + +QIOSScreen::QIOSScreen(unsigned int screenIndex) + : QPlatformScreen() + , m_uiScreen([[UIScreen screens] objectAtIndex:qMin(screenIndex, [[UIScreen screens] count] - 1)]) + , m_orientationListener(0) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + QString deviceIdentifier = deviceModelIdentifier(); + + if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */ + || deviceIdentifier == QStringLiteral("iPod3,1") /* iPod touch 3G */) { + m_depth = 18; + } else { + m_depth = 24; + } + + int unscaledDpi = 163; // Regular iPhone DPI + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad + && deviceIdentifier != QStringLiteral("iPad2,5") /* iPad Mini */) { + unscaledDpi = 132; + }; + + CGRect bounds = [m_uiScreen bounds]; + m_geometry = QRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); + + CGRect frame = m_uiScreen.applicationFrame; + m_availableGeometry = QRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); + + const qreal millimetersPerInch = 25.4; + m_physicalSize = QSizeF(m_geometry.size()) / unscaledDpi * millimetersPerInch; + + if (isQtApplication()) { + // When in a non-mixed environment, let QScreen follow the current interface orientation: + setPrimaryOrientation(toQtScreenOrientation(rootViewController().interfaceOrientation)); + } + + [pool release]; +} + +QIOSScreen::~QIOSScreen() +{ + [m_orientationListener release]; +} + +QRect QIOSScreen::geometry() const +{ + return m_geometry; +} + +QRect QIOSScreen::availableGeometry() const +{ + return m_availableGeometry; +} + +int QIOSScreen::depth() const +{ + return m_depth; +} + +QImage::Format QIOSScreen::format() const +{ + return QImage::Format_ARGB32_Premultiplied; +} + +QSizeF QIOSScreen::physicalSize() const +{ + return m_physicalSize; +} + +QDpi QIOSScreen::logicalDpi() const +{ + return QDpi(72, 72); +} + +qreal QIOSScreen::devicePixelRatio() const +{ + return [m_uiScreen scale]; +} + +Qt::ScreenOrientation QIOSScreen::nativeOrientation() const +{ + return Qt::PortraitOrientation; +} + +Qt::ScreenOrientation QIOSScreen::orientation() const +{ + return toQtScreenOrientation([UIDevice currentDevice].orientation); +} + +void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) +{ + if (m_orientationListener && mask == Qt::PrimaryOrientation) { + [m_orientationListener release]; + m_orientationListener = 0; + } else if (!m_orientationListener) { + m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this]; + } +} + +void QIOSScreen::setPrimaryOrientation(Qt::ScreenOrientation orientation) +{ + // Note that UIScreen never changes orientation, but QScreen should. To work around + // this, we let QIOSViewController call us whenever interface orientation changes, and + // use that as primary orientation. After all, the viewcontrollers geometry is what we + // place QWindows on top of. A problem with this approach is that QIOSViewController is + // not in use in a mixed environment, which results in no change to primary orientation. + // We see that as acceptable since Qt should most likely not interfere with orientation + // for that case anyway. + bool portrait = screen()->isPortrait(orientation); + if (portrait && m_geometry.width() < m_geometry.height()) + return; + + // Switching portrait/landscape means swapping width/height (and adjusting x/y): + m_geometry = QRect(0, 0, m_geometry.height(), m_geometry.width()); + m_physicalSize = QSizeF(m_physicalSize.height(), m_physicalSize.width()); + m_availableGeometry = fromPortraitToPrimary(fromCGRect(m_uiScreen.applicationFrame), this); + + QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry); + QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_availableGeometry); +} + +UIScreen *QIOSScreen::uiScreen() const +{ + return m_uiScreen; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiossoftwareinputhandler.h b/src/plugins/platforms/ios/qiossoftwareinputhandler.h new file mode 100644 index 0000000000..5dad6b8d86 --- /dev/null +++ b/src/plugins/platforms/ios/qiossoftwareinputhandler.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 QIOSSOFTWAREINPUTHANDLER_H +#define QIOSSOFTWAREINPUTHANDLER_H + +#include <QtCore/QObject> +#include <QtCore/QPointer> +#include <QtWidgets/QWidget> + +QT_BEGIN_NAMESPACE + +class QIOSSoftwareInputHandler : public QObject +{ + Q_OBJECT + +public: + QIOSSoftwareInputHandler() : m_CurrentFocusWidget(0), m_CurrentFocusObject(0) {} + bool eventFilter(QObject *obj, QEvent *event); + +private slots: + void activeFocusChanged(bool focus); + +private: + bool closeSoftwareInputPanel(QWidget *widget); + + QPointer<QWidget> m_currentFocusWidget; + QPointer<QObject> m_currentFocusObject; +}; + +QT_END_NAMESPACE + +#endif diff --git a/mkspecs/unsupported/macx-iosdevice-clang/qplatformdefs.h b/src/plugins/platforms/ios/qiostheme.h index 5f80a17860..5ccbcac710 100644 --- a/mkspecs/unsupported/macx-iosdevice-clang/qplatformdefs.h +++ b/src/plugins/platforms/ios/qiostheme.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the qmake spec of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,4 +39,26 @@ ** ****************************************************************************/ -#include "../../common/ios/qplatformdefs.h" +#ifndef QIOSTHEME_H +#define QIOSTHEME_H + +#include <qpa/qplatformtheme.h> + +QT_BEGIN_NAMESPACE + +class QIOSTheme : public QPlatformTheme +{ +public: + QIOSTheme(); + ~QIOSTheme(); + + QVariant themeHint(ThemeHint hint) const; + + const QFont *font(Font type = SystemFont) const; + + static const char *name; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm new file mode 100644 index 0000000000..f98781f8a7 --- /dev/null +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 "qiostheme.h" + +#include <QtCore/QStringList> +#include <QtCore/QVariant> + +#include <QtGui/QFont> + +#include <UIKit/UIFont.h> +#include <UIKit/UIInterface.h> + +QT_BEGIN_NAMESPACE + +const char *QIOSTheme::name = "ios"; + +QIOSTheme::QIOSTheme() +{ +} + +QIOSTheme::~QIOSTheme() +{ +} + +QVariant QIOSTheme::themeHint(ThemeHint hint) const +{ + switch (hint) { + case QPlatformTheme::StyleNames: + return QStringList(QStringLiteral("fusion")); + default: + return QPlatformTheme::themeHint(hint); + } +} + +const QFont *QIOSTheme::font(Font type) const +{ + static QHash<QPlatformTheme::Font, QFont *> fonts; + if (fonts.isEmpty()) { + // The real system font on iOS is '.Helvetica Neue UI', as returned by both [UIFont systemFontOfSize] + // and CTFontCreateUIFontForLanguage(kCTFontSystemFontType, ...), but this font is not included when + // populating the available fonts in QCoreTextFontDatabase::populateFontDatabase(), since the font + // is internal to iOS and not supposed to be used by applications. We could potentially add this + // font to the font-database, but it would then show up when enumerating user fonts from Qt + // applications since we don't have a flag in Qt to mark a font as a private system font. + // For now we hard-code the font to Helvetica, which should be very close to the actual + // system font. + QLatin1String systemFontFamilyName("Helvetica"); + fonts.insert(QPlatformTheme::SystemFont, new QFont(systemFontFamilyName, [UIFont systemFontSize])); + fonts.insert(QPlatformTheme::SmallFont, new QFont(systemFontFamilyName, [UIFont smallSystemFontSize])); + fonts.insert(QPlatformTheme::LabelFont, new QFont(systemFontFamilyName, [UIFont labelFontSize])); + fonts.insert(QPlatformTheme::PushButtonFont, new QFont(systemFontFamilyName, [UIFont buttonFontSize])); + } + + return fonts.value(type, 0); +} + +QT_END_NAMESPACE diff --git a/mkspecs/common/ios/GLES/gl.h b/src/plugins/platforms/ios/qiosviewcontroller.h index 2b94b162eb..d5a61cb3f4 100644 --- a/mkspecs/common/ios/GLES/gl.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -3,7 +3,7 @@ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the qmake spec of the Qt Toolkit. +** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -39,5 +39,8 @@ ** ****************************************************************************/ -#include <OpenGLES/ES1/gl.h> -#include <OpenGLES/ES1/glext.h> +#import <UIKit/UIKit.h> + +@interface QIOSViewController : UIViewController +@end + diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm new file mode 100644 index 0000000000..c52bfd7345 --- /dev/null +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 "qiosviewcontroller.h" + +#include <QtGui/QGuiApplication> +#include <QtGui/QScreen> +#include "qiosscreen.h" +#include "qiosglobal.h" + +@implementation QIOSViewController + +- (void)viewDidLoad +{ +#ifdef QT_DEBUG + if (!self.nibName) + self.view.backgroundColor = [UIColor magentaColor]; +#endif +} + +-(BOOL)shouldAutorotate +{ + // For now we assume that if the application doesn't listen to orientation + // updates it means it would like to enable auto-rotation, and vice versa. + if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp)) + return !guiApp->primaryScreen()->orientationUpdateMask(); + else + return YES; // Startup case: QGuiApplication is not ready yet. + + // FIXME: Investigate a proper Qt API for auto-rotation and orientation locking +} + +-(NSUInteger)supportedInterfaceOrientations +{ + // We need to tell iOS that we support all orientations in order to set + // status bar orientation when application content orientation changes. + return UIInterfaceOrientationMaskAll; +} + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration +{ + Q_UNUSED(duration); + Qt::ScreenOrientation orientation = toQtScreenOrientation(toInterfaceOrientation); + if (orientation == -1) + return; + + QIOSScreen *qiosScreen = static_cast<QIOSScreen *>(QGuiApplication::primaryScreen()->handle()); + qiosScreen->setPrimaryOrientation(orientation); +} + +@end + diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h new file mode 100644 index 0000000000..cefb6f9388 --- /dev/null +++ b/src/plugins/platforms/ios/qioswindow.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 QIOSWINDOW_H +#define QIOSWINDOW_H + +#include <qpa/qplatformwindow.h> +#include <qpa/qwindowsysteminterface.h> + +#import <UIKit/UIKit.h> + +class QIOSContext; +class QIOSWindow; + +@interface UIView (QIOS) +@property(readonly) QWindow *qwindow; +@end + +QT_BEGIN_NAMESPACE + +class QIOSWindow : public QPlatformWindow +{ +public: + explicit QIOSWindow(QWindow *window); + ~QIOSWindow(); + + void setGeometry(const QRect &rect); + + void setWindowState(Qt::WindowState state); + void setParent(const QPlatformWindow *window); + void handleContentOrientationChange(Qt::ScreenOrientation orientation); + void setVisible(bool visible); + + void raise() { raiseOrLower(true); } + void lower() { raiseOrLower(false); } + void requestActivateWindow(); + + qreal devicePixelRatio() const; + int effectiveWidth() const; + int effectiveHeight() const; + + WId winId() const { return WId(m_view); }; + + QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; } + QHash<UITouch *, int> &activeTouches() { return m_activeTouches; } + int &touchId() { return m_touchId; } + +private: + UIView *m_view; + QList<QWindowSystemInterface::TouchPoint> m_touchPoints; + QHash<UITouch *, int> m_activeTouches; + int m_touchId; + + QRect m_requestedGeometry; + int m_windowLevel; + qreal m_devicePixelRatio; + + void raiseOrLower(bool raise); + void updateWindowLevel(); + bool blockedByModal(); +}; + +QT_END_NAMESPACE + +#endif // QIOSWINDOW_H diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm new file mode 100644 index 0000000000..e4fb5e2e1c --- /dev/null +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -0,0 +1,523 @@ +/**************************************************************************** +** +** 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 "qiosglobal.h" +#include "qioswindow.h" +#include "qioscontext.h" +#include "qiosinputcontext.h" +#include "qiosscreen.h" +#include "qiosapplicationdelegate.h" +#include "qiosviewcontroller.h" +#include "qiosintegration.h" +#include <QtGui/private/qguiapplication_p.h> +#include <qpa/qplatformintegration.h> + +#import <QuartzCore/CAEAGLLayer.h> + +#include <QtGui/QKeyEvent> +#include <qpa/qwindowsysteminterface.h> + +#include <QtDebug> + +@interface EAGLView : UIView <UIKeyInput> +{ +@public + UITextAutocapitalizationType autocapitalizationType; + UITextAutocorrectionType autocorrectionType; + BOOL enablesReturnKeyAutomatically; + UIKeyboardAppearance keyboardAppearance; + UIKeyboardType keyboardType; + UIReturnKeyType returnKeyType; + BOOL secureTextEntry; + QIOSWindow *m_qioswindow; +} + +@property(nonatomic) UITextAutocapitalizationType autocapitalizationType; +@property(nonatomic) UITextAutocorrectionType autocorrectionType; +@property(nonatomic) BOOL enablesReturnKeyAutomatically; +@property(nonatomic) UIKeyboardAppearance keyboardAppearance; +@property(nonatomic) UIKeyboardType keyboardType; +@property(nonatomic) UIReturnKeyType returnKeyType; +@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry; + +@end + +@implementation EAGLView + ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +-(id)initWithQIOSWindow:(QIOSWindow *)window +{ + if (self = [self initWithFrame:toCGRect(window->geometry())]) + m_qioswindow = window; + + return self; +} + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + // Set up EAGL layer + CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer); + eaglLayer.opaque = TRUE; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking, + kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + // Set up text input + autocapitalizationType = UITextAutocapitalizationTypeNone; + autocorrectionType = UITextAutocorrectionTypeNo; + enablesReturnKeyAutomatically = NO; + keyboardAppearance = UIKeyboardAppearanceDefault; + keyboardType = UIKeyboardTypeDefault; + returnKeyType = UIReturnKeyDone; + secureTextEntry = NO; + + if (isQtApplication()) + self.hidden = YES; + + self.multipleTouchEnabled = YES; + } + + return self; +} + +- (void)layoutSubviews +{ + // This method is the de facto way to know that view has been resized, + // or otherwise needs invalidation of its buffers. Note though that we + // do not get this callback when the view just changes its position, so + // the position of our QWindow (and platform window) will only get updated + // when the size is also changed. + + if (!CGAffineTransformIsIdentity(self.transform)) + qWarning() << m_qioswindow->window() + << "is backed by a UIView that has a transform set. This is not supported."; + + QRect geometry = fromCGRect(self.frame); + m_qioswindow->QPlatformWindow::setGeometry(geometry); + QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), geometry); + + // If we have a new size here we need to resize the FBO's corresponding buffers, + // but we defer that to when the application calls makeCurrent. + + [super layoutSubviews]; +} + +/* + Touch handling: + + UIKit generates [Began -> Moved -> Ended] event sequences for + each touch point. The iOS plugin tracks each individual + touch and assigns it an id for use by Qt. The id counter is + incremented on each began and decrement as follows: + 1) by one when the most recent touch ends. + 2) to zero when all touches ends. + + The TouchPoint list is reused between events. +*/ +- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state +{ + QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints(); + QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches(); + + // Mark all touch points as stationary + for (QList<QWindowSystemInterface::TouchPoint>::iterator it = touchPoints.begin(); it != touchPoints.end(); ++it) + it->state = Qt::TouchPointStationary; + + // Update changed touch points with the new state + for (UITouch *touch in touches) { + const int touchId = activeTouches.value(touch); + QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[touchId]; + touchPoint.state = state; + if (state == Qt::TouchPointPressed) + touchPoint.pressure = 1.0; + else if (state == Qt::TouchPointReleased) + touchPoint.pressure = 0.0; + + // Set position + QRect viewGeometry = fromCGRect(self.frame); + QPoint touchViewLocation = fromCGPoint([touch locationInView:self]); + QPoint touchScreenLocation = touchViewLocation + viewGeometry.topLeft(); + touchPoint.area = QRectF(touchScreenLocation , QSize(0, 0)); + + CGSize fullscreenSize = self.window.rootViewController.view.bounds.size; + touchPoint.normalPosition = QPointF(touchScreenLocation.x() / fullscreenSize.width, touchScreenLocation.y() / fullscreenSize.height); + } +} + +- (void) sendTouchEventWithTimestamp:(ulong)timeStamp +{ + // Send touch event synchronously + QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp, + iosIntegration->touchDevice(), m_qioswindow->touchPoints()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + QWindow *window = m_qioswindow->window(); + + // Transfer focus to the touched window: + if (window != QGuiApplication::focusWindow()) + m_qioswindow->requestActivateWindow(); + + // Track Cocoa touch id to Qt touch id. The UITouch pointer is constant + // for the touch duration. + QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches(); + QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints(); + for (UITouch *touch in touches) + activeTouches.insert(touch, m_qioswindow->touchId()++); + + // Create new touch points if needed. + int newTouchPointsNeeded = m_qioswindow->touchId() - touchPoints.count(); + for (int i = 0; i < newTouchPointsNeeded; ++i) { + QWindowSystemInterface::TouchPoint touchPoint; + touchPoint.id = touchPoints.count(); // id is the index in the touchPoints list. + touchPoints.append(touchPoint); + } + + [self updateTouchList:touches withState:Qt::TouchPointPressed]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + [self updateTouchList:touches withState:Qt::TouchPointMoved]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + [self updateTouchList:touches withState:Qt::TouchPointReleased]; + [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)]; + + // Remove ended touch points from the active set (event processing has completed at this point) + QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches(); + for (UITouch *touch in touches) { + int id = activeTouches.take(touch); + + // If this touch is the most recent touch we can reuse its id + if (id == m_qioswindow->touchId() - 1) + --m_qioswindow->touchId(); + } + + // Reset the touch id when there are no more active touches + if (activeTouches.isEmpty()) + m_qioswindow->touchId() = 0; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event +{ + Q_UNUSED(touches) // ### can a subset of the active touches be cancelled? + + // Clear current touch points + m_qioswindow->activeTouches().clear(); + m_qioswindow->touchId() = 0; + + // Send cancel touch event synchronously + QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(event.timestamp * 1000), iosIntegration->touchDevice()); + QWindowSystemInterface::flushWindowSystemEvents(); +} + +@synthesize autocapitalizationType; +@synthesize autocorrectionType; +@synthesize enablesReturnKeyAutomatically; +@synthesize keyboardAppearance; +@synthesize keyboardType; +@synthesize returnKeyType; +@synthesize secureTextEntry; + +- (BOOL)canBecomeFirstResponder +{ + return YES; +} + +- (BOOL)hasText +{ + return YES; +} + +- (void)insertText:(NSString *)text +{ + QString string = QString::fromUtf8([text UTF8String]); + int key = 0; + if ([text isEqualToString:@"\n"]) + key = (int)Qt::Key_Return; + + // Send key event to window system interface + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyPress, key, Qt::NoModifier, string, false, int(string.length())); + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyRelease, key, Qt::NoModifier, string, false, int(string.length())); +} + +- (void)deleteBackward +{ + // Send key event to window system interface + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier); + QWindowSystemInterface::handleKeyEvent( + 0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier); +} + +@end + +@implementation UIView (QIOS) + +- (QWindow *)qwindow +{ + if ([self isKindOfClass:[EAGLView class]]) + return static_cast<EAGLView *>(self)->m_qioswindow->window(); + return nil; +} + +@end + +QT_BEGIN_NAMESPACE + +QIOSWindow::QIOSWindow(QWindow *window) + : QPlatformWindow(window) + , m_view([[EAGLView alloc] initWithQIOSWindow:this]) + , m_touchId(0) + , m_requestedGeometry(QPlatformWindow::geometry()) + , m_windowLevel(0) + , m_devicePixelRatio(1.0) +{ + setParent(parent()); + setWindowState(window->windowState()); + + // Retina support: get screen scale factor and set it in the content view. + // This will make framebufferObject() create a 2x frame buffer on retina + // displays. Also set m_devicePixelRatio which is used for scaling the + // paint device. + if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES) { + m_devicePixelRatio = [[UIScreen mainScreen] scale]; + [m_view setContentScaleFactor: m_devicePixelRatio]; + } +} + +QIOSWindow::~QIOSWindow() +{ + [m_view removeFromSuperview]; + [m_view release]; +} + +bool QIOSWindow::blockedByModal() +{ + QWindow *modalWindow = QGuiApplication::modalWindow(); + return modalWindow && modalWindow != window(); +} + +void QIOSWindow::setVisible(bool visible) +{ + QPlatformWindow::setVisible(visible); + m_view.hidden = !visible; + + if (!isQtApplication()) + return; + + // Since iOS doesn't do window management the way a Qt application + // expects, we need to raise and activate windows ourselves: + if (visible) + updateWindowLevel(); + + if (blockedByModal()) { + if (visible) + raise(); + return; + } + + if (visible) { + requestActivateWindow(); + } else { + // Activate top-most visible QWindow: + NSArray *subviews = rootViewController().view.subviews; + for (int i = int(subviews.count) - 1; i >= 0; --i) { + UIView *view = [subviews objectAtIndex:i]; + if (!view.hidden) { + if (QWindow *window = view.qwindow) { + static_cast<QIOSWindow *>(window->handle())->requestActivateWindow(); + break; + } + } + } + } +} + +void QIOSWindow::setGeometry(const QRect &rect) +{ + // If the window is in fullscreen, just bookkeep the requested + // geometry in case the window goes into Qt::WindowNoState later: + m_requestedGeometry = rect; + if (window()->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) + return; + + // Since we don't support transformations on the UIView, we can set the frame + // directly and let UIKit deal with translating that into bounds and center. + // Changing the size of the view will end up in a call to -[EAGLView layoutSubviews] + // which will update QWindowSystemInterface with the new size. + m_view.frame = toCGRect(rect); +} + +void QIOSWindow::setWindowState(Qt::WindowState state) +{ + // FIXME: Figure out where or how we should disable/enable the statusbar. + // Perhaps setting QWindow to maximized should also mean that we'll show + // the statusbar, and vice versa for fullscreen? + + switch (state) { + case Qt::WindowMaximized: + case Qt::WindowFullScreen: { + // Since UIScreen does not take orientation into account when + // reporting geometry, we need to look at the top view instead: + CGSize fullscreenSize = m_view.window.rootViewController.view.bounds.size; + m_view.frame = CGRectMake(0, 0, fullscreenSize.width, fullscreenSize.height); + m_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + break; } + default: + m_view.frame = toCGRect(m_requestedGeometry); + m_view.autoresizingMask = UIViewAutoresizingNone; + break; + } +} + +void QIOSWindow::setParent(const QPlatformWindow *parentWindow) +{ + if (parentWindow) { + UIView *parentView = reinterpret_cast<UIView *>(parentWindow->winId()); + [parentView addSubview:m_view]; + } else if (isQtApplication()) { + [rootViewController().view addSubview:m_view]; + } +} + +void QIOSWindow::requestActivateWindow() +{ + // Note that several windows can be active at the same time if they exist in the same + // hierarchy (transient children). But only one window can be QGuiApplication::focusWindow(). + // Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window: + if (blockedByModal()) + return; + + raise(); + QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); + static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view); + QPlatformWindow::requestActivateWindow(); +} + +void QIOSWindow::raiseOrLower(bool raise) +{ + // Re-insert m_view at the correct index among its sibling views + // (QWindows) according to their current m_windowLevel: + if (!isQtApplication()) + return; + + NSArray *subviews = m_view.superview.subviews; + if (subviews.count == 1) + return; + + for (int i = int(subviews.count) - 1; i >= 0; --i) { + UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]); + if (view.hidden || view == m_view) + continue; + int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel; + if (m_windowLevel > level || (raise && m_windowLevel == level)) { + [m_view.superview insertSubview:m_view aboveSubview:view]; + return; + } + } + [m_view.superview insertSubview:m_view atIndex:0]; +} + +void QIOSWindow::updateWindowLevel() +{ + Qt::WindowType type = static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask)); + + if (type == Qt::ToolTip) + m_windowLevel = 120; + else if (window()->flags() & Qt::WindowStaysOnTopHint) + m_windowLevel = 100; + else if (window()->isModal()) + m_windowLevel = 30; + else if (type & Qt::Popup & ~Qt::Window) + m_windowLevel = 20; + else if (type == Qt::Tool) + m_windowLevel = 10; + else + m_windowLevel = 0; + + // A window should be in at least the same m_windowLevel as its parent: + QWindow *transientParent = window()->transientParent(); + QIOSWindow *transientParentWindow = transientParent ? static_cast<QIOSWindow *>(transientParent->handle()) : 0; + if (transientParentWindow) + m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel); +} + +void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation) +{ + // Keep the status bar in sync with content orientation. This will ensure + // that the task bar (and associated gestures) are aligned correctly: + UIDeviceOrientation uiOrientation = fromQtScreenOrientation(orientation); + [[UIApplication sharedApplication] setStatusBarOrientation:uiOrientation animated:NO]; +} + +qreal QIOSWindow::devicePixelRatio() const +{ + return m_devicePixelRatio; +} + +int QIOSWindow::effectiveWidth() const +{ + return geometry().width() * m_devicePixelRatio; +} + +int QIOSWindow::effectiveHeight() const +{ + return geometry().height() * m_devicePixelRatio; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm new file mode 100644 index 0000000000..10c83f4b18 --- /dev/null +++ b/src/plugins/platforms/ios/qtmain.mm @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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" +#include "qiosviewcontroller.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 +{ + self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease]; + +#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 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..cbcb272217 --- /dev/null +++ b/src/plugins/platforms/ios/qtmain.pro @@ -0,0 +1,8 @@ +TARGET = qiosmain + +PLUGIN_TYPE = platforms +load(qt_plugin) + +QT += gui-private + +OBJECTIVE_SOURCES = qtmain.mm diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 173757568f..a60a3626fa 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -6,7 +6,10 @@ contains(QT_CONFIG, xcb) { SUBDIRS += xcb } -mac:!ios: SUBDIRS += cocoa +mac { + ios: SUBDIRS += ios + else: SUBDIRS += cocoa +} win32: SUBDIRS += windows diff --git a/src/printsupport/dialogs/dialogs.pri b/src/printsupport/dialogs/dialogs.pri index 9db975e202..9659046f60 100644 --- a/src/printsupport/dialogs/dialogs.pri +++ b/src/printsupport/dialogs/dialogs.pri @@ -8,7 +8,7 @@ HEADERS += \ dialogs/qprintdialog.h \ dialogs/qprintpreviewdialog.h -mac { +mac:!ios { OBJECTIVE_SOURCES += dialogs/qpagesetupdialog_mac.mm \ dialogs/qprintdialog_mac.mm LIBS += -framework Cocoa diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index f9f21c6a8f..ef8ffa570b 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -82,7 +82,7 @@ #include <time.h> #endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) #include <IOKit/pwr_mgt/IOPMLib.h> #endif @@ -2078,7 +2078,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) int callgrindChildExitCode = 0; #endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) bool macNeedsActivate = qApp && (qstrcmp(qApp->metaObject()->className(), "QApplication") == 0); IOPMAssertionID powerID; #endif @@ -2093,7 +2093,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX); #endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) if (macNeedsActivate) { CFStringRef reasonForActivity= CFSTR("No Display Sleep"); IOReturn ok = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, reasonForActivity, &powerID); @@ -2146,7 +2146,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) } QTestLog::stopLogging(); -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) if (macNeedsActivate) { IOPMAssertionRelease(powerID); } @@ -2163,7 +2163,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) QSignalDumper::endDump(); -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) if (macNeedsActivate) { IOPMAssertionRelease(powerID); } diff --git a/src/widgets/kernel/mac.pri b/src/widgets/kernel/mac.pri index 5474a41f15..4c507ae80e 100644 --- a/src/widgets/kernel/mac.pri +++ b/src/widgets/kernel/mac.pri @@ -1,4 +1,4 @@ -!x11::mac { +!x11:mac:!ios { LIBS_PRIVATE += -framework Carbon -framework Cocoa -lz *-mwerks:INCLUDEPATH += compat } diff --git a/src/widgets/styles/qfusionstyle_p_p.h b/src/widgets/styles/qfusionstyle_p_p.h index d3f2ff5f40..58595fe889 100644 --- a/src/widgets/styles/qfusionstyle_p_p.h +++ b/src/widgets/styles/qfusionstyle_p_p.h @@ -88,9 +88,9 @@ public: // On mac we want a standard blue color used when the system palette is used bool isMacSystemPalette(const QPalette &pal) const { Q_UNUSED(pal); -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette(); - if (themePalette->color(QPalette::Normal, QPalette::Highlight) == + if (themePalette && themePalette->color(QPalette::Normal, QPalette::Highlight) == pal.color(QPalette::Normal, QPalette::Highlight) && themePalette->color(QPalette::Normal, QPalette::HighlightedText) == pal.color(QPalette::Normal, QPalette::HighlightedText)) diff --git a/src/widgets/styles/qstyleoption.cpp b/src/widgets/styles/qstyleoption.cpp index 01e51d594d..eff6837c5a 100644 --- a/src/widgets/styles/qstyleoption.cpp +++ b/src/widgets/styles/qstyleoption.cpp @@ -206,7 +206,7 @@ void QStyleOption::init(const QWidget *widget) if (!(state & QStyle::State_Active) && !qt_mac_can_clickThrough(widget)) state &= ~QStyle::State_Enabled; #endif -#ifdef Q_OS_MAC +#if defined(Q_OS_MAC) && !defined(Q_OS_IOS) switch (QMacStyle::widgetSizePolicy(widget)) { case QMacStyle::SizeSmall: state |= QStyle::State_Small; |