Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
osy authored Aug 23, 2024
2 parents 9f4bc39 + 9beddf5 commit 42eda52
Show file tree
Hide file tree
Showing 68 changed files with 2,504 additions and 256 deletions.
4 changes: 2 additions & 2 deletions Build.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974

MARKETING_VERSION = 4.5.1
CURRENT_PROJECT_VERSION = 96
MARKETING_VERSION = 4.5.3
CURRENT_PROJECT_VERSION = 99

// Codesigning settings defined optionally, see Documentation/iOSDevelopment.md
#include? "CodeSigning.xcconfig"
Expand Down
4 changes: 3 additions & 1 deletion Configuration/UTMAppleConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,13 @@ extension UTMAppleConfiguration {
}
if !ignoringDrives {
vzconfig.storageDevices = try drives.compactMap { drive in
guard let attachment = try drive.vzDiskImage() else {
guard let attachment = try drive.vzDiskImage(useFsWorkAround: system.boot.operatingSystem == .linux) else {
return nil
}
if #available(macOS 13, *), drive.isExternal {
return VZUSBMassStorageDeviceConfiguration(attachment: attachment)
} else if #available(macOS 14, *), drive.isNvme, system.boot.operatingSystem == .linux {
return VZNVMExpressControllerDeviceConfiguration(attachment: attachment)
} else {
return VZVirtioBlockDeviceConfiguration(attachment: attachment)
}
Expand Down
19 changes: 16 additions & 3 deletions Configuration/UTMAppleConfigurationDrive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {
var sizeMib: Int = 0
var isReadOnly: Bool
var isExternal: Bool
var isNvme: Bool
var imageURL: URL?
var imageName: String?

Expand All @@ -36,6 +37,7 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {

private enum CodingKeys: String, CodingKey {
case isReadOnly = "ReadOnly"
case isNvme = "Nvme"
case imageName = "ImageName"
case bookmark = "Bookmark" // legacy only
case identifier = "Identifier"
Expand All @@ -55,12 +57,14 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {
sizeMib = newSize
isReadOnly = false
isExternal = false
isNvme = false
}

init(existingURL url: URL?, isExternal: Bool = false) {
init(existingURL url: URL?, isExternal: Bool = false, isNvme: Bool = false) {
self.imageURL = url
self.isReadOnly = isExternal
self.isExternal = isExternal
self.isNvme = isNvme
}

init(from decoder: Decoder) throws {
Expand All @@ -83,6 +87,7 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {
isExternal = true
}
isReadOnly = try container.decodeIfPresent(Bool.self, forKey: .isReadOnly) ?? isExternal
isNvme = try container.decodeIfPresent(Bool.self, forKey: .isNvme) ?? false
id = try container.decode(String.self, forKey: .identifier)
}

Expand All @@ -92,12 +97,18 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {
try container.encodeIfPresent(imageName, forKey: .imageName)
}
try container.encode(isReadOnly, forKey: .isReadOnly)
try container.encode(isNvme, forKey: .isNvme)
try container.encode(id, forKey: .identifier)
}

func vzDiskImage() throws -> VZDiskImageStorageDeviceAttachment? {
func vzDiskImage(useFsWorkAround: Bool = false) throws -> VZDiskImageStorageDeviceAttachment? {
if let imageURL = imageURL {
return try VZDiskImageStorageDeviceAttachment(url: imageURL, readOnly: isReadOnly)
// Use cached caching mode for virtio drive to prevent fs corruption on linux when possible
if #available(macOS 12.0, *), !isNvme, useFsWorkAround {
return try VZDiskImageStorageDeviceAttachment(url: imageURL, readOnly: isReadOnly, cachingMode: .cached, synchronizationMode: .full)
} else {
return try VZDiskImageStorageDeviceAttachment(url: imageURL, readOnly: isReadOnly)
}
} else {
return nil
}
Expand All @@ -107,6 +118,7 @@ struct UTMAppleConfigurationDrive: UTMConfigurationDrive {
imageName?.hash(into: &hasher)
sizeMib.hash(into: &hasher)
isReadOnly.hash(into: &hasher)
isNvme.hash(into: &hasher)
isExternal.hash(into: &hasher)
id.hash(into: &hasher)
}
Expand All @@ -127,6 +139,7 @@ extension UTMAppleConfigurationDrive {
sizeMib = oldDrive.sizeMib
isReadOnly = oldDrive.isReadOnly
isExternal = oldDrive.isExternal
isNvme = false
imageURL = oldDrive.imageURL
}
}
10 changes: 7 additions & 3 deletions Configuration/UTMQemuConfiguration+Arguments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,9 @@ import Virtualization // for getting network interfaces
"if=pflash"
"format=raw"
"unit=0"
"file="
"file.filename="
bios
"file.locking=off"
"readonly=on"
f()
f("-drive")
Expand Down Expand Up @@ -733,13 +734,16 @@ import Virtualization // for getting network interfaces
}
"id=drive\(drive.id)"
if let imageURL = drive.imageURL {
"file="
"file.filename="
imageURL
} else if !isCd {
"file="
"file.filename="
placeholderUrl
}
if drive.isReadOnly || isCd {
if drive.imageURL != nil {
"file.locking=off"
}
"readonly=on"
} else {
"discard=unmap"
Expand Down
6 changes: 4 additions & 2 deletions Documentation/MacDevelopment.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ git submodule update --init --recursive

## Dependencies

The easy way is to get the prebuilt dependences from [GitHub Actions][1]. Pick the latest release and download all of the `Sysroot-macos-*` artifacts. You need to be logged in to GitHub to download artifacts. If you only intend to run locally, it is alright to just download the sysroot for your architecture.
The easy way is to get the prebuilt dependences from [GitHub Actions][1]. Pick the latest release and download all of the `Sysroot-macos-*` artifacts. You need to be logged in to GitHub to download artifacts. If you only intend to run locally, it is alright to just download the sysroot for your architecture. After downloading the prebuilt artifacts of your choice, extract them to the root directory where you cloned the repository.

To build UTM, make sure you have the latest version of Xcode installed.

### Building Dependencies (Advanced)

Expand Down Expand Up @@ -58,7 +60,7 @@ If you are developing QEMU and wish to pass in a custom path to QEMU, you can us
You can build UTM with the script:

```sh
./scripts/build_utm.sh -t TEAMID -p macos -a ARCH -o /path/to/output/directory
./scripts/build_utm.sh -t TEAMID -k macosx -s macos -a ARCH -o /path/to/output/directory
```

`ARCH` can be `x86_64` or `arm64` or `"arm64 x86_64"` (quotes are required) for a universal binary. The built artifact is an unsigned `.xcarchive` which you can use with the package tool (see below).
Expand Down
26 changes: 17 additions & 9 deletions Documentation/iOSDevelopment.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,20 @@ Alternatively, run `git submodule update --init --recursive` after cloning if yo

The easy way is to get the prebuilt dependences from [GitHub Actions][1]. Pick the latest release and download the `Sysroot-*` artifact for the targets you wish to develop on. You need to be logged in to GitHub to download artifacts.

| | Intel | Apple Silicon |
|--------------|----------------------------|---------------------------|
| iOS | N/A | `ios-arm64` |
| iOS SE | N/A | `ios-tci-arm64` |
| Simulator | `ios_simulator-x86_64` | `ios_simulator-arm64` |
| Simulator SE | `ios_simulator-tci-x86_64` | `ios_simulator-tci-arm64` |
| | Intel | Apple Silicon |
|-----------------------|----------------------------|--------------------------------|
| iOS | N/A | `ios-arm64` |
| iOS SE | N/A | `ios-tci-arm64` |
| iOS Simulator | `ios_simulator-x86_64` | `ios_simulator-arm64` |
| iOS Simulator SE | `ios_simulator-tci-x86_64` | `ios_simulator-tci-arm64` |
| visionOS | N/A | `visionos-arm64` |
| visionOS SE | N/A | `visionos-tci-arm64` |
| visionOS Simulator | N/A | `visionos_simulator-arm64` |
| visionOS Simulator SE | N/A | `visionos_simulator-tci-arm64` |

After downloading the prebuilt artifacts of your choice, extract them to the root directory where you cloned the repository.

To build UTM, make sure you have the latest version of Xcode installed.

### Building Dependencies (Advanced)

Expand All @@ -39,13 +47,13 @@ If you want to build the dependencies yourself, it is highly recommended that yo

### Command Line

You can build UTM with the script:
You can build UTM for iOS with the script (run `./scripts/build_utm.sh` for all options):

```
./scripts/build_utm.sh -p ios -a arm64 -o /path/to/output/directory
./scripts/build_utm.sh -k iphoneos -s iOS -a arm64 -o /path/to/output/directory
```

The built artifact is an unsigned `.xcarchive` which you can use with the package tool (see below). Replace `ios` with `ios-tci` to build UTM SE.
The built artifact is an unsigned `.xcarchive` which you can use with the package tool (see below). Replace `iOS` with `iOS-SE` to build UTM SE. Replace `iphoneos` with `xros` to build for visionOS.

### Packaging

Expand Down
5 changes: 5 additions & 0 deletions Platform/Main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//

import Logging
import TipKit

let logger = Logger(label: "com.utmapp.UTM") { label in
var utmLogger = UTMLoggingSwift(label: label)
Expand Down Expand Up @@ -60,6 +61,10 @@ class Main {
#if os(iOS) || os(visionOS)
// register defaults
registerDefaultsFromSettingsBundle()
// register tips
if #available(iOS 17, macOS 14, *) {
try? Tips.configure()
}
#endif
UTMApp.main()
}
Expand Down
27 changes: 26 additions & 1 deletion Platform/Shared/BusyIndicator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,38 @@
import SwiftUI

struct BusyIndicator: View {
@Binding var progress: Float?

init(progress: Binding<Float?> = .constant(nil)) {
_progress = progress
}

var body: some View {
Spinner(size: .large)
progressView
.frame(width: 100, height: 100, alignment: .center)
.foregroundColor(.white)
.background(Color.gray.opacity(0.5))
.clipShape(RoundedRectangle(cornerRadius: 25.0, style: .continuous))
}

#if os(macOS)
@ViewBuilder
private var progressView: some View {
if let progress = progress {
ProgressView(value: progress)
.progressViewStyle(.circular)
.controlSize(.large)
} else {
Spinner(size: .large)
}
}
#else
// TODO: implement progress spinner for iOS
@ViewBuilder
private var progressView: some View {
Spinner(size: .large)
}
#endif
}

struct BusyIndicator_Previews: PreviewProvider {
Expand Down
2 changes: 1 addition & 1 deletion Platform/Shared/BusyOverlay.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct BusyOverlay: View {
var body: some View {
Group {
if data.busy {
BusyIndicator()
BusyIndicator(progress: $data.busyProgress)
} else {
EmptyView()
}
Expand Down
25 changes: 22 additions & 3 deletions Platform/Shared/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import UniformTypeIdentifiers
#if os(iOS)
import IQKeyboardManagerSwift
#endif
import TipKit

// on visionOS, there is no text to show more than UTM
#if WITH_QEMU_TCI && !os(visionOS)
Expand Down Expand Up @@ -48,6 +49,9 @@ struct ContentView: View {
.disabled(data.busy && !data.showNewVMSheet && !data.showSettingsModal)
.sheet(isPresented: $releaseHelper.isReleaseNotesShown, onDismiss: {
releaseHelper.closeReleaseNotes()
if #available(iOS 17, macOS 14, *) {
UTMTipCreateVM.isVMListEmpty = data.virtualMachines.count == 0
}
}, content: {
VMReleaseNotesView(helper: releaseHelper).padding()
})
Expand Down Expand Up @@ -80,15 +84,19 @@ struct ContentView: View {
.onAppear {
Task {
await data.listRefresh()
await releaseHelper.fetchReleaseNotes()
if #available(iOS 17, macOS 14, *) {
if !releaseHelper.isReleaseNotesShown {
UTMTipCreateVM.isVMListEmpty = data.virtualMachines.count == 0
UTMTipDonate.timesLaunched += 1
}
}
#if os(macOS)
if isServerAutostart {
await data.remoteServer.start()
}
#endif
}
Task {
await releaseHelper.fetchReleaseNotes()
}
#if os(macOS)
NSWindow.allowsAutomaticWindowTabbing = false
#else
Expand Down Expand Up @@ -121,6 +129,17 @@ struct ContentView: View {
#endif
#endif
}
#if WITH_SERVER
.onChange(of: isServerAutostart) { newValue in
if newValue {
Task {
if isServerAutostart && !data.remoteServer.state.isServerActive {
await data.remoteServer.start()
}
}
}
}
#endif
}

private func handleURL(url: URL) {
Expand Down
2 changes: 1 addition & 1 deletion Platform/Shared/RAMSlider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct RAMSlider: View {
}
NumberTextField("", number: $systemMemory, prompt: "Size", onEditingChanged: validateMemorySize)
.frame(width: 80)
Text("MB")
Text("MiB")
}
}.frame(height: 30)
}
Expand Down
4 changes: 2 additions & 2 deletions Platform/Shared/SizeTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ struct SizeTextField: View {
Button(action: { isGiB.toggle() }, label: {
Group {
if isGiB {
Text("GB")
Text("GiB")
} else {
Text("MB")
Text("MiB")
}
}.foregroundColor(.blue)
}).buttonStyle(.plain)
Expand Down
Loading

0 comments on commit 42eda52

Please sign in to comment.