Commit Graph
3874 Commits
Author SHA1 Message Date
osy cb9e95af4d snapshots: add snapshot management to the VM details view
Snapshots could only be managed through scripting. Split the details view
into tabs (a tab view on macOS and a segmented control elsewhere, following
the HIG) and add a Snapshots tab next to the existing details.

The tab lists the current state followed by every snapshot, newest first,
along a timeline. A snapshot never changes unless it is overwritten, and
restoring one replaces the current state with a copy, so the actions say as
much: the current state can be saved as a new snapshot or overwrite the one
it is based on, and a snapshot can be restored or deleted. Anything that
loses data asks first.

A snapshot is based on whatever the current state was based on when it was
created. One that follows what it is based on is joined to it so a lineage
without branches reads as a single line. A base that is elsewhere in the
list is named by a link instead, which keeps branches of any depth from
widening the list. The lineage of the focused row is highlighted and only
that row shows its actions. Rows choose their layout from the measured
width because a regular size class can still be narrow next to the sidebar.

The operations only modify an in-memory list for now and no snapshots are
read from the VM yet.

Whether a snapshot holds the running machine decides whether restoring it
resumes the guest or starts it up, so the mark on the timeline is filled for one
that does and hollow for one that holds only the disks.

Assisted-by: Claude:claude-fable-5-1
2026-09-22 10:57:29 -05:00
osy a69ad794dd QEMULauncher: pass on the exit status of qemu-img
qemu-img reports most failures, such as an image that cannot be opened, by
returning from main rather than by exiting. The launcher dropped that value
and always exited with 0, so on macOS a conversion, resize or snapshot
operation that failed looked like it had succeeded. Snapshots of a VM that
is off depend on those errors to know that a state was not deleted or
reverted.

Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:29 -05:00
osy 19185e8331 Merge pull request #7894 from utmapp/feature/keyboard-accessory-glass
display(iOS): match keyboard accessory to the iOS 26 keyboard
2026-09-21 09:08:27 -05:00
osy 00e83da7ca Merge pull request #7893 from utmapp/ios-touch-gestures
display(iOS): fix touch gestures and add drag to scroll mode
2026-09-21 09:08:12 -05:00
osy 4cd971dc3d Merge pull request #7892 from changanmoon/l10n_de
Fix translation placeholder for German (de)
2026-09-21 09:07:39 -05:00
osy 52e8c3e6bc Merge pull request #7891 from utmapp/input/ios-gamepad-home-options
input(iOS): let the controller Options and Home buttons be mapped
2026-09-21 09:07:11 -05:00
osy f33763ebcd Merge pull request #7890 from utmapp/vm/ios-close-confirmation
vm(iOS): confirm before closing the window of a running VM
2026-09-21 09:06:58 -05:00
osy cbbacec96b Merge pull request #7889 from utmapp/display/fullscreen-hot-corners
display: turn off Hot Corners while a VM is in full screen
2026-09-21 09:06:44 -05:00
Tiffany Fung 43720e14b0 Add more translations for zh-Hans & zh-HK (#7887)
* Add more translations for zh-HK

* Add more translations for zh-Hans

* Add more translations for zh-HK

* Add more translations for zh-Hans

* Fix translations for zh-HK
2026-09-21 09:06:28 -05:00
osy beb2ce330f Merge pull request #7886 from utmapp/feature/apple-secure-boot
config: add Secure Boot option for Apple UEFI guests
2026-09-21 09:05:59 -05:00
osy 24fc103404 welcome: offer opening an existing VM instead of the gallery
The welcome placeholder's second tile linked out to the UTM Gallery
website, which is already reachable from the Help menu and from the new
VM wizard. Opening an existing .utm bundle had no tile at all, so the
most common way to get a VM into a fresh install was the least
discoverable. Point the tile at the existing OpenVirtualMachine
notification instead.

Assisted-by: Claude:claude-opus-5
2026-09-21 09:04:53 -05:00
osy 10799d9f46 Merge pull request #7853 from evan314159/fix-spice-gtk-coreaudio-hang
spice-gtk: fix SPICE deadlock under memory pressure
2026-09-20 22:16:18 -05:00
osy 0e87c45f7f display(iOS): match keyboard accessory to the iOS 26 keyboard
On iOS 26 the system no longer draws a backdrop behind the input
accessory and the keyboard became a rounded glass panel with flat keys,
which left the old shadowed keys floating over the VM display with
nearly invisible paste and hide buttons.

Replace the XIB with a programmatic view that keeps the previous look on
iOS 18 and earlier and draws keyboard-style keys on a glass bar on
iOS 26 and later. Standard glass takes its brightness from the guest
display behind it and its tint renders differently on iOS 26 and 27, so
clear glass filled with the keyboard's color is used to follow the
keyboard's appearance on both. Keys with word labels now size to their
label instead of shrinking the font.

The localized accessibility labels move from the XIB strings to
Localizable.strings. The forward delete key was mislabeled "Right" and
the toggled state of modifiers was not reported to VoiceOver. visionOS
has its own keyboard window and no longer builds the accessory.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 18:43:08 -05:00
osy 2f3413ff67 docs: clarify attribution rules for AI tools 2026-09-20 15:21:34 -05:00
osy 3c7ee99d06 scripts: stop dependencies weak-linking pipe2() and dup3()
pipe2() and dup3() are new in the 27.0 SDKs and carry
__API_AVAILABLE(macos(27.0), ios(27.0), ...). Both meson's has_function()
and autoconf's AC_CHECK_FUNCS declare their own prototype rather than
including the system header, so they never see that annotation and report
the functions present no matter the deployment target. The real call sites
do include <unistd.h>, so clang emits a weak import that is NULL on
anything older than 27 and the first call branches to zero.

That broke every VM start on iOS 26 and below: -[CSMain init] ->
g_main_context_new() -> g_wakeup_new() -> g_unix_open_pipe(), which calls
pipe2() when glib is configured with HAVE_PIPE2. glib, gio, gettext and
libusb all picked it up in every sysroot built with Xcode 27.

Tell both configure systems the functions are missing so the existing
pipe() + fcntl(FD_CLOEXEC) fallbacks are compiled in instead. Nothing
detects dup3() today, but cover it so the next dependency bump cannot
reintroduce the same crash.

Assisted-by: Claude:claude-opus-5
2026-09-20 15:12:05 -05:00
osy be6a8da127 display(iOS): release the mouse button when a drag is cancelled
A gesture that holds a mouse button only released it when the gesture
ended. When the system takes over the touch instead, for example a long
press drag that starts at the bottom edge and turns into the swipe to go
home, the gesture is cancelled and the guest was left with the button
held down until the next click.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 15:02:56 -05:00
osy a070e93140 display(iOS): add touch mode that scrolls instead of dragging
In the touch modes the left button goes down the moment a finger lands,
because the touch itself is the drag. Every other gesture starts with a
finger landing too, so a two finger tap, scroll or pinch first clicked
and dragged whatever was under the first finger until the gesture was
recognized, and a long press held the left button for half a second
before its right click.

Add "Touch mode (drag to scroll)" as a third touch mode that behaves
like a touch screen and never presses a button on touch down. A tap is
a left click, a long press runs the long press action, and dragging one
finger scrolls the mouse wheel so that the content follows the finger.
Since a touch no longer drags, a long press that moves turns into a left
button drag so windows and selections can still be moved with one
finger. A ring is shown when the long press is recognized because
nothing in the guest reacts until the finger lifts.

A finger never lands on the same spot twice, and a guest only counts two
clicks on the same spot as a double click, so a second tap that follows
quickly and close by clicks where the first one did.

The existing touch modes are unchanged.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 15:02:56 -05:00
osy cdfc7129e4 display(iOS): add middle click and right/middle drag gestures
Touch gestures could only produce a left drag and a right click, so a
guest that needs the middle button (paste or pan in many Linux and CAD
programs) or a right button drag could not be used without a mouse.

Add "Middle Click" to the long press and two finger tap actions, and
"Right Click & Hold" and "Middle Click & Hold" to the two and three
finger pan actions. These are new values for existing settings and the
defaults are unchanged.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 15:02:56 -05:00
osy 745e7cfc93 display(iOS): defer system gestures at the screen edges
A touch that starts at the top or bottom edge of the screen is held
back by the system in case it turns into a system gesture. A drag from
the top edge of the VM display pulled down Notification Center and the
guest never saw the touch at all.

Ask the system to defer its edge gestures while the VM display is up,
next to where the home indicator is already hidden, so the first swipe
goes to the guest and only a second one is taken by the system. This
uses the SwiftUI modifier, which needs iOS 16. Overriding the view
controller preference instead needs the hosting controller patched to
forward it, and was ignored on iOS 17.

On iOS 18 and later a swipe up from the bottom edge still goes home,
because the system ignores the deferral there while the home indicator
is hidden. Touches at the bottom edge do reach the guest immediately.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 15:02:56 -05:00
Tiffany Fung 7d6e683d00 Fix translation placeholder for German (de) 2026-09-20 20:50:42 +08:00
osy b67d062206 display(iOS): start pan gestures without waiting for swipes
Every pan and the pinch required the three finger keyboard swipes to
fail first, and a swipe recognizer only fails once the touch has moved
far enough to be judged or after about half a second. Moving the cursor
with one finger, scrolling with two or pinching therefore did nothing
for a quarter to half a second, and a short or slow two finger scroll
was mostly lost.

A swipe can only be confused with a pan that uses the same number of
touches, so only the three finger pan still waits for the keyboard
swipes. The pinch needs a guard instead: before iOS 18 it begins with
two of three fingers and would take the touches from the swipe, so it is
not allowed to begin while three fingers are down. That also stops three
fingers from zooming the display on those versions.

The two finger pan still waits for the two finger swipe when the two are
bound to different actions. When both scroll the mouse wheel there is
nothing to tell apart: the pan scrolls right away and a swipe adds its
wheel tick on top, where before any steady two finger drag was taken for
a swipe and scrolled a single tick. Because the two now scroll together,
the swipe follows the "Invert Scroll" setting like the pan.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 06:43:46 -05:00
osy 8304154849 display(iOS): recognize long press without waiting for tap
The long press recognizer required the tap recognizers to fail first. A
tap only fails once the finger has been held for well over a second, so
a normal long press was delivered as a tap when the finger lifted: the
"Right Click" action produced a left click (or nothing in touch mode)
and "Click & Hold" never pressed the button.

Reverse the dependency so the tap waits for the long press, which fails
as soon as a short touch ends and so adds no delay to taps. When the
long press action is disabled the recognizer is not allowed to begin,
otherwise holding before lifting would no longer click.

Reworked from #7697.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 04:29:46 -05:00
osy 17244e6f6c input(iOS): let the controller Options and Home buttons be mapped
Only the Menu button could be mapped to the guest. Options and Home were
left out because the system uses them for its own gestures (screenshots,
recording, opening the game overlay), so a press never did anything useful
for the guest.

Add both to the gamepad settings with the same choices as the other
buttons. They default to Disabled, which leaves the system gestures alone.
Once a button is mapped we ask the system to give up its gesture through
preferredSystemGestureState, which the system honours according to the
user's Home button setting.

Not tested with a physical controller.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 03:45:31 -05:00
osy d6306ed8c3 vm(iOS): confirm before closing the window of a running VM
On iPad, closing the last window quits the app: the system ends the process
about 100 ms after the scene disconnects, so a running VM was lost without
any warning. macOS already asks through windowShouldClose.

iOS 27 lets a scene ask for confirmation first, so do that for the last
interactive window unless the VM is stopped or paused with its state saved.
Stop replaces the Close button.

There is no Suspend button because the process does not live long enough
after the window closes to save the state; a button that started the save
was tried and the state was never written.

Not available on visionOS, and not needed for UTM Remote where the VM keeps
running on the server.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 03:45:31 -05:00
osy 04b38aec87 display: turn off Hot Corners while a VM is in full screen
A guest in full screen owns the whole display, and its own corners are
commonly used (Start button, Show Desktop, Apple menu). Moving the pointer
there also triggered the Hot Corner configured on the host, e.g. Quick Note
or Mission Control popping up over the guest.

macOS 27 adds NSApplication.PresentationOptions.disableScreenCornerInteractions,
which we now request for the full screen space. The camera housing mode
forces its own options and has to carry the flag over.

On macOS 27.0 the window server keeps the corners disabled for the app after
the full screen space is gone, even though AppKit reports no options, until
the options change again. Reset them when leaving full screen.

Nothing is done for a captured mouse: the pointer is detached from the
cursor and parked in the middle of the screen, so it never reaches a corner.

Assisted-by: Claude:claude-fable-5-1
2026-09-20 03:45:30 -05:00
osy 855bc0d2df config: add Secure Boot option for Apple UEFI guests
macOS 27 lets the host manage Secure Boot state in the EFI variable
store. Add a persisted flag and a toggle in the Boot settings so generic
UEFI guests on the Apple backend can opt in. The state is reconciled when
the configuration is saved, using the default platform key and the
default Microsoft signatures so that mainstream Linux distributions boot
unmodified. The store is only written when its state differs from the
configuration, and a virtual machine with the option off never fails to
save because of it. The option defaults to off because guests without a
Microsoft-signed bootloader would otherwise stop booting.

Assisted-by: Claude:claude-fable-5-1
2026-09-19 23:18:45 -05:00
osy 9d00a54833 Merge pull request #7885 from utmapp/feature/fullscreen-notch
display: fill the area beside the camera housing in full screen
2026-09-19 22:45:35 -05:00
osy 3af22be5a1 Merge pull request #7881 from utmapp/feature/apple-guest-provisioning
scripting: provision macOS guests on first boot
2026-09-19 22:45:12 -05:00
osy 602d8fc615 scripting: provision macOS guests on first boot
macOS 27 can create the guest's user account, turn on automatic login and
Remote Login without going through Setup Assistant, which lets CI and other
automation get a ready-to-use macOS VM. The guest only reads these options
on the first boot after macOS is installed and they include a password, so
they are passed as a parameter to a single start and are never saved to the
configuration or the registry.

This is only exposed to AppleScript (`start ... provisioning {...}`) and
utmctl (`start --provision-*`) because most users will never need it. utmctl
can read the password from standard input to keep it out of the process
list. Requests that cannot be honoured (not a macOS guest, host older than
macOS 27, install still pending, saved state, recovery mode, invalid account)
fail before the VM starts so the first boot is not used up.

UTMScripting.swift has only the regenerated `start` declaration. The rest of
the current bridge-gen.sh output is unrelated to this change.

Assisted-by: Claude:claude-fable-5-1
2026-09-19 22:05:10 -05:00
osy b58ac6b535 Merge pull request #7880 from utmapp/apple/diskimagekit
apple: adopt DiskImageKit and add disposable mode on macOS 27
2026-09-19 22:01:06 -05:00
osy 230f400ddc display: fill the area beside the camera housing in full screen
A full screen VM on a Mac with a camera housing loses the strip beside
it, which the guest could otherwise use. Two things keep a native full
screen window out of that strip: AppKit insets the full screen frame and
the window server covers the strip with an opaque menu bar. There is no
public way around either, and a borderless window is not an option
because macOS would no longer treat the VM as a full screen app.

Add an opt-in preference (macOS 27+) and a window subclass that returns
the whole screen as the full screen frame and makes the menu bar of its
own full screen space transparent while it is not revealed. When the menu
bar is revealed it looks and behaves as it always did. It works within
the App Sandbox.

All of it relies on private AppKit and SkyLight symbols. None of them are
used or hooked until the option is enabled and a window enters full
screen, so the window is unaffected by changes to them otherwise. They
are looked up at runtime by name and checked against the signatures we
expect, so no private symbol is linked or compiled into the binary and
if any are missing or different the window behaves like any other.

The window server reveals the menu bar as soon as the pointer is over the
strip, which would make that area of the guest display unusable. It is
instead only revealed when the pointer reaches the top edge of the
screen: until then the space uses presentation options that hide the menu
bar, which also hides the Dock. AppKit applies the options of the space
again when it changes spaces, so they are kept up to date.

The window server only lets a window cover the strip if it does so from
the moment it enters the full screen space, which shapes the rest:

- Every frame query in the transition is answered with the whole screen,
  and later requests to resize the window are ignored, because asking
  for any frame again, even the current one, moves it out of the strip.
  Our window controllers do so to fit the guest display, and AppKit does
  when the space becomes active again.
- Once the strip has been left, such as when tiled in Split View, it is
  not asked for again until full screen is next entered.
- The QEMU window is no longer resized to fit a display the guest just
  changed while the transition to full screen is still running. The flag
  the controller kept for that is only set once the transition is over,
  so the window ended up taller than the screen and lost the strip.
- AppKit parks the auto hidden toolbar behind the menu bar, or over our
  content while the menu bar is hidden, so it is hidden along with it.

The window stands down when tiled, on a screen without a camera housing,
and when the menu bar is set to always be visible in full screen.
Terminal windows do not opt in.

Resolves #6183

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-19 18:27:21 -05:00
osy 3b0da37c46 apple: run without saving changes on macOS 27
"Run without saving changes" has only been available for QEMU, where it
maps to `-snapshot`. Apple Virtualization has no such option, but
DiskImageKit on macOS 27 can stack a copy-on-write layer on top of an
image and Virtualization accepts the stacked image as a storage
attachment.

When started with the disposable option, the Apple backend now creates a
temporary directory in the sandbox and gives every writable drive an
ephemeral ASIF overlay there. The base image is opened read-only and is
never touched. The EFI variable store and the macOS auxiliary storage are
cloned into the same directory so firmware settings are not persisted
either. The directory is deleted when the guest stops or when start
fails, any leftover from a previous start is discarded before the next
start, and directories orphaned by a crash are swept at app launch.
Removable drives attached at start or hot-plugged during the run are
covered as well.

A disposable run boots fresh and leaves any saved suspend state and the
modification date alone, and reports the save/restore path as
unsupported so closing the window offers to kill the VM instead of
suspending it, matching the QEMU behaviour. The stop paths that delete a
saved suspend state skip that while running disposably.

The context menu, the Start intent and the menu bar extra now check the
backend capability instead of assuming QEMU, and the Apple display window
shows the same "Disposable Mode" subtitle as QEMU.

Assisted-by: Claude:claude-fable-5-1
2026-09-19 10:51:06 -05:00
osy fa92ca48ed asif: use DiskImageKit on macOS 27
ASIF drives for Apple Virtualization are created, inspected and resized
through the private DiskImages2 framework, loaded by path and called via
NSInvocation. macOS 27 ships DiskImageKit, a public Swift-only framework
that covers the same operations and is what Virtualization.framework now
consumes directly.

Add UTMAppleDiskImage, a Swift wrapper that uses DiskImageKit on macOS 27
and later and falls back to the existing UTMASIFImage helper on macOS 13
through 26. The legacy path is confined to one private extension so it
can be deleted together with UTMASIFImage once the minimum host is
macOS 27. DiskImageKit is weak linked because the deployment target is
below macOS 27.

Callers switch to the wrapper; the resize path no longer force-unwraps
the helper.

Assisted-by: Claude:claude-fable-5-1
2026-09-19 10:49:50 -05:00
osy d67f4ba35c docs: add comment style guideline 2026-09-19 10:48:32 -05:00
osy b4e22be198 Merge pull request #7872 from changanmoon/l10n
Update translations for zh-Hans & zh-HK
2026-09-19 10:46:42 -05:00
Tiffany Fung 18be937cb1 Add MS-DOS logo 2026-09-19 10:46:23 -05:00
osy fa30b642f9 Merge pull request #7863 from meisenbarth/scripting-install-command
scripting: add an install command for macOS guests
2026-09-19 10:44:34 -05:00
osy 9b183e5154 Merge pull request #7862 from meisenbarth/scripting-macos-create
scripting: allow creating macOS VMs with the Apple backend
2026-09-19 10:44:22 -05:00
Marc Eisenbarth e25397a431 scripting: allow creating macOS VMs with the Apple backend
createAppleVirtualMachine hardcodes the guest OS:

    config.system.boot = try UTMAppleConfigurationBoot(for: .linux)

Every other field in the record is already honoured via
updateConfiguration(from:). The OS is the only thing a script cannot ask
for, and UTMAppleConfigurationBoot.init(for:) already accepts one.

This reads `os` from the record (as an AEKeyword, the same as `backend`;
sdef enumerations do not arrive as strings), defaulting to .linux so
existing scripts are unaffected. When the OS is macOS it requires and sets
`macRecoveryIpsw`, since without it the VM has nothing to restore from.

It also derives macPlatform from the caller's IPSW. fillVZConfiguration
throws platformUnsupported for a macOS guest with no platform, so setting
the OS and IPSW alone produces a VM that is created and then fails to
start with "This virtual machine cannot run on the current host machine."
The hardware model comes from the caller's own image via
VZMacOSRestoreImage.image(from:) rather than fetchLatestSupported: the
caller named a specific IPSW and the model must match it. An IPSW this
Mac cannot run fails with the same error the wizard shows.

And it gives a macOS guest a display, audio, keyboard and pointer by
default. The scripted create clears `displays` (the headless-by-default
convention that suits a Linux guest with a serial console), and
fillVZConfiguration only builds a graphics device when `displays` is
non-empty. For macOS that produced a guest with no framebuffer: it booted
to 0% CPU and UTMData.run chose a headless session because there was
nothing to show. The defaults mirror VMWizardState for a new macOS VM
(1920x1200, audio, generic keyboard, trackpad on Ventura+). A caller may
still override `displays`, but the input and audio devices cannot be set
from a script, so they are always enabled for a macOS guest.

The sdef gains an `operating system` enumeration (linux / macOS) and a
`macRecoveryIpsw` file property. The property name matches the existing
macRecoveryIpswURL and the "IPSW Install Image" label in
VMConfigAppleBootView.

UTMScripting.swift: the UTMScriptingOperatingSystem enum matches the
output of bridge-gen.sh for this sdef change.

Verified against main on Xcode 26.6 / Apple Silicon: a macOS 26.6.2 VM
created from AppleScript with OperatingSystem=macOS, a HardwareModel,
MachineIdentifier, AuxiliaryStoragePath and a 1920x1200 Display in the
resulting config.plist, and booted to Setup Assistant in a UTM display
window.

Refs #6092

Assisted-by: Claude:claude-opus-5
2026-09-19 10:09:24 -05:00
osy 5d395abfc8 scripting: return from install before the Apple Event times out
A macOS install takes several minutes, well past the default two minute
Apple Event timeout. A plain `install` therefore failed with -1712 while
the installation kept running, and a script reacting to that error by
retrying or starting the VM would race the install.

`install` now returns as soon as the installation starts, and the new
`query install` verb reports whether it is still running and how far it
has progressed, or raises the error if it failed. The installation only
counts as finished once the VM has stopped by itself, so the VM can be
started right away.

Other verbs fail with a clear error while an installation started from
a script is in progress. This includes `start`, which would otherwise
open a window that asks to install macOS again. As in the GUI, `stop`
cancels the installation.

Assisted-by: Claude:claude-opus-5
2026-09-19 09:49:15 -05:00
Marc Eisenbarth 8d04b96c23 scripting: add an install command for macOS guests
VMDisplayAppleWindowController.windowDidLoad shows a confirmation sheet
before calling requestInstallVM, so a macOS install cannot be driven from
a script without someone clicking OK.

This does not remove the sheet. It guards a genuinely destructive action
(it erases the primary drive) and a GUI user who opens a VM that happens
to carry an IPSW should keep being asked. It is also structurally
unavailable to a script: showConfirmAlert calls
beginSheetModal(for: window!), so it needs a window, and the scripted
`start` verb calls data.run(...), which loads the window controller and
raises the sheet in the first place.

So this adds a separate `install` verb that goes straight to
installVM(with:) and never opens a window. The confirmation moves rather
than disappearing: asking for `install` is the confirmation, which is why
the sdef entry says DESTRUCTIVE in as many words. This matches the
CONTRIBUTING.md guidance about putting things most users do not need into
the scripting interface rather than the UI.

It also clears the IPSW on success, as the GUI does in
didCompleteInstallation. That clearing lives in the window controller's
delegate callback, and a scripted install has no window, so without it
the IPSW outlives the install and the next `start` that does open a
display window asks "Would you like to install macOS?" over a guest that
is already installed. Measured before the fix: the registry still held
the IPSW after a completed scripted install.

Two guards, because installVM returns silently when the VM is not
stopped and calling it unguarded would report success having done
nothing: a VM with no IPSW configured, and a VM that is not stopped, each
fail with an error naming the cause.

Verified against main on Xcode 26.6 / Apple Silicon: no confirmation
sheet at any point, a macOS 26.6.2 install run to completion (21 GB,
framework returned success), the IPSW cleared from the registry
afterwards, and a subsequent `start` opening a display window with no
reinstall prompt and the guest booting to Setup Assistant.

UTMScripting.swift gains the install() method that bridge-gen.sh
generates for this sdef change.

Refs #6092

Assisted-by: Claude:claude-opus-5
2026-09-19 09:34:56 -05:00
osy a4edd6175f Merge pull request #7860 from LayerTM/fix/utmctl-entitlement-unsigned
package_mac: expand the utmctl scripting target before signing
2026-09-19 09:07:43 -05:00
osy a3242448ca Merge pull request #7856 from atkinsam/fix/apple-scripting-shared-dir
scripting: fix shared directory access for Apple Virtualization VMs
2026-09-19 09:02:23 -05:00
osy 56ebf381f9 Merge pull request #7854 from lprazdnik/fix/browse-button-accessibility
ui(macOS): identify file browse fields as accessibility groups
2026-09-19 08:58:43 -05:00
osy be869dd2ab Merge pull request #7865 from lovon-spec/apple/vmnet-networking
apple: let virtual machines connect to each other
2026-09-19 08:56:03 -05:00
osy 47eadda150 apple: make the vmnet modes predictable and simpler
Follow-up to the vmnet networking modes:

- Rename "Shared Network (VM to VM)" to "NAT Network" (config value
  "NATNetwork", scripting term "nat network") so the picker does not offer
  two "Shared" modes that differ only by a suffix.
- Request a fixed subnet per mode outside of the ranges vmnet hands out by
  default. Those ranges are also used by NAT attachments and QEMU, so guest
  addresses depended on what else was running whenever the network was
  (re)created. Fall back to a vmnet chosen subnet when ours is taken.
- Show the mode description with DetailedSection. The bare Text row widened
  the form and clipped the labels and controls in the settings window.
- Only require macOS 26 when a network is actually created, so a VM using
  one of these modes can still be edited and saved on older hosts.
- Do not apply locale digit grouping to the vmnet error code.
- Fold the validation flag into the existing one that skipped drives and
  leave the device unattached instead of using a NAT placeholder, remove
  the unused reverse mapping, key the networks by vmnet_mode_t, and isolate
  the manager to the main actor in place of a lock with no concurrent users.

Use .1 as the host-side address within each preferred /24. As reproduced
in PR #7865, vmnet accepts .0 during network creation but the interface
fails later at startup.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: ChatGPT:GPT-6-Astra-Pro
2026-09-18 20:43:49 -04:00
osy fe74b1d8cc apple: release the virtual machine when it fails to start
No delegate callback follows a failed start, restore, or install, so the
VZVirtualMachine created for the attempt was kept until the next start and
the serial port PTYs stayed open and advertised for a stopped VM. With vmnet
networking this also kept the network and its subnet reserved with nothing
running. Drop the virtual machine and close the serial ports in that case,
unless the guest is still alive and will report its own stop.

Assisted-by: Claude:claude-fable-5-1
2026-09-18 13:39:50 +02:00
lovon-spec 31b431f8b5 apple: let virtual machines connect to each other
Apple Virtualization's existing Shared Network uses a separate NAT
attachment per VM, so guests cannot use it to reach each other. macOS 26
adds VZVmnetNetworkDeviceAttachment, which lets multiple VMs attach to the
same process-owned vmnet network.

Add two macOS 26+ modes:

- "Shared Network (VM to VM)": guests share a NAT-backed vmnet network and
  can reach each other, the host, and external networks.
- "Host Only": guests share a host-only vmnet network and can reach each
  other and the host without external routing.

UTMAppleVmnetNetworkManager keeps a weak attachment cache per mode while
Virtualization configuration and runtime objects own the attachment and its
native network. The network therefore follows the actual VZ object lifetime
rather than UTM's presentation state, including failure paths where a VZ VM
can remain alive after UTM reports it stopped. Configuration validation uses
a side-effect-free placeholder so saving a VM does not create a live vmnet
network.

Hide both modes before macOS 26 and add matching scripting enumerators and
round-trip parsing.

Resolves #6975.
Related to #7418 and #7380.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: ChatGPT:GPT-6-Pro
Assisted-by: ChatGPT:GPT-5.6-Sol
2026-09-18 13:26:24 +02:00
osy 5534ffab7d Merge pull request #7879 from utmapp/feature/toolbar-power-control
toolbar(macOS): draw VM power controls as one segmented control
2026-09-18 09:33:32 +02:00
osy 99afefaed4 Merge pull request #7877 from utmapp/feature/apple-usb-passthrough
apple: add USB passthrough on macOS 27
2026-09-18 09:31:35 +02:00