diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ea57c49..d58e514 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,6 +10,195 @@ permissions:
contents: write
packages: write
jobs:
+ build-ios:
+ name: Build iOS
+ runs-on: macos-15
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: '16.4'
+
+ - name: Configure iOS
+ run: |
+ cmake -S . -B build -G Xcode --toolchain cmake/ios-toolchain.cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5
+
+ - name: Build iOS
+ run: cmake --build build --config Release --target vanilla
+
+ - name: Create unsigned IPA
+ run: |
+ APP=build/bin/Release/Vanilla.app
+ test -d "$APP"
+ mkdir -p Payload
+ cp -R "$APP" Payload/
+ zip -9rX vanilla-ios.ipa Payload
+
+ - name: Upload iOS Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ios
+ path: vanilla-ios.ipa
+
+ - name: Upload Continuous Release
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'vanilla-wiiu/vanilla' }}
+ shell: bash
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ curl -fLOSs --retry 2 --retry-delay 60 https://github.com/probonopd/uploadtool/raw/master/upload.sh
+ bash upload.sh vanilla-ios.ipa
+
+ build-macos:
+ name: Build macOS
+ runs-on: macos-15
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: '16.4'
+
+ - name: Configure
+ run: |
+ cmake -S . -B build \
+ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \
+ -DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \
+ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
+ -DVANILLA_BUILD_PIPE=OFF \
+ -DVANILLA_BUILD_VENDORED=ON
+
+ - name: Build
+ run: cmake --build build --target vanilla
+
+ - name: Package
+ run: |
+ ditto -c -k --keepParent "$GITHUB_WORKSPACE/build/bin/Vanilla.app" vanilla-macos-universal-unsigned.zip
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: macos universal unsigned
+ path: vanilla-macos-universal-unsigned.zip
+ if-no-files-found: error
+
+ sign-macos:
+ name: Sign and notarize macOS
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'vanilla-wiiu/vanilla' }}
+ needs: build-macos
+ runs-on: macos-15
+ environment: macos-release
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: '16.4'
+
+ - name: Download unsigned macOS artifact
+ uses: actions/download-artifact@v4
+ with:
+ name: macos universal unsigned
+ path: incoming
+
+ - name: Unpack
+ run: |
+ mkdir -p signing
+ ditto -x -k incoming/vanilla-macos-universal-unsigned.zip signing
+
+ - name: Import signing certificate
+ env:
+ MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }}
+ MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
+ MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
+ MACOS_NOTARY_KEY_BASE64: ${{ secrets.MACOS_NOTARY_KEY_BASE64 }}
+ MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
+ run: |
+ certificate_path="$RUNNER_TEMP/developer-id.p12"
+ keychain_path="$RUNNER_TEMP/vanilla-signing.keychain-db"
+ notary_key_path="$RUNNER_TEMP/AuthKey_${MACOS_NOTARY_KEY_ID}.p8"
+
+ printf '%s' "$MACOS_CERTIFICATE_BASE64" | base64 --decode -o "$certificate_path"
+ printf '%s' "$MACOS_NOTARY_KEY_BASE64" | base64 --decode -o "$notary_key_path"
+
+ security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path"
+ security set-keychain-settings -lut 21600 "$keychain_path"
+ security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path"
+ security import "$certificate_path" -P "$MACOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$keychain_path"
+ security set-key-partition-list -S apple-tool:,apple: -k "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path"
+ security list-keychains -d user -s "$keychain_path"
+
+ signing_identity="$(security find-identity -v -p codesigning "$keychain_path" | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' | head -n 1)"
+
+ echo "MACOS_NOTARY_KEY_PATH=$notary_key_path" >> "$GITHUB_ENV"
+ echo "MACOS_SIGNING_IDENTITY=$signing_identity" >> "$GITHUB_ENV"
+
+ - name: Sign
+ run: |
+ codesign \
+ --force \
+ --timestamp \
+ --options runtime \
+ --entitlements "$GITHUB_WORKSPACE/gui/res/Vanilla.entitlements" \
+ --sign "$MACOS_SIGNING_IDENTITY" \
+ "$GITHUB_WORKSPACE/signing/Vanilla.app"
+ codesign --verify --deep --strict --verbose=2 "$GITHUB_WORKSPACE/signing/Vanilla.app"
+
+ - name: Notarize and staple app
+ env:
+ MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
+ MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
+ run: |
+ APP="$GITHUB_WORKSPACE/signing/Vanilla.app"
+ ARCHIVE="$RUNNER_TEMP/Vanilla-notary.zip"
+
+ ditto -c -k --keepParent "$APP" "$ARCHIVE"
+ xcrun notarytool submit "$ARCHIVE" \
+ --key "$MACOS_NOTARY_KEY_PATH" \
+ --key-id "$MACOS_NOTARY_KEY_ID" \
+ --issuer "$MACOS_NOTARY_ISSUER_ID" \
+ --wait
+
+ xcrun stapler staple "$APP"
+ xcrun stapler validate "$APP"
+ spctl --assess --type execute --verbose=4 "$APP"
+
+ - name: Package
+ run: ditto -c -k --keepParent signing/Vanilla.app vanilla-macos-universal.zip
+
+ - name: Remove signing credentials
+ if: ${{ always() }}
+ env:
+ MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
+ run: |
+ security delete-keychain "$RUNNER_TEMP/vanilla-signing.keychain-db" || true
+ rm -f "$RUNNER_TEMP/developer-id.p12"
+ if [ -n "$MACOS_NOTARY_KEY_ID" ]; then
+ rm -f "$RUNNER_TEMP/AuthKey_${MACOS_NOTARY_KEY_ID}.p8"
+ fi
+
+ - name: Upload signed macOS artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: macOS signed and notarized
+ path: vanilla-macos-universal.zip
+ if-no-files-found: error
+
+ - name: Upload signed continuous release
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'vanilla-wiiu/vanilla' }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ curl -fLOSs --retry 2 --retry-delay 60 https://github.com/probonopd/uploadtool/raw/master/upload.sh
+ bash upload.sh vanilla-macos-universal.zip
+
build:
strategy:
fail-fast: false
@@ -27,9 +216,6 @@ jobs:
- os: android
arch: universal
artifact: vanilla-android-universal.apk
- - os: macos
- arch: universal
- artifact: vanilla-macos-universal.zip
- os: raspberrypi0w
arch: armv6l
artifact: vanilla-raspberrypi0w-image.zip
@@ -95,8 +281,8 @@ jobs:
run: |
tar czf ${{ matrix.platform.artifact }} -C "${{ github.workspace }}/build" .
- - name: Archive (Windows/macOS/Raspberry Pi/Nintendo Switch)
- if: ${{ matrix.platform.os == 'windows' || matrix.platform.os == 'macos' || matrix.platform.os == 'raspberrypi0w' || matrix.platform.os == 'raspberrypi64' || matrix.platform.os == 'nintendoswitch' || matrix.platform.os == 'orangepi_zero3' || matrix.platform.os == 'orangepi_zero2w' }}
+ - name: Archive (Windows/Raspberry Pi/Nintendo Switch)
+ if: ${{ matrix.platform.os == 'windows' || matrix.platform.os == 'raspberrypi0w' || matrix.platform.os == 'raspberrypi64' || matrix.platform.os == 'nintendoswitch' || matrix.platform.os == 'orangepi_zero3' || matrix.platform.os == 'orangepi_zero2w' }}
run: |
cd build
zip -r ../${{ matrix.platform.artifact }} .
@@ -130,4 +316,3 @@ jobs:
run: |
curl -fLOSs --retry 2 --retry-delay 60 https://github.com/probonopd/uploadtool/raw/master/upload.sh
bash upload.sh ${{ matrix.platform.artifact }}
-
diff --git a/.gitignore b/.gitignore
index cef5039..957ed6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
build/
+CMakeUserPresets.json
.vscode/
.directory
.cache/
@@ -12,3 +13,6 @@ buildpi/
.idea/
android/local.properties
android/app/src/main/assets
+
+# macOS
+.DS_Store
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f7b49f..449be7b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,7 +13,13 @@ if(UNIX AND NOT APPLE AND NOT ANDROID)
set(LINUX TRUE)
endif()
-if(ANDROID OR MSVC)
+if(APPLE)
+ # FFmpeg's configure step expects both compiler drivers even though Vanilla
+ # itself is written in C.
+ enable_language(CXX)
+endif()
+
+if(ANDROID OR MSVC OR IOS)
set(vendored_default TRUE)
else()
set(vendored_default FALSE)
diff --git a/README.md b/README.md
index 9272dd3..443c8d5 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ An Arch User Repository (AUR) package called `vanilla-wiiu-git` is available for
- [Raspberry Pi](https://github.com/vanilla-wiiu/vanilla/wiki/Single%E2%80%90Board-Computers) (requires [external Wi-Fi adapter](https://github.com/vanilla-wiiu/vanilla/wiki/Linux-Setup-Guide#raspberry-pi))
- [Orange Pi](https://github.com/vanilla-wiiu/vanilla/wiki/Single%E2%80%90Board-Computers) (requires [external Wi-Fi adapter](https://github.com/vanilla-wiiu/vanilla/wiki/Linux-Setup-Guide#raspberry-pi))
- macOS (currently frontend only)
-- *iOS* - Coming soon
+- [iOS](https://github.com/vanilla-wiiu/vanilla/wiki/iOS) (currently frontend only)
## What Wi-Fi adapter should I use?
diff --git a/cmake/ios-toolchain.cmake b/cmake/ios-toolchain.cmake
new file mode 100644
index 0000000..ef442c4
--- /dev/null
+++ b/cmake/ios-toolchain.cmake
@@ -0,0 +1,50 @@
+set(CMAKE_SYSTEM_NAME iOS)
+
+if(NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ message(FATAL_ERROR "iOS build requires Xcode generator")
+endif()
+
+set(CMAKE_OSX_SYSROOT iphoneos CACHE STRING "iOS SDK")
+set(CMAKE_OSX_ARCHITECTURES arm64 CACHE STRING "iOS architectures")
+set(CMAKE_XCODE_GENERATE_SCHEME ON CACHE BOOL "Generate an Xcode scheme")
+
+# Determine Xcode version to determine iOS deployment target
+if(NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
+ execute_process(
+ COMMAND xcodebuild -version
+ RESULT_VARIABLE _vanilla_xcode_version_result
+ OUTPUT_VARIABLE _vanilla_xcode_version_output
+ ERROR_VARIABLE _vanilla_xcode_version_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT _vanilla_xcode_version_result EQUAL 0)
+ message(FATAL_ERROR "Could not determine the selected Xcode version: ${_vanilla_xcode_version_error}")
+ endif()
+
+ string(REGEX MATCH "Xcode ([0-9]+(\\.[0-9]+)*)" _vanilla_xcode_version_match "${_vanilla_xcode_version_output}")
+ if(NOT CMAKE_MATCH_1)
+ message(FATAL_ERROR "Could not parse the selected Xcode version from: ${_vanilla_xcode_version_output}")
+ endif()
+
+ if(CMAKE_MATCH_1 VERSION_GREATER_EQUAL 26.0)
+ set(_vanilla_ios_deployment_target 15.0)
+ else()
+ set(_vanilla_ios_deployment_target 12.0)
+ endif()
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "${_vanilla_ios_deployment_target}" CACHE STRING "Minimum iOS deployment version")
+endif()
+
+if(IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+ set(VANILLA_IOS_SDK_PATH "${CMAKE_OSX_SYSROOT}")
+else()
+ execute_process(
+ COMMAND xcrun --sdk "${CMAKE_OSX_SYSROOT}" --show-sdk-path
+ RESULT_VARIABLE _vanilla_ios_sdk_result
+ OUTPUT_VARIABLE VANILLA_IOS_SDK_PATH
+ ERROR_VARIABLE _vanilla_ios_sdk_error
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ if(NOT _vanilla_ios_sdk_result EQUAL 0 OR NOT IS_DIRECTORY "${VANILLA_IOS_SDK_PATH}")
+ message(FATAL_ERROR "Could not resolve iOS SDK '${CMAKE_OSX_SYSROOT}': ${_vanilla_ios_sdk_error}")
+ endif()
+endif()
diff --git a/docker/macos/Dockerfile b/docker/macos/Dockerfile
deleted file mode 100644
index ec97a34..0000000
--- a/docker/macos/Dockerfile
+++ /dev/null
@@ -1,33 +0,0 @@
-FROM docker.io/ubuntu:24.04@sha256:33ceb71981b602c1a7443a53469e4dba065f7503eab3078a2d7a57a2ab987517
-
-ENV DEBIAN_FRONTEND=noninteractive
-ENV TZ=Etc/UTC
-
-RUN apt -y update && \
- apt -y install build-essential git clang patch python3 cmake patch libssl-dev libxml2-dev liblzma-dev cpio libbz2-dev zlib1g-dev bash wget nasm && \
- apt-get clean && \
- apt-get autoremove --yes && \
- rm -rf /var/lib/{apt,dpkg,cache,log}/
-
-RUN git clone https://github.com/tpoechtrager/osxcross
-
-RUN wget -c https://archive.org/download/xcode-clt/Command_Line_Tools_for_Xcode_16.4.dmg
-
-RUN /osxcross/tools/gen_sdk_package_tools_dmg.sh /Command_Line_Tools_for_Xcode_*.dmg
-
-RUN rm /Command_Line_Tools_for_Xcode_*.dmg
-
-RUN mv /osxcross/*.sdk.tar.xz /osxcross/tarballs/
-
-RUN SDK_VERSION=14 UNATTENDED=1 /osxcross/build.sh
-RUN /osxcross/build_compiler_rt.sh
-
-# Fix linker in osxcross cmake (https://github.com/tpoechtrager/osxcross/issues/454)
-RUN echo 'set(CMAKE_LINKER "${OSXCROSS_TARGET_DIR}/bin/${OSXCROSS_HOST}-ld" CACHE FILEPATH "ld")' >> /osxcross/target/toolchain.cmake
-RUN echo 'set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=${CMAKE_LINKER}")' >> /osxcross/target/toolchain.cmake
-RUN echo 'set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=${CMAKE_LINKER}")' >> /osxcross/target/toolchain.cmake
-RUN echo 'set(CMAKE_MODULE_LINKER_FLAGS "-fuse-ld=${CMAKE_LINKER}")' >> /osxcross/target/toolchain.cmake
-
-ENV PATH=/osxcross/target/bin:$PATH
-
-ENTRYPOINT [ "/vanilla/docker/macos/build.sh" ]
diff --git a/docker/macos/build.sh b/docker/macos/build.sh
deleted file mode 100755
index 154b346..0000000
--- a/docker/macos/build.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-
-set -e
-
-cmake \
- -S /vanilla \
- -B /build \
- -DVANILLA_BUILD_VENDORED=ON \
- -DCMAKE_BUILD_TYPE=RelWithDebInfo \
- -DCMAKE_TOOLCHAIN_FILE=/vanilla/docker/macos/toolchain.cmake
-
-cmake --build /build --parallel
-mv /build/bin/*.app /install/
diff --git a/docker/macos/toolchain.cmake b/docker/macos/toolchain.cmake
deleted file mode 100644
index 1bcd371..0000000
--- a/docker/macos/toolchain.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-set(CMAKE_CROSSCOMPILING ON)
-
-set(CMAKE_SYSTEM_NAME "Darwin")
-
-set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
-set(CMAKE_OSX_SYSROOT "/osxcross/target/SDK/MacOSX14.sdk")
-set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
-
-set(CMAKE_INSTALL_NAME_TOOL "xcrun install_name_tool")
-set(CMAKE_C_COMPILER clang)
-set(CMAKE_CXX_COMPILER clang)
-execute_process(COMMAND xcrun -find ar OUTPUT_VARIABLE CMAKE_AR OUTPUT_STRIP_TRAILING_WHITESPACE)
-execute_process(COMMAND xcrun -find nm OUTPUT_VARIABLE CMAKE_NM OUTPUT_STRIP_TRAILING_WHITESPACE)
-execute_process(COMMAND xcrun -find ranlib OUTPUT_VARIABLE CMAKE_RANLIB OUTPUT_STRIP_TRAILING_WHITESPACE)
-execute_process(COMMAND xcrun -find strip OUTPUT_VARIABLE CMAKE_STRIP OUTPUT_STRIP_TRAILING_WHITESPACE)
-
-execute_process(COMMAND xcrun -find ld OUTPUT_VARIABLE CMAKE_LINKER OUTPUT_STRIP_TRAILING_WHITESPACE)
-set(CMAKE_C_FLAGS "--target=darwin -fuse-ld=${CMAKE_LINKER}")
-set(CMAKE_CXX_FLAGS "--target=darwin -fuse-ld=${CMAKE_LINKER}")
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index 199b844..27fee24 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -69,6 +69,27 @@ function(compile_ffmpeg _target_name _system_name _system_processor)
)
elseif(MSVC)
set(FFMPEG_TARGET_OS "win32")
+ elseif(IOS)
+ set(FFMPEG_TARGET_OS "darwin")
+ set(_ios_version_flag "-mios-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
+ set(FFMPEG_LDFLAGS "${CMAKE_C_FLAGS} -arch ${_system_processor} ${_ios_version_flag} -isysroot ${VANILLA_IOS_SDK_PATH}")
+ set(FFMPEG_CFLAGS "${CMAKE_C_FLAGS} -arch ${_system_processor} ${_ios_version_flag} -isysroot ${VANILLA_IOS_SDK_PATH} -w")
+ list(APPEND FFMPEG_CONFIGURE_ARGS
+ --disable-asm
+ --disable-avdevice
+ --disable-indevs
+ --disable-outdevs
+ --nm=${CMAKE_NM}
+ --ar=${CMAKE_AR}
+ --ranlib=${CMAKE_RANLIB}
+ --cc=${CMAKE_C_COMPILER}
+ --cxx=${CMAKE_CXX_COMPILER}
+ --ld=${CMAKE_C_COMPILER}
+ --strip=${CMAKE_STRIP}
+ --host-cc=clang
+ --host-ld=clang
+ --enable-videotoolbox
+ )
elseif(APPLE)
set(FFMPEG_TARGET_OS "darwin")
set(FFMPEG_LDFLAGS "${FFMPEG_LDFLAGS} -arch ${_system_processor} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -L${CMAKE_OSX_SYSROOT}/usr/lib -lSystem")
@@ -220,16 +241,23 @@ if (VANILLA_BUILD_VENDORED)
set(LIBXML2_WITH_ICONV OFF)
set(LIBXML2_WITH_PROGRAMS OFF)
set(LIBXML2_WITH_TESTS OFF)
- FetchContent_Declare(
- libxml2
- GIT_REPOSITORY https://gitlab.gnome.org/GNOME/libxml2.git
- GIT_TAG v2.13.5
- EXCLUDE_FROM_ALL
- )
- FetchContent_MakeAvailable(SDL2 SDL2_ttf SDL2_image libxml2)
+ if (NOT IOS)
+ FetchContent_Declare(
+ libxml2
+ GIT_REPOSITORY https://gitlab.gnome.org/GNOME/libxml2.git
+ GIT_TAG v2.13.5
+ EXCLUDE_FROM_ALL
+ )
+ FetchContent_MakeAvailable(SDL2 SDL2_ttf SDL2_image libxml2)
+ else()
+ FetchContent_MakeAvailable(SDL2 SDL2_ttf SDL2_image)
+ endif()
- if (APPLE)
+ if (IOS)
+ # Compile FFmpeg for arm64
+ compile_ffmpeg("FFmpeg" "${CMAKE_SYSTEM_NAME}" "${CMAKE_OSX_ARCHITECTURES}")
+ elseif (APPLE)
# Compile FFmpeg for both x86_64 and arm64
foreach (_arch ${CMAKE_OSX_ARCHITECTURES})
compile_ffmpeg("FFmpeg_${_arch}" "${CMAKE_SYSTEM_NAME}" "${_arch}")
@@ -359,10 +387,105 @@ if (VANILLA_BUILD_USE_POLKIT)
)
endif()
+if(APPLE)
+ if(IOS)
+ set(VANILLA_PLATFORM_INFO_PLIST_ENTRIES [=[
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ arm64
+ wifi
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIStatusBarHidden
+
+ UIViewControllerBasedStatusBarAppearance
+
+ UIRequiresFullScreen
+ ]=])
+ else()
+ set(VANILLA_PLATFORM_INFO_PLIST_ENTRIES [=[
+ LSMinimumSystemVersion
+ ${CMAKE_OSX_DEPLOYMENT_TARGET}
+ NSHighResolutionCapable
+ ]=])
+ endif()
+
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/res/Info.plist.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/Vanilla.Info.plist.in"
+ @ONLY
+ )
+endif()
+
# Declare executable
add_library(vanillagui STATIC ${VANILLA_GUI_SRC})
if (ANDROID)
add_library(vanilla SHARED main.c)
+elseif(IOS)
+ add_executable(vanilla MACOSX_BUNDLE
+ main.c
+ )
+ set_target_properties(vanilla PROPERTIES
+ XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.mattkc.vanilla"
+ XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
+ XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${CMAKE_OSX_DEPLOYMENT_TARGET}"
+ )
+
+ set_target_properties(vanilla PROPERTIES
+ XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
+ )
+
+ # Compile storyboard
+ add_custom_command(
+ TARGET vanilla POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "$/LaunchScreen.storyboardc"
+ COMMAND xcrun ibtool --compile "$/LaunchScreen.storyboardc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/LaunchScreen.storyboard"
+ --target-device iphone --target-device ipad
+ --minimum-deployment-target "${CMAKE_OSX_DEPLOYMENT_TARGET}"
+ VERBATIM
+ )
+
+ # Compile app icon with actool
+ if(XCODE_VERSION VERSION_GREATER_EQUAL 26.0
+ AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 15.0)
+ set(_vanilla_icon_input "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/AppIcon.icon")
+ set(_vanilla_icon_extra_args --include-all-app-icons)
+ else()
+ set(_vanilla_icon_input "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/Assets.xcassets")
+ set(_vanilla_icon_extra_args)
+ endif()
+
+ add_custom_command(
+ TARGET vanilla POST_BUILD
+ COMMAND xcrun actool
+ --compile "$"
+ --enable-on-demand-resources NO
+ --app-icon AppIcon
+ --platform iphoneos
+ ${_vanilla_icon_extra_args}
+ --minimum-deployment-target "${CMAKE_OSX_DEPLOYMENT_TARGET}"
+ --target-device iphone --target-device ipad
+ --output-partial-info-plist "${CMAKE_CURRENT_BINARY_DIR}/AssetCatalog-Info.plist"
+ "${_vanilla_icon_input}"
+ COMMAND /usr/libexec/PlistBuddy -x
+ -c "Merge ${CMAKE_CURRENT_BINARY_DIR}/AssetCatalog-Info.plist"
+ "$/Info.plist"
+ VERBATIM
+ )
else()
add_executable(vanilla MACOSX_BUNDLE main.c)
endif()
@@ -377,6 +500,11 @@ if (APPLE)
# Set bundle name to be more user-friendly
set_target_properties(vanilla PROPERTIES
OUTPUT_NAME Vanilla
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Vanilla.Info.plist.in"
+ MACOSX_BUNDLE_GUI_IDENTIFIER "com.mattkc.vanilla"
+ MACOSX_BUNDLE_BUNDLE_NAME "Vanilla"
+ MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
+ MACOSX_BUNDLE_BUNDLE_VERSION "1"
)
else()
# Ensure executable is installed
@@ -391,7 +519,6 @@ if (NOT VANILLA_BUILD_VENDORED)
endif()
target_link_libraries(vanillagui PRIVATE
- SDL2::SDL2main
${_sdl_lib}
SDL2_ttf
SDL2_image
@@ -401,7 +528,6 @@ target_link_libraries(vanillagui PRIVATE
if (ANDROID)
target_link_libraries(vanillagui PRIVATE
- SDL2main
android
GLESv2
log
@@ -409,6 +535,9 @@ if (ANDROID)
)
endif()
+# SDL owns the platform entry-point shim used by main.c.
+target_link_libraries(vanilla PRIVATE SDL2::SDL2main ${_sdl_lib})
+
# Find FFmpeg
if (NOT VANILLA_BUILD_VENDORED)
find_package(FFmpeg REQUIRED COMPONENTS avformat avcodec avutil swscale)
@@ -431,7 +560,24 @@ if (LINUX)
endif()
if (APPLE)
- target_link_libraries(vanillagui PRIVATE "-framework VideoToolbox" "-framework CoreMedia" iconv)
+ target_compile_definitions(vanillagui PRIVATE VANILLA_VIDEOTOOLBOX_AVAILABLE)
+ target_link_libraries(vanillagui PRIVATE
+ "-framework CoreFoundation"
+ "-framework CoreMedia"
+ "-framework CoreVideo"
+ "-framework Foundation"
+ "-framework Metal"
+ "-framework QuartzCore"
+ "-framework VideoToolbox"
+ iconv
+ )
+endif()
+
+if (IOS)
+ target_link_libraries(vanillagui PRIVATE
+ "-framework ImageIO"
+ "-framework MobileCoreServices"
+ )
endif()
if (VANILLA_BUILD_PIPE)
@@ -484,7 +630,12 @@ endif()
# Find libxml2 (used for storing/parsing user config)
if (VANILLA_BUILD_VENDORED)
- target_link_libraries(vanillagui PRIVATE LibXml2::LibXml2)
+ if (IOS)
+ target_link_libraries(vanillagui PRIVATE "-lxml2")
+ target_include_directories(vanillagui PRIVATE "${VANILLA_IOS_SDK_PATH}/usr/include/libxml2")
+ else()
+ target_link_libraries(vanillagui PRIVATE LibXml2::LibXml2)
+ endif()
else()
find_package(LibXML2 REQUIRED)
target_link_libraries(vanillagui PRIVATE ${LibXML2_LIBRARIES})
@@ -506,8 +657,20 @@ target_include_directories(vanillagui PRIVATE
)
# Install assets
-if(APPLE)
- # Put assets in correct place relative to build
+if(ANDROID)
+ # Put assets in correct place relative to build
+ add_custom_command(
+ TARGET vanilla POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/assets" "${CMAKE_CURRENT_SOURCE_DIR}/../android/app/src/main/assets"
+ )
+elseif(IOS)
+ # Put assets inside the iOS app bundle
+ add_custom_command(
+ TARGET vanilla POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/assets" "$/assets"
+ )
+elseif(APPLE)
+ # Put assets in correct place relative to build
add_custom_command(
TARGET vanilla POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${CMAKE_CURRENT_SOURCE_DIR}/assets" "$/../Resources/assets"
diff --git a/gui/main.c b/gui/main.c
index 83fffbe..1571225 100644
--- a/gui/main.c
+++ b/gui/main.c
@@ -1,4 +1,5 @@
#include
+#include
#include
#include
#include
@@ -9,18 +10,22 @@
#include "ui/ui.h"
#include "ui/ui_sdl.h"
+#if defined(__APPLE__)
+#include
+#if TARGET_OS_IOS
+// SDL_main will be linked incorrectly on iOS unless we include this
+#include
+#endif
+#endif
+
#define SCREEN_WIDTH 854
#define SCREEN_HEIGHT 480
-#if !defined(ANDROID) && !defined(_WIN32)
-#define SDL_main main
-#endif
-
#include "pipemgmt.h"
-void display_cli_help(const char **argv);
+void display_cli_help(char **argv);
-int SDL_main(int argc, const char **argv)
+int main(int argc, char **argv)
{
int ret = 1;
@@ -126,7 +131,7 @@ exit_config:
return ret;
}
-void display_cli_help(const char **argv) {
+void display_cli_help(char **argv) {
vpilog("Usage: %s [options]\n\n", argv[0]);
vpilog("Options:\n");
vpilog(" -w, --window Run Vanilla in a window (overrides config)\n");
diff --git a/gui/platform.c b/gui/platform.c
index 1a96945..2c6f483 100644
--- a/gui/platform.c
+++ b/gui/platform.c
@@ -1,12 +1,7 @@
#include "platform.h"
-#if defined(ANDROID)
-#include
-#elif defined(_WIN32)
-#include
-#endif
-
#include
+#include
#include
#include "ui/ui_util.h"
@@ -34,15 +29,7 @@ void vpi_get_data_filename(char *out, size_t out_size, const char *filename, con
void vpilog_va(const char *fmt, va_list va)
{
-#if defined(ANDROID)
- __android_log_vprint(ANDROID_LOG_ERROR, "VPI", fmt, va);
-// #elif defined(_WIN32)
-// char buf[4096];
-// vsnprintf(buf, sizeof(buf), fmt, va);
-// MessageBoxA(0, buf, 0, 0);
-#else
- vfprintf(stderr, fmt, va);
-#endif
+ SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, va);
}
void vpilog(const char *fmt, ...)
diff --git a/gui/res/Info.plist.in b/gui/res/Info.plist.in
new file mode 100644
index 0000000..31dbb54
--- /dev/null
+++ b/gui/res/Info.plist.in
@@ -0,0 +1,29 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ ${MACOSX_BUNDLE_BUNDLE_NAME}
+ CFBundleExecutable
+ ${MACOSX_BUNDLE_EXECUTABLE_NAME}
+ CFBundleIdentifier
+ ${MACOSX_BUNDLE_GUI_IDENTIFIER}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${MACOSX_BUNDLE_BUNDLE_NAME}
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ ${MACOSX_BUNDLE_SHORT_VERSION_STRING}
+ CFBundleVersion
+ ${MACOSX_BUNDLE_BUNDLE_VERSION}
+@VANILLA_PLATFORM_INFO_PLIST_ENTRIES@
+ NSLocalNetworkUsageDescription
+ Vanilla needs local network access to connect to your Wii U.
+ NSMicrophoneUsageDescription
+ Vanilla needs microphone access to stream audio to your Wii U.
+
+
diff --git a/gui/res/Vanilla.entitlements b/gui/res/Vanilla.entitlements
new file mode 100644
index 0000000..d459cb2
--- /dev/null
+++ b/gui/res/Vanilla.entitlements
@@ -0,0 +1,8 @@
+
+
+
+
+ com.apple.security.device.audio-input
+
+
+
diff --git a/gui/res/ios/AppIcon.icon/Assets/Vanilla.svg b/gui/res/ios/AppIcon.icon/Assets/Vanilla.svg
new file mode 100644
index 0000000..d996a31
--- /dev/null
+++ b/gui/res/ios/AppIcon.icon/Assets/Vanilla.svg
@@ -0,0 +1,4 @@
+
diff --git a/gui/res/ios/AppIcon.icon/icon.json b/gui/res/ios/AppIcon.icon/icon.json
new file mode 100644
index 0000000..58b780b
--- /dev/null
+++ b/gui/res/ios/AppIcon.icon/icon.json
@@ -0,0 +1,36 @@
+{
+ "fill": {
+ "automatic-gradient": "srgb:0.13333,0.79608,1.00000,1.00000"
+ },
+ "groups": [
+ {
+ "layers": [
+ {
+ "image-name": "Vanilla.svg",
+ "name": "Vanilla",
+ "position": {
+ "scale": 34.5,
+ "translation-in-points": [
+ 0,
+ 0
+ ]
+ }
+ }
+ ],
+ "shadow": {
+ "kind": "neutral",
+ "opacity": 0.5
+ },
+ "translucency": {
+ "enabled": true,
+ "value": 0.5
+ }
+ }
+ ],
+ "supported-platforms": {
+ "circles": [
+ "watchOS"
+ ],
+ "squares": "shared"
+ }
+}
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..089dc45
--- /dev/null
+++ b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x", "filename" : "icon-40.png" },
+ { "idiom" : "iphone", "size" : "20x20", "scale" : "3x", "filename" : "icon-60.png" },
+ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x", "filename" : "icon-58.png" },
+ { "idiom" : "iphone", "size" : "29x29", "scale" : "3x", "filename" : "icon-87.png" },
+ { "idiom" : "iphone", "size" : "40x40", "scale" : "2x", "filename" : "icon-80.png" },
+ { "idiom" : "iphone", "size" : "40x40", "scale" : "3x", "filename" : "icon-120.png" },
+ { "idiom" : "iphone", "size" : "60x60", "scale" : "2x", "filename" : "icon-120.png" },
+ { "idiom" : "iphone", "size" : "60x60", "scale" : "3x", "filename" : "icon-180.png" },
+ { "idiom" : "ipad", "size" : "20x20", "scale" : "1x", "filename" : "icon-20.png" },
+ { "idiom" : "ipad", "size" : "20x20", "scale" : "2x", "filename" : "icon-40.png" },
+ { "idiom" : "ipad", "size" : "29x29", "scale" : "1x", "filename" : "icon-29.png" },
+ { "idiom" : "ipad", "size" : "29x29", "scale" : "2x", "filename" : "icon-58.png" },
+ { "idiom" : "ipad", "size" : "40x40", "scale" : "1x", "filename" : "icon-40.png" },
+ { "idiom" : "ipad", "size" : "40x40", "scale" : "2x", "filename" : "icon-80.png" },
+ { "idiom" : "ipad", "size" : "76x76", "scale" : "1x", "filename" : "icon-76.png" },
+ { "idiom" : "ipad", "size" : "76x76", "scale" : "2x", "filename" : "icon-152.png" },
+ { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x", "filename" : "icon-167.png" },
+ { "idiom" : "ios-marketing", "size" : "1024x1024", "scale" : "1x", "filename" : "icon-1024.png" }
+ ],
+ "info" : { "version" : 1, "author" : "xcode" }
+}
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-1024.png
new file mode 100644
index 0000000..d36f3ee
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-1024.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-120.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-120.png
new file mode 100644
index 0000000..90c3ac6
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-120.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-152.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-152.png
new file mode 100644
index 0000000..385f5e7
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-152.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-167.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-167.png
new file mode 100644
index 0000000..3c40d76
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-167.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-180.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-180.png
new file mode 100644
index 0000000..10cea3a
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-180.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-20.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-20.png
new file mode 100644
index 0000000..093137b
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-20.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-29.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-29.png
new file mode 100644
index 0000000..97d027e
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-29.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-40.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-40.png
new file mode 100644
index 0000000..c626515
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-40.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-58.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-58.png
new file mode 100644
index 0000000..7241456
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-58.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-60.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-60.png
new file mode 100644
index 0000000..2a34d49
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-60.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-76.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-76.png
new file mode 100644
index 0000000..a6be856
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-76.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-80.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-80.png
new file mode 100644
index 0000000..2a4fad4
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-80.png differ
diff --git a/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-87.png b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-87.png
new file mode 100644
index 0000000..26b2b6c
Binary files /dev/null and b/gui/res/ios/Assets.xcassets/AppIcon.appiconset/icon-87.png differ
diff --git a/gui/res/ios/Assets.xcassets/Contents.json b/gui/res/ios/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..0ce4e31
--- /dev/null
+++ b/gui/res/ios/Assets.xcassets/Contents.json
@@ -0,0 +1,3 @@
+{
+ "info" : { "version" : 1, "author" : "xcode" }
+}
diff --git a/gui/res/ios/LaunchScreen.storyboard b/gui/res/ios/LaunchScreen.storyboard
new file mode 100644
index 0000000..a0abceb
--- /dev/null
+++ b/gui/res/ios/LaunchScreen.storyboard
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+