Merge pull request #7885 from utmapp/feature/fullscreen-notch

display: fill the area beside the camera housing in full screen
This commit is contained in:
osy
2026-09-19 22:45:35 -05:00
committed by GitHub
6 changed files with 480 additions and 2 deletions
@@ -31,7 +31,7 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="UTM" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" toolbarStyle="compact" id="QvC-M9-y7g">
<window title="UTM" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" toolbarStyle="compact" id="QvC-M9-y7g" customClass="VMDisplayWindow" customModule="UTM" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
@@ -53,6 +53,7 @@ class VMDisplayAppleDisplayWindowController: VMDisplayAppleWindowController {
override func windowDidLoad() {
mainView = VZVirtualMachineView()
captureMouseToolbarButton.image = captureMouseToolbarButton.alternateImage // show capture keyboard image
(window as? VMDisplayWindow)?.isCameraHousingAreaAllowed = true
screenChangedToken = NotificationCenter.default.addObserver(forName: NSWindow.didChangeScreenNotification, object: nil, queue: .main) { [weak self] _ in
// update minSize when we change screens
if let self = self,
@@ -90,6 +90,7 @@ class VMDisplayQemuMetalWindowController: VMDisplayQemuWindowController {
return
}
displayView.addSubview(metalView)
(window as? VMDisplayWindow)?.isCameraHousingAreaAllowed = true
renderer = CSMetalRenderer.init(metalKitView: metalView)
guard let renderer = self.renderer else {
showErrorAlert(NSLocalizedString("Internal error.", comment: "VMDisplayMetalWindowController"))
@@ -284,7 +285,8 @@ extension VMDisplayQemuMetalWindowController {
return
}
self.displaySize = size
if self.isFullScreen {
// the flag is only set once the transition to full screen is over, until then the window must not be resized
if self.isFullScreen || window.styleMask.contains(.fullScreen) {
_ = self.updateHostScaling(for: window, frameSize: window.frame.size)
} else {
self.updateHostFrame(forGuestResolution: size)
@@ -0,0 +1,465 @@
//
// Copyright © 2026 Turing Software, LLC. 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 AppKit
/// VM window which can fill the area beside the camera housing when in full screen.
///
/// A full screen window is normally kept below the camera housing by two separate mechanisms: AppKit insets the window
/// frame and the window server covers the inset area with an opaque menu bar. Both are undone here with private APIs,
/// all of which must be present or the window behaves like any other. None of them are used or hooked until the
/// option is enabled and a window enters full screen.
class VMDisplayWindow: NSWindow {
/// Set when the content of this window is a display which should fill the area beside the camera housing.
var isCameraHousingAreaAllowed: Bool = false
/// Set from the start of the transition to full screen until the start of the transition out of it.
private var isFullScreenFrameKept: Bool = false
/// Set between entering and exiting full screen, the style mask is not enough as it changes before the space does.
private var isInFullScreenSpace: Bool = false
/// Set once we have been in the full screen space without covering the area beside the camera housing, such as when
/// tiled. The window server does not let a window return to it, so we stop asking until full screen is entered again.
private var isCameraHousingAreaLost: Bool = false
/// Full screen space where the menu bar is currently hidden by us.
private var menuBarHiddenSpaceID: UInt64?
/// Presentation options of our full screen space, which let the menu bar be revealed.
private var menuBarRevealablePresentationOptions: NSApplication.PresentationOptions?
/// Set when the pointer has reached the top edge of the screen, until the menu bar it revealed is hidden again.
///
/// The menu bar is otherwise revealed as soon as the pointer is over the area beside the camera housing, which would
/// make it impossible to use that area of the display. The window server decides that on its own, so we keep the
/// menu bar hidden with the presentation options until the pointer is at the very top.
private var isMenuBarRevealAllowed: Bool = false {
didSet {
updatePresentationOptions()
}
}
private var topEdgeEventMonitor: Any?
/// Set while the presentation options of the application are ours rather than the ones of the full screen space.
private var isPresentationOptionsForced: Bool = false
/// AppKit applies the presentation options of the full screen space again when it changes spaces or menus.
private var presentationOptionsObservation: NSKeyValueObservation?
@Setting("FullScreenUseCameraHousingArea") private var isCameraHousingAreaEnabled: Bool = false
private var isCameraHousingAreaUsable: Bool {
guard #available(macOS 27, *) else {
return false
}
guard isCameraHousingAreaAllowed && isCameraHousingAreaEnabled else {
return false
}
// when the user wants the menu bar to always be visible, the area is never free
guard !UserDefaults.standard.bool(forKey: "AppleMenuBarVisibleInFullscreen") else {
return false
}
return FullScreenFrameHook.isInstalled && SkyLight.shared != nil && MenuBarReveal.isObserving
}
/// AppKit parks the auto hidden toolbar behind the menu bar, so it has to be hidden along with it.
///
/// The alpha of this window is updated by AppKit on every step of the reveal animation, so its views are hidden instead.
private var isFullScreenToolbarHidden: Bool = false {
didSet {
guard let contentView = fullScreenToolbarWindow?.contentView else {
return
}
(contentView.superview ?? contentView).isHidden = isFullScreenToolbarHidden
// while the menu bar cannot be revealed, AppKit parks the toolbar over our content
fullScreenToolbarWindow?.ignoresMouseEvents = isFullScreenToolbarHidden
}
}
private var fullScreenToolbarWindow: NSWindow? {
guard let spaceID = menuBarHiddenSpaceID, let skyLight = SkyLight.shared else {
return nil
}
return NSApp.windows.first { window in
window !== self && window.className == "NSToolbarFullScreenWindow" && skyLight.spaceID(for: window) == spaceID
}
}
override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag)
let center = NotificationCenter.default
center.addObserver(self, selector: #selector(willEnterFullScreen), name: NSWindow.willEnterFullScreenNotification, object: self)
center.addObserver(self, selector: #selector(didEnterFullScreen), name: NSWindow.didEnterFullScreenNotification, object: self)
center.addObserver(self, selector: #selector(updateMenuBarHidden), name: NSWindow.didResizeNotification, object: self)
center.addObserver(self, selector: #selector(willLeaveFullScreen), name: NSWindow.willExitFullScreenNotification, object: self)
center.addObserver(self, selector: #selector(willLeaveFullScreen), name: NSWindow.willCloseNotification, object: self)
center.addObserver(self, selector: #selector(menuBarRevealDidChange), name: MenuBarReveal.didChangeNotification, object: nil)
center.addObserver(self, selector: #selector(otherWindowDidChangeOcclusionState), name: NSWindow.didChangeOcclusionStateNotification, object: nil)
center.addObserver(self, selector: #selector(updatePresentationOptions), name: NSWindow.didBecomeKeyNotification, object: self)
}
override func toggleFullScreen(_ sender: Any?) {
if !styleMask.contains(.fullScreen) {
// installs our hooks before AppKit asks for the full screen frame
_ = isCameraHousingAreaUsable
}
super.toggleFullScreen(sender)
}
/// Keeps the full screen frame once we have it.
///
/// Our window controllers resize the window to fit the guest display, and AppKit constrains it to the safe area when
/// it is ordered front again. The window server does not let a window return to the area beside the camera housing
/// after it has left it, and even asking it for the frame we already have gets us moved out, so those are ignored.
override func setFrame(_ frameRect: NSRect, display flag: Bool) {
if isFullScreenFrameKept, styleMask.contains(.fullScreen), isCameraHousingAreaUsable, !isCameraHousingAreaLost,
let screen = screen, screen.safeAreaInsets.top > 0, frame == screen.frame,
fullScreenFrame(forAppKitFrame: FullScreenFrameHook.appKitFrame(for: self)) == screen.frame {
if flag {
display()
}
} else {
super.setFrame(frameRect, display: flag)
}
}
/// Frame to use in full screen instead of the one AppKit would use.
///
/// The window server only lets a window cover the area beside the camera housing if it does so from the moment it
/// enters the full screen space, so every call during the transition must return the same answer.
fileprivate func fullScreenFrame(forAppKitFrame frame: NSRect) -> NSRect {
guard isCameraHousingAreaUsable, !isCameraHousingAreaLost, let screen = screen, screen.safeAreaInsets.top > 0 else {
return frame
}
// a tiled window keeps its tile, only a window which has the screen to itself is extended
guard FullScreenFrameHook.tileFrame(for: self) == screen.frame else {
return frame
}
// the whole screen, which is the frame the window server accepts for a window that has it to itself
return screen.frame
}
@objc private func willEnterFullScreen() {
isFullScreenFrameKept = true
_ = isCameraHousingAreaUsable
}
@objc private func didEnterFullScreen() {
isInFullScreenSpace = true
updateMenuBarHidden()
}
@objc private func willLeaveFullScreen() {
isFullScreenFrameKept = false
isInFullScreenSpace = false
isCameraHousingAreaLost = false
showMenuBar()
}
/// Hides the menu bar of our full screen space if and only if we are covered by it.
@objc private func updateMenuBarHidden() {
if isInFullScreenSpace, let screen = screen, frame != screen.frame {
isCameraHousingAreaLost = true
}
guard isInFullScreenSpace, isCameraHousingAreaUsable, !isCameraHousingAreaLost, let screen = screen,
screen.safeAreaInsets.top > 0, frame == screen.frame,
let skyLight = SkyLight.shared, let spaceID = skyLight.fullScreenSpaceID(for: self) else {
showMenuBar()
return
}
guard menuBarHiddenSpaceID != spaceID else {
return
}
showMenuBar()
logger.debug("hiding menu bar in full screen space \(spaceID)")
menuBarHiddenSpaceID = spaceID
menuBarRevealablePresentationOptions = NSApp.presentationOptions
presentationOptionsObservation = NSApp.observe(\.currentSystemPresentationOptions) { [weak self] _, _ in
DispatchQueue.main.async {
self?.updatePresentationOptions()
}
}
topEdgeEventMonitor = NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved, .leftMouseDragged, .rightMouseDragged, .otherMouseDragged]) { [weak self] event in
self?.pointerDidMove()
return event
}
isMenuBarRevealAllowed = false
applyMenuBarReveal()
}
@objc private func showMenuBar() {
guard let spaceID = menuBarHiddenSpaceID else {
return
}
if let topEdgeEventMonitor = topEdgeEventMonitor {
NSEvent.removeMonitor(topEdgeEventMonitor)
self.topEdgeEventMonitor = nil
}
presentationOptionsObservation = nil
// hands the presentation options of the space back to AppKit
isMenuBarRevealAllowed = true
menuBarRevealablePresentationOptions = nil
isFullScreenToolbarHidden = false
SkyLight.shared?.setMenuBarAlpha(1, inSpace: spaceID)
menuBarHiddenSpaceID = nil
}
@objc private func updatePresentationOptions() {
guard let revealableOptions = menuBarRevealablePresentationOptions else {
return
}
// the menu bar is only kept hidden for the space we are in, but what we did must be undone in any case
let options: NSApplication.PresentationOptions?
if !isMenuBarRevealAllowed && isKeyWindow {
options = [.fullScreen, .hideMenuBar, .hideDock]
isPresentationOptionsForced = true
} else if isPresentationOptionsForced {
options = revealableOptions
isPresentationOptionsForced = false
} else {
options = nil
}
if let options = options, NSApp.presentationOptions != options {
NSApp.presentationOptions = options
}
}
private func pointerDidMove() {
guard isKeyWindow, let spaceID = menuBarHiddenSpaceID, let screen = screen else {
return
}
let location = NSEvent.mouseLocation
if !isMenuBarRevealAllowed && location.y >= screen.frame.maxY - 1 {
isMenuBarRevealAllowed = true
} else if isMenuBarRevealAllowed && location.y < screen.frame.maxY - screen.safeAreaInsets.top && !MenuBarReveal.state(inSpace: spaceID).isMenuBarRevealed {
// the pointer left the top without the menu bar being revealed
isMenuBarRevealAllowed = false
}
}
private func applyMenuBarReveal() {
guard let spaceID = menuBarHiddenSpaceID else {
return
}
let reveal = MenuBarReveal.state(inSpace: spaceID)
SkyLight.shared?.setMenuBarAlpha(reveal.isMenuBarRevealed ? 1 : 0, inSpace: spaceID)
isFullScreenToolbarHidden = !reveal.isToolbarRevealed
}
/// AppKit shows the full screen toolbar window some time after we have entered full screen.
@objc private func otherWindowDidChangeOcclusionState(_ notification: Notification) {
if menuBarHiddenSpaceID != nil, let window = notification.object as? NSWindow, window === fullScreenToolbarWindow {
applyMenuBarReveal()
}
}
@objc private func menuBarRevealDidChange(_ notification: Notification) {
guard let spaceID = menuBarHiddenSpaceID,
let userInfo = notification.userInfo,
userInfo[MenuBarReveal.spaceIDKey] as? UInt64 == spaceID,
let duration = userInfo[MenuBarReveal.durationKey] as? TimeInterval else {
return
}
let reveal = MenuBarReveal.state(inSpace: spaceID)
if reveal.isMenuBarRevealed || reveal.isToolbarRevealed {
applyMenuBarReveal()
}
if !reveal.isMenuBarRevealed || !reveal.isToolbarRevealed {
// they are animated out, do not show our content until they are gone
DispatchQueue.main.asyncAfter(deadline: .now() + duration) { [weak self] in
guard let self = self, self.menuBarHiddenSpaceID == spaceID else {
return
}
self.applyMenuBarReveal()
if !MenuBarReveal.state(inSpace: spaceID).isMenuBarRevealed {
self.isMenuBarRevealAllowed = false
}
}
}
}
}
/// Replaces the frame AppKit uses for a window in full screen, installed the first time it is needed.
private enum FullScreenFrameHook {
private typealias FrameFunction = @convention(c) (NSWindow, Selector) -> NSRect
private typealias FrameBlock = @convention(block) (VMDisplayWindow) -> NSRect
private static let frameTypeEncoding = "{CGRect={CGPoint=dd}{CGSize=dd}}16@0:8"
private static let frameForFullScreenModeSelector = NSSelectorFromString("_frameForFullScreenMode")
private static let tileFrameForFullScreenSelector = NSSelectorFromString("_tileFrameForFullScreen")
private static var frameForFullScreenMode: FrameFunction?
private static var tileFrameForFullScreen: FrameFunction?
static let isInstalled: Bool = {
func frameFunction(for selector: Selector) -> FrameFunction? {
guard let method = class_getInstanceMethod(NSWindow.self, selector),
let types = method_getTypeEncoding(method), String(cString: types) == frameTypeEncoding else {
logger.debug("cannot use \(NSStringFromSelector(selector))")
return nil
}
return unsafeBitCast(method_getImplementation(method), to: FrameFunction.self)
}
guard let appKitFrameForFullScreenMode = frameFunction(for: frameForFullScreenModeSelector),
let appKitTileFrameForFullScreen = frameFunction(for: tileFrameForFullScreenSelector) else {
return false
}
let selector = frameForFullScreenModeSelector
let block: FrameBlock = { window in
window.fullScreenFrame(forAppKitFrame: appKitFrameForFullScreenMode(window, selector))
}
guard class_addMethod(VMDisplayWindow.self, selector, imp_implementationWithBlock(block), frameTypeEncoding) else {
return false
}
frameForFullScreenMode = appKitFrameForFullScreenMode
tileFrameForFullScreen = appKitTileFrameForFullScreen
return true
}()
static func appKitFrame(for window: NSWindow) -> NSRect {
frameForFullScreenMode?(window, frameForFullScreenModeSelector) ?? window.frame
}
static func tileFrame(for window: NSWindow) -> NSRect? {
tileFrameForFullScreen?(window, tileFrameForFullScreenSelector)
}
}
/// Private window server functions, resolved at runtime.
private struct SkyLight {
private typealias MainConnectionIDFunction = @convention(c) () -> Int32
private typealias CopySpacesForWindowsFunction = @convention(c) (Int32, Int32, CFArray) -> Unmanaged<CFArray>?
private typealias SpaceGetTypeFunction = @convention(c) (Int32, UInt64) -> Int32
private typealias TransactionCreateFunction = @convention(c) (Int32) -> Unmanaged<CFTypeRef>?
private typealias TransactionSetMenuBarSystemOverrideAlphaFunction = @convention(c) (CFTypeRef, UInt64, Float) -> Void
private typealias TransactionCommitFunction = @convention(c) (CFTypeRef, Int32) -> Int32
private let mainConnectionID: MainConnectionIDFunction
private let copySpacesForWindows: CopySpacesForWindowsFunction
private let spaceGetType: SpaceGetTypeFunction
private let transactionCreate: TransactionCreateFunction
private let transactionSetMenuBarSystemOverrideAlpha: TransactionSetMenuBarSystemOverrideAlphaFunction
private let transactionCommit: TransactionCommitFunction
static let shared: SkyLight? = {
guard let handle = dlopen("/System/Library/PrivateFrameworks/SkyLight.framework/SkyLight", RTLD_LAZY) else {
logger.debug("SkyLight is not available")
return nil
}
return SkyLight(handle: handle)
}()
private init?(handle: UnsafeMutableRawPointer) {
func symbol<T>(_ name: String) -> T? {
guard let symbol = dlsym(handle, name) else {
logger.debug("SkyLight is missing \(name)")
return nil
}
return unsafeBitCast(symbol, to: T.self)
}
guard let mainConnectionID: MainConnectionIDFunction = symbol("SLSMainConnectionID"),
let copySpacesForWindows: CopySpacesForWindowsFunction = symbol("SLSCopySpacesForWindows"),
let spaceGetType: SpaceGetTypeFunction = symbol("SLSSpaceGetType"),
let transactionCreate: TransactionCreateFunction = symbol("SLSTransactionCreate"),
let transactionSetMenuBarSystemOverrideAlpha: TransactionSetMenuBarSystemOverrideAlphaFunction = symbol("SLSTransactionSetMenuBarSystemOverrideAlpha"),
let transactionCommit: TransactionCommitFunction = symbol("SLSTransactionCommit") else {
return nil
}
self.mainConnectionID = mainConnectionID
self.copySpacesForWindows = copySpacesForWindows
self.spaceGetType = spaceGetType
self.transactionCreate = transactionCreate
self.transactionSetMenuBarSystemOverrideAlpha = transactionSetMenuBarSystemOverrideAlpha
self.transactionCommit = transactionCommit
}
/// - Returns: Space that the window is in, if it is in exactly one
func spaceID(for window: NSWindow) -> UInt64? {
let allSpacesMask: Int32 = 7
let windows = [NSNumber(value: window.windowNumber)] as CFArray
guard let spaces = copySpacesForWindows(mainConnectionID(), allSpacesMask, windows)?.takeRetainedValue() as? [NSNumber],
spaces.count == 1 else {
return nil
}
return spaces[0].uint64Value
}
/// - Returns: Space that the window is in, if that is a full screen space
func fullScreenSpaceID(for window: NSWindow) -> UInt64? {
let fullScreenSpaceType: Int32 = 4
guard let spaceID = spaceID(for: window), spaceGetType(mainConnectionID(), spaceID) == fullScreenSpaceType else {
return nil
}
return spaceID
}
/// The override only exists for the lifetime of the space, which for full screen is until the window leaves it.
func setMenuBarAlpha(_ alpha: Float, inSpace spaceID: UInt64) {
guard let transaction = transactionCreate(mainConnectionID())?.takeRetainedValue() else {
return
}
transactionSetMenuBarSystemOverrideAlpha(transaction, spaceID, alpha)
_ = transactionCommit(transaction, 1)
}
}
/// Observes AppKit being told to reveal or hide the menu bar in a full screen space.
private enum MenuBarReveal {
static let didChangeNotification = Notification.Name("VMDisplayWindowMenuBarRevealDidChange")
static let spaceIDKey = "SpaceID"
static let durationKey = "Duration"
private typealias DispatchRevealChangedFunction = @convention(c) (AnyClass, Selector, UInt64, Double, Double, Double) -> Void
private typealias DispatchRevealChangedBlock = @convention(block) (AnyClass, UInt64, Double, Double, Double) -> Void
struct State {
var isMenuBarRevealed: Bool = false
var isToolbarRevealed: Bool = false
}
private static var states = [UInt64: State]()
static let isObserving: Bool = {
let selector = NSSelectorFromString("_dispatchAgentRevealChangedForSpaceID:menuBarRevealTarget:toolbarRevealTarget:duration:")
guard let method = class_getClassMethod(NSMenu.self, selector),
let types = method_getTypeEncoding(method), String(cString: types) == "v48@0:8q16d24d32d40" else {
logger.debug("cannot observe menu bar reveal")
return false
}
let original = unsafeBitCast(method_getImplementation(method), to: DispatchRevealChangedFunction.self)
let block: DispatchRevealChangedBlock = { cls, spaceID, menuBarRevealTarget, toolbarRevealTarget, duration in
original(cls, selector, spaceID, menuBarRevealTarget, toolbarRevealTarget, duration)
let update = {
let state = State(isMenuBarRevealed: menuBarRevealTarget > 0, isToolbarRevealed: toolbarRevealTarget > 0)
states[spaceID] = state.isMenuBarRevealed || state.isToolbarRevealed ? state : nil
NotificationCenter.default.post(name: didChangeNotification, object: nil, userInfo: [spaceIDKey: spaceID, durationKey: duration])
}
if Thread.isMainThread {
update()
} else {
DispatchQueue.main.async(execute: update)
}
}
method_setImplementation(method, imp_implementationWithBlock(block))
return true
}()
static func state(inSpace spaceID: UInt64) -> State {
states[spaceID] ?? State()
}
}
+6
View File
@@ -198,6 +198,7 @@ struct ApplicationSettingsView: View {
struct DisplaySettingsView: View {
@AppStorage("NoScreenshot") var isNoScreenshot = false
@AppStorage("NoSaveScreenshot") var isNoSaveScreenshot = false
@AppStorage("FullScreenUseCameraHousingArea") var isFullScreenUseCameraHousingArea = false
@AppStorage("QEMURendererBackend") var qemuRendererBackend: UTMQEMURendererBackend = .qemuRendererBackendDefault
@AppStorage("QEMUVulkanDriver") var qemuVulkanDriver: UTMQEMUVulkanDriver = .qemuVulkanDriverDefault
@AppStorage("QEMUDirectXDriver") var qemuDirectXDriver: UTMQEMUDirectXDriver = .qemuDirectXDriverDefault
@@ -237,6 +238,11 @@ struct DisplaySettingsView: View {
Text("Do not save VM screenshot to disk")
}.help("If enabled, any existing screenshot will be deleted the next time the VM is started.")
.disabled(isNoScreenshot)
if #available(macOS 27, *) {
Toggle(isOn: $isFullScreenUseCameraHousingArea) {
Text("Fill the area beside the camera housing in full screen")
}.help("If enabled, a full screen VM display will use the entire screen including the area beside the built-in camera. The menu bar will cover this area while it is revealed.")
}
}
Section(header: Text("QEMU Graphics Acceleration")) {
+4
View File
@@ -653,6 +653,7 @@
CE611BEB29F50D3E001817BC /* VMReleaseNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE611BEA29F50D3E001817BC /* VMReleaseNotesView.swift */; };
CE611BEC29F50D3E001817BC /* VMReleaseNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE611BEA29F50D3E001817BC /* VMReleaseNotesView.swift */; };
CE611BED29F50D3E001817BC /* VMReleaseNotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE611BEA29F50D3E001817BC /* VMReleaseNotesView.swift */; };
CE5A7E112E9F4A1100C0FFEE /* VMDisplayWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5A7E102E9F4A1100C0FFEE /* VMDisplayWindow.swift */; };
CE612AC624D3B50700FA6300 /* VMDisplayWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE612AC524D3B50700FA6300 /* VMDisplayWindowController.swift */; };
CE63B0DB2F0ED4FF00C59D13 /* vulkan_kosmickrisp.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE63B0D72F0ED4FE00C59D13 /* vulkan_kosmickrisp.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CE63B0DD2F0ED4FF00C59D13 /* vulkan.1.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = CE63B0D82F0ED4FE00C59D13 /* vulkan.1.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -2032,6 +2033,7 @@
CE59A7AF2AA69AE400E5FFBD /* UTMScriptingUSBDeviceImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMScriptingUSBDeviceImpl.swift; sourceTree = "<group>"; };
CE611BE629F50CAD001817BC /* UTMReleaseHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTMReleaseHelper.swift; sourceTree = "<group>"; };
CE611BEA29F50D3E001817BC /* VMReleaseNotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMReleaseNotesView.swift; sourceTree = "<group>"; };
CE5A7E102E9F4A1100C0FFEE /* VMDisplayWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMDisplayWindow.swift; sourceTree = "<group>"; };
CE612AC524D3B50700FA6300 /* VMDisplayWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMDisplayWindowController.swift; sourceTree = "<group>"; };
CE63B0D72F0ED4FE00C59D13 /* vulkan_kosmickrisp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = vulkan_kosmickrisp.framework; path = "$(SYSROOT_DIR)/Frameworks/vulkan_kosmickrisp.framework"; sourceTree = "<group>"; };
CE63B0D82F0ED4FE00C59D13 /* vulkan.1.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = vulkan.1.framework; path = "$(SYSROOT_DIR)/Frameworks/vulkan.1.framework"; sourceTree = "<group>"; };
@@ -2650,6 +2652,7 @@
children = (
A1C4F00130C1200000CA9501 /* CapsLockRemapper.swift */,
CE061CDD289E6DC30000351C /* VMDisplayWindow.xib */,
CE5A7E102E9F4A1100C0FFEE /* VMDisplayWindow.swift */,
CE612AC524D3B50700FA6300 /* VMDisplayWindowController.swift */,
84F746B8276FF40900A20C87 /* VMDisplayAppleWindowController.swift */,
845F170A289CB07200944904 /* VMDisplayAppleDisplayWindowController.swift */,
@@ -4174,6 +4177,7 @@
841E997728AA1191003C6CB6 /* UTMRegistry.swift in Sources */,
841E997B28AA119B003C6CB6 /* UTMRegistryEntry.swift in Sources */,
CE2D956424AD4F990059923A /* VMConfigNetworkPortForwardView.swift in Sources */,
CE5A7E112E9F4A1100C0FFEE /* VMDisplayWindow.swift in Sources */,
CE612AC624D3B50700FA6300 /* VMDisplayWindowController.swift in Sources */,
53A0BDD726D79FE40010EDC5 /* SavePanel.swift in Sources */,
843BF82A28441FAF0029D60D /* QEMUConstantGenerated.swift in Sources */,