Skip to content

Commit

Permalink
Merge branch 'main' into typo-new-drive
Browse files Browse the repository at this point in the history
  • Loading branch information
osy authored Aug 23, 2024
2 parents b225b14 + a03951b commit 54b4b1b
Show file tree
Hide file tree
Showing 44 changed files with 596 additions and 108 deletions.
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
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
82 changes: 82 additions & 0 deletions Platform/Shared/UTMTips.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// Copyright © 2024 osy. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import TipKit

@available(iOS 17, macOS 14, *)
struct UTMTipDonate: Tip {
@Parameter
static var timesLaunched: Int = 0

var title: Text {
Text("Support UTM")
}

var message: Text? {
Text("Enjoying the app? Consider making a donation to support development.")
}

var actions: [Action] {
Action(id: "donate", title: "Donate")
Action(id: "no-thanks", title: "No Thanks")
}

var rules: [Rule] {
#Rule(Self.$timesLaunched) {
$0 > 3
}
}
}

@available(iOS 17, macOS 14, *)
struct UTMTipHideToolbar: Tip {
@Parameter
static var didHideToolbar: Bool = true

var title: Text {
Text("Tap to hide/show toolbar")
}

var message: Text? {
Text("When the toolbar is hidden, the icon will disappear after a few seconds. To show the icon again, tap anywhere on the screen.")
}

var rules: [Rule] {
#Rule(Self.$didHideToolbar) {
!$0
}
}
}

@available(iOS 17, macOS 14, *)
struct UTMTipCreateVM: Tip {
@Parameter(.transient)
static var isVMListEmpty: Bool = false

var title: Text {
Text("Start Here")
}

var message: Text? {
Text("Create a new virtual machine or import an existing one.")
}

var rules: [Rule] {
#Rule(Self.$isVMListEmpty) {
$0
}
}
}
4 changes: 4 additions & 0 deletions Platform/Shared/UTMUnavailableVMView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ fileprivate struct WrappedVMDetailsView: View {
}
#if os(macOS)
.frame(width: 230)
#else
.padding()
#endif
}
}
Expand All @@ -92,6 +94,8 @@ fileprivate struct UnsupportedVMDetailsView: View {
}
#if os(macOS)
.frame(width: 230)
#else
.padding()
#endif
}
}
Expand Down
2 changes: 1 addition & 1 deletion Platform/Shared/VMConfigSystemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct VMConfigSystemView: View {
HStack {
NumberTextField("", number: $config.jitCacheSize, prompt: "Default", onEditingChanged: validateMemorySize)
.multilineTextAlignment(.trailing)
Text("MB")
Text("MiB")
}
}
}
Expand Down
58 changes: 53 additions & 5 deletions Platform/Shared/VMNavigationListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//

import SwiftUI
import TipKit

struct VMNavigationListView: View {
@EnvironmentObject private var data: UTMData
Expand Down Expand Up @@ -106,6 +107,29 @@ private struct VMListModifier: ViewModifier {
@State private var sheetPresented = false
@State private var donatePresented = false

private let _donateTip: Any?
private let _createTip: Any?

@available(iOS 17, macOS 14, *)
private var donateTip: UTMTipDonate {
_donateTip as! UTMTipDonate
}

@available(iOS 17, macOS 14, *)
private var createTip: UTMTipCreateVM {
_createTip as! UTMTipCreateVM
}

init() {
if #available(iOS 17, macOS 14, *) {
_donateTip = UTMTipDonate()
_createTip = UTMTipCreateVM()
} else {
_donateTip = nil
_createTip = nil
}
}

func body(content: Content) -> some View {
content
#if os(macOS)
Expand All @@ -124,15 +148,39 @@ private struct VMListModifier: ViewModifier {
#else
#if !WITH_REMOTE // FIXME: implement remote feature
ToolbarItem(placement: .navigationBarLeading) {
newButton
if #available(iOS 17, visionOS 99, *) {
Button {
createTip.invalidate(reason: .actionPerformed)
data.newVM()
} label: {
Image(systemName: "plus") // SwiftUI bug: tip won't show up if this is a label
}.help("Create a new VM")
.popoverTip(createTip, arrowEdge: .top)
} else {
newButton
}
}
#endif
#if !WITH_REMOTE
ToolbarItem(placement: .navigationBarLeading) {
Button {
donatePresented.toggle()
} label: {
Label("Donate", systemImage: "heart.fill")
if #available(iOS 17, visionOS 99, *) {
Button {
donateTip.invalidate(reason: .actionPerformed)
donatePresented.toggle()
} label: {
Image(systemName: "heart.fill") // SwiftUI bug: tip won't show up if this is a label
}.popoverTip(donateTip, arrowEdge: .top) { action in
donateTip.invalidate(reason: .actionPerformed)
if action.id == "donate" {
donatePresented.toggle()
}
}
} else {
Button {
donatePresented.toggle()
} label: {
Label("Donate", systemImage: "heart.fill")
}
}
}
#endif
Expand Down
Loading

0 comments on commit 54b4b1b

Please sign in to comment.