Commit Graph
3908 Commits
Author SHA1 Message Date
osy a68e2745ec project: add helper schemes and update the UTM SE and macOS schemes
The iOS-SE scheme has run with Address Sanitizer since the schemes were
first committed to set the architecture override, which was incidental.
An ExtensionKit extension linked with the sanitizer does not start on a
device, so every qemu-img operation of UTM SE failed when run from
Xcode. Turn it off, add the schemes Xcode created for the helper targets
so both can be built and debugged on their own, and take the Metal API
validation setting Xcode 27 writes into the macOS scheme.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 23:10:06 -05:00
osy 3359543d2c ios: run qemu-img in a helper extension on iOS 26
QEMU tools cannot run in the app process on iOS: a process may load QEMU
only once and qemu-img calls exit(). So disk snapshots of a stopped VM,
reclaiming space, compression, resizing and conversion on import were
macOS-only.

iOS 26 brings ExtensionKit, so qemu-img now runs in an ExtensionKit
extension (iOSHelper, and iOSHelper-SE for UTM SE since an extension's
bundle identifier must be prefixed by its host's). The helper speaks the
same QEMUHelperProtocol as the macOS XPC helper but loads the tool into
its own process, one tool per process. UTMProcess accepts an injected
connection so the remote path is shared with macOS, including file
access through bookmarks, whose implicit security scope grants the
resolving process access. UTMHelperProcess launches the helper and,
because the system hands a process that is still exiting to a launch
that comes too soon, tears it down with a handshake on the interruption
callback and runs helpers one at a time.

UTMQemuImage now reads the tool's output until it ends instead of
racing the exit message, resumes its continuations off the XPC reply
queue (a call made from that queue blocks in NSXPC), and stops the
process explicitly since the connection's exported object kept it from
ever being deallocated on macOS. The last stderr line becomes the error
text when the tool gives none.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 23:10:06 -05:00
osy 6d87bf6065 scripts: skip host tools when packing universal sysroots
The Mesa host build now installs a build machine copy of the KosmicKrisp
driver into host/lib. It has the same architecture in every sysroot, so
lipo refuses to combine it.

Assisted-by: Claude:claude-opus-5-5
2026-09-23 23:08:47 -05:00
osy 3adfacfe8d build: disable KosmicKrisp for simulator builds
Simulator does not support Metal 4
2026-09-23 14:21:46 -05:00
osy 9d8dc338e3 settings(iOS): store the KosmicKrisp driver tag as an integer
The other Vulkan driver values are integers, and the raw value is
read back as one, so the string entry was inconsistent with its
siblings.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 11:01:44 -05:00
osy c066b83069 build: update KosmicKrisp which now requires macOS 26
The new Mesa revision builds KosmicKrisp with the precompiled shader
compiler, and the driver now needs macOS 26 (and the aligned iOS,
tvOS, and visionOS 26 releases) at runtime. Bump the availability
gates on the settings picker and the VM start check to match.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 11:01:44 -05:00
osy 26080e4be9 build: update accelerated graphics backends 2026-09-23 11:01:34 -05:00
osy b397117744 spice: fix mic quality issues
Fixes #7751
2026-09-23 11:01:34 -05:00
osy dd49e2f51a Merge pull request #7903 from utmapp/agents/utm-release
agents: add /utm-test and /utm-release workflows
2026-09-23 10:29:13 -05:00
osy 2c71eadfac Merge pull request #7907 from utmapp/settings/add-device-menu-style
settings: match the add-device menu to the sidebar on macOS 26
2026-09-23 09:33:33 -05:00
osy 5a01ce6bc4 Merge pull request #7906 from utmapp/settings/notes-field
settings: use a bezeled multi-line text field for notes on macOS
2026-09-23 09:33:12 -05:00
osy 4d8e9538cd Merge pull request #7905 from utmapp/feature/qemu-args-rework
settings(qemu): separate custom arguments from the generated command line
2026-09-23 09:32:57 -05:00
osy 849619b22f agents: add /utm-release for publishing GitHub releases
Cutting a release meant hand-assembling notes that the app parses for
"What's New", and Release.md no longer matched the template in use. The
skill drafts the notes from the commits and PRs since the last release
(carrying the series forward on revisions), waits for approval, then
bumps Build.xcconfig, tags, and creates the release and its Releases
discussion. Release.md now holds the current template and footer and
documents which platform prefixes the in-app parser accepts.

Assisted-by: Claude:claude-opus-5-5
2026-09-23 09:30:35 -05:00
osy 2e0bfc8bbe settings: match the add-device menu to the sidebar on macOS 26
On macOS 26 and later, the borderless button menu style draws the
Devices "New…" entry as a compact pull-down: smaller text, an untinted
icon, a chevron, and a text column that does not line up with the other
sidebar rows. Only the button menu style combined with the plain button
style renders the label like the neighbouring rows, so use that on
macOS 26 and keep the existing style on older releases and on iOS.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 01:05:58 -05:00
osy dedb00e3b1 settings: use a bezeled multi-line text field for notes on macOS
The macOS notes box was a TextEditor with a hand-drawn half-point
border, which did not match the bezel of the name field above it and
had no focus ring. A TextField with a vertical axis has the right look
but submits on Return instead of inserting a newline, and a drawn
overlay cannot follow the bezel style of each macOS release.

Wrap an NSTextField configured for wrapping instead, so AppKit draws
the same bezel, highlight and focus ring as the name field on every
supported macOS version. Return is routed through the field editor
to insert a newline, the field grows with its contents from a 200pt
minimum, and the page's disableAutocorrection setting is applied to
the field editor as the TextEditor did. iOS keeps the TextEditor.

Assisted-by: Claude:claude-fable-5-1
2026-09-23 00:19:18 -05:00
osy 3de02b50ee settings(qemu): separate custom arguments from the generated command line
The QEMU settings page listed UTM's generated arguments next to the
editable custom ones in a single list, which made users think the
generated arguments could be changed and invited pasting options found
online that do not apply to UTM's build of QEMU.

Move custom arguments to their own page, edited through a popover on
macOS and a pushed page on iOS like port forwarding, instead of inline
text fields that needed SwiftUI workarounds. On macOS the page is hidden
behind a checkbox on the QEMU page that is only on while the settings
sheet is open unless the VM already has custom arguments; a short
disclaimer sits under the checkbox and under the iOS row. The complete
command line is shown as read-only selectable text, so the export
command feature is removed.

Assisted-by: Claude:claude-fable-5-1
2026-09-22 23:21:22 -05:00
osy 100701eb8b Merge pull request #7902 from utmapp/feature/apple-audio-input
apple: allow sound input and output to be enabled separately
2026-09-22 18:51:24 -05:00
osy d798b3204b Merge pull request #7901 from utmapp/feature/swiftterm-2
terminal: update SwiftTerm and adopt its new renderer and find bar
2026-09-22 18:50:56 -05:00
osy 5887740570 Merge pull request #7900 from utmapp/fix/serial-terminal-input
CocoaSpice: fix typing into the built-in serial terminal
2026-09-22 18:50:34 -05:00
osy 4dababc843 Merge pull request #7899 from utmapp/fix/stale-display-window
scripting: close the VM's window when updating its configuration
2026-09-22 18:50:16 -05:00
osy e50840634f apple: allow sound input and output to be enabled separately
Since the input and output streams were merged into a single
virtio-sound device, playing audio in the guest also opens the host
microphone, which switches Bluetooth headphones into headset mode.
Replace the "Enable Sound" toggle with a choice of input only, output
only, or both so users can avoid opening the microphone.

The existing "Audio" key keeps meaning output and a new "AudioInput"
key is added. When "AudioInput" is missing it defaults to "Audio", so
existing configs keep both streams and new configs still load on older
versions of UTM.

Resolves #7875

Assisted-by: Claude:claude-opus-5-5
2026-09-22 15:03:12 -05:00
osy d50855b743 agents: add /utm-test for building, running, and debugging changes
Gives agents a repeatable way to exercise a change in the real app before
/utm-review: build UTM and dependencies, repackage a single dependency
with scripts/fixup.sh, create and delete a throwaway test VM by scripting,
find logs, debug, and test headless GUI and the iOS simulator.

Assisted-by: Claude:claude-opus-5-5
2026-09-22 14:59:56 -05:00
osy c18d86dd50 scripts: extract fixup.sh so a single rebuilt dependency can be repackaged
Repackaging one dependency after a change previously meant re-running the
whole build_dependencies.sh. Move the framework fixup into scripts/fixup.sh
so it can be run on its own, and have build_dependencies.sh call it.

Standalone use needed two fixes: re-running no longer nests symlinks
inside an existing Versions/Current (ln -h) and updates Info.plist keys
instead of skipping them, and imports are also matched by file name so
a sysroot built elsewhere (e.g. a CI artifact) is rewritten correctly.
Output for a full build is unchanged.

Assisted-by: Claude:claude-opus-5-5
2026-09-22 14:59:56 -05:00
osy 1d563cf9b3 CocoaSpice: fix typing into the built-in serial terminal
Keystrokes typed into a QEMU VM's built-in terminal never reached the
guest. SPICE sends port writes by reference after CSPort returns, and
since the CocoaSpice update in cebbab9d drains an autorelease pool on
every SPICE loop iteration, the bytes were freed before they were sent.
Pull in the CocoaSpice fix that keeps the data alive until the write
completes.

Fixes #7814

Assisted-by: Claude:claude-opus-5-5
2026-09-22 14:53:14 -05:00
osy 29a3c1f62b terminal: update SwiftTerm and adopt its new renderer and find bar
SwiftTerm 2 no longer exposes the underlying Terminal from TerminalView, so
move the terminal views to the copied view APIs: terminalDimensions,
resize(cols:rows:), setCursorStyle, softReset and resetToInitialState. The
view's resize also soft resets the terminal now, so only call it when the
saved size differs, otherwise every resume would reset the guest's modes.

Track SwiftTerm from the osy/SwiftTerm fork's fix/visionos-build branch
for now: upstream main reads UIWindow.screen, which does not exist on
visionOS, and the fork reads the display scale from the trait collection
instead so the visionOS build works again.

SwiftTerm now ships a build tool plugin, which needs two changes to
build_utm.sh for CI. Xcode refuses to run a package plugin the machine has
not trusted, so pass -skipPackagePluginValidation. And -sdk also applies
to host tools, so the plugin's generator was built for the target platform
instead of the Mac and the build could not find it; pick the platform
with a generic destination and the architectures with ARCHS instead.
Also match the SDK name macosx when picking the default macOS scheme.

Take advantage of what the update brings:

- Render with Metal on macOS and iOS, falling back to Core Graphics if the
  GPU pipeline cannot be created. visionOS stays on Core Graphics because
  SwiftTerm's Metal path draws at the wrong scale there.
- Release the renderer with updateUiClosed() when the terminal window
  closes or the iOS view is dismantled, as SwiftTerm now requires.
- Feed guest output straight from the serial port thread; feed() is
  thread-safe now, so the hop to the main queue is no longer needed.
- Add the standard Edit > Find menu on macOS, which the terminal's new
  find bar is driven from.
- Open only http(s) links from the terminal. SwiftTerm now also turns host
  file paths printed by the guest into links, and its default handler on
  macOS opens any URL or existing host path, so clicking one could launch
  a host app. On iOS, let the bell use SwiftTerm's default haptic instead
  of an empty override.

Assisted-by: Claude:claude-opus-5
Assisted-by: Claude:claude-opus-5-5
2026-09-22 14:52:14 -05:00
osy adb43bffbb scripting: close the VM's window when updating its configuration
A VM's window is kept after it stops and run(vm:) reuses it as is. The Edit
button closes it before opening the settings, but AppleScript's update
configuration did not. If the displays were removed that way, the next start
got the old display window, which looks up the now missing display 0 and
crashes with an index out of range.

Close the window before updating the configuration, like the Edit button does,
so the next start creates the right kind of window.

Resolves #7882

Assisted-by: Claude:claude-opus-5-5
2026-09-22 14:11:18 -05:00
osy 8bc7a0ba7e Merge pull request #7896 from utmapp/feature/snapshots-gui
snapshots: manage snapshots of QEMU and Apple VMs
2026-09-22 13:02:41 -05:00
osy b1e1b12a05 scripting: model snapshots as scriptable objects
The snapshot commands could only name a snapshot and could not say anything
about it. A script could not tell when a snapshot was taken, how much it
holds, whether restoring it resumes the guest or starts it up, or whether
its data has gone missing, and there was no way to rename one or to throw
away a suspended state, both of which the window offers.

Make a snapshot an object instead. A virtual machine now has snapshots as
elements, each carrying those details, so a script can pick one out and
read it:

    tell application "UTM"
      set vm to virtual machine named "Debian"
      set candidates to (snapshots of vm whose includes running state)
      restore (item 1 of candidates)
    end tell

Renaming is setting the name, and the commands that act on a snapshot take
the snapshot itself. Creating one returns it. Two more commands cover what
the window can do and scripting could not: scanning the images for
snapshots made by other tools, and discarding a saved state so the guest
starts up instead of resuming.

This replaces the snapshot commands of the 5.0.5 beta, which addressed a
snapshot by name through its virtual machine, so scripts and utmctl calls
written against them have to be updated.

Snapshots are addressed by name, so names are now kept apart the way
virtual machine names are, by appending a number.

Deleting a snapshot is its own command rather than the standard delete,
which coerces a specifier for anything inside a virtual machine into the
virtual machine itself; deleting that would throw away far more than was
asked for. The delete command refuses such a specifier for the same reason.

UTMScripting.swift is regenerated from the sdef; only the hunks that
changed are taken.

Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:36 -05:00
osy e79d3b3bf0 snapshots: fill in the snapshots tab
The tab was built against a list that only held its entries in memory. Read
them from the VM instead, and send every action to UTMSnapshotService.

Which actions a snapshot offers now follows what the backend can do in the
state the VM is in, so a snapshot that cannot be restored right now says so
by being unavailable rather than by failing afterwards.

qemu-img is only part of the macOS app, so a VM whose snapshots cannot be
managed at all shows the details on their own as before.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:30 -05:00
osy f4a3c5ac7c snapshots: manage Apple VM snapshots
Apple virtualization reported snapshots as unsupported. It has no notion of
them, but the pieces are there: the disks can be layered and the saved
state and firmware storage are ordinary files.

Add a backend that freezes a layer per drive and keeps copies of the saved
state, the EFI variables and the macOS auxiliary storage beside them. The
layers under a disk that is attached cannot be changed, so a running VM may
only delete; everything else waits until it stops.

A layer sits beside the image it belongs to and is named after it, and the saved
state and firmware of a snapshot are copies named the same way. A bundle only
keeps the files its configuration names, so saving the configuration would take
all of them with it. Work out what the snapshots still need instead — the layer
being written to, the layers of the snapshots in the bundle, and whatever lies
underneath those — and keep exactly that, so anything left over is still cleaned
up. When that cannot be worked out, because the manifest or a layer cannot be
read, everything named after the file is kept instead.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:30 -05:00
osy 0086417b97 snapshots: manage QEMU snapshots through a backend
Snapshots were read straight out of the QEMU images by the scripting
commands, which only worked while the VM was off and knew nothing beyond
the tags in the image.

Put a backend behind the operations instead. Which one is chosen depends on
whether the VM is running, and each says what it can do in that state:

- A running VM goes through the QEMU monitor, which saves and loads the
  whole machine along with the disks.
- A VM that is off goes through qemu-img, which can only save and revert
  disk contents. Nothing may touch the images while QEMU has them open, so
  a snapshot of disks alone is left alone until the VM stops.

Either way a snapshot spans every writable image, the UEFI variable store
included, because QEMU refuses to load one that any of them is missing. A
snapshot that some of them lack, such as one taken before a drive was added,
is kept but cannot be restored, which is not the same as its state being
gone: reverting only some of the drives would leave them at different points
in time. Reclaiming space rebuilds an image without its snapshots, so it is
refused while there are any.

UTMSnapshotService sits above the backend and keeps the manifest and the
stored state consistent: it marks entries whose state has disappeared when
an operation fails, and the first time a VM is opened it adopts whatever
snapshots are already in the images so that snapshots taken by other tools
are not lost. Both wait until the VM is stopped, because a running QEMU
lists the snapshots of every drive together, removable ones included.

Suspending is folded into the same mechanism. A VM now suspends to a
snapshot of its own rather than always the same name, so a suspended state
can be kept as a snapshot without copying it, and restoring a snapshot
makes the VM resume from it. The state is deleted once nothing refers to
it, where it used to be left behind in the image. One that cannot be deleted
right away stays listed in the manifest and is tried again the next time.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:30 -05:00
osy 9e8bd13e32 snapshots: record snapshot metadata in the VM bundle
A snapshot has a title, a date, a size, a screenshot and the snapshot it
was based on. None of that fits in the image formats the backends use, so
keep it in a new `snapshots.plist` in the VM bundle where each entry links
to the state in the backend by identifier.

The file also remembers which snapshot the current state came from and
which state the VM resumes from while it is suspended, along with the
states that are no longer needed but could not be deleted yet.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:29 -05:00
osy 2d48f084e6 apple(disk): stack disk image snapshots as layers
DiskImageKit can put a copy-on-write layer on an image and remembers what
each layer sits on. Use that to freeze the contents of a drive: the layer
holding what the guest has written so far is closed off under the name of a
snapshot and a fresh one is opened above it for further writes.

Layers are kept beside the image as `<image>.<name>.asif`. A layer whose
snapshot is deleted cannot be merged away while other layers are stacked on
it, so it is only marked as unlinked and is swept once nothing needs it.

Attachments are built through the same path so that a drive with layers is
opened as the whole stack, and a disposable run adds its throwaway layer on
top of it.

A stack is only ever opened whole. When one of its layers cannot be read the
drive is not attached at all: opening the rest without it would hide what it
holds, and falling back to the bare image would write underneath every layer
stacked on it. For the same reason a layer to write to is always put in place
before the one it replaces goes, and the image under a stack cannot be resized.
Nor can a drive with layers be attached read only, which a stack cannot be, or
before macOS 27, which cannot read the layers: the image alone is the drive as
it was before the first snapshot. Removable media never has layers.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:29 -05:00
osy a021240ab3 qemu-img: add snapshot subcommands
Wrap `qemu-img snapshot` so the internal snapshots of an image can be
listed, created, applied and deleted while QEMU is not running.

Assisted-by: Claude:claude-fable-5-1
2026-09-22 10:57:29 -05:00
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