From 2224ffadba2928333d9e3e4480719adf9fdd0215 Mon Sep 17 00:00:00 2001 From: osy <50960678+osy@users.noreply.github.com> Date: Fri, 27 May 2022 12:06:29 -0700 Subject: [PATCH] CocoaSpice: updated backend --- Managers/UTMSpiceIO.h | 2 +- Managers/UTMSpiceIO.m | 35 +++++++++----- Managers/UTMSpiceIODelegate.h | 16 ++++--- Managers/UTMVirtualMachineDelegate.h | 2 +- Platform/iOS/Display/VMCursor.m | 6 +-- .../VMDisplayMetalViewController+Gamepad.m | 2 +- .../VMDisplayMetalViewController+Pointer.m | 2 +- .../VMDisplayMetalViewController+Touch.m | 6 +-- .../Display/VMDisplayMetalViewController.h | 2 +- .../Display/VMDisplayMetalViewController.m | 31 +++++++++--- .../iOS/Display/VMDisplayViewController.m | 12 +++-- .../VMDisplayMetalWindowController.swift | 47 ++++++++++++------- .../VMDisplayQemuDisplayController.swift | 20 ++++++-- .../xcshareddata/swiftpm/Package.resolved | 4 +- 14 files changed, 121 insertions(+), 66 deletions(-) diff --git a/Managers/UTMSpiceIO.h b/Managers/UTMSpiceIO.h index 6abea035..54d093d4 100644 --- a/Managers/UTMSpiceIO.h +++ b/Managers/UTMSpiceIO.h @@ -32,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN @interface UTMSpiceIO : NSObject @property (nonatomic, readonly, nonnull) UTMQemuConfiguration* configuration; -@property (nonatomic, readonly, nullable) CSDisplayMetal *primaryDisplay; +@property (nonatomic, readonly, nullable) CSDisplay *primaryDisplay; @property (nonatomic, readonly, nullable) CSInput *primaryInput; @property (nonatomic, readonly, nullable) CSPort *primarySerial; #if !defined(WITH_QEMU_TCI) diff --git a/Managers/UTMSpiceIO.m b/Managers/UTMSpiceIO.m index 04a47e57..58b0ecda 100644 --- a/Managers/UTMSpiceIO.m +++ b/Managers/UTMSpiceIO.m @@ -29,7 +29,7 @@ extern NSString *const kUTMErrorDomain; @interface UTMSpiceIO () -@property (nonatomic, readwrite, nullable) CSDisplayMetal *primaryDisplay; +@property (nonatomic, readwrite, nullable) CSDisplay *primaryDisplay; @property (nonatomic, readwrite, nullable) CSInput *primaryInput; @property (nonatomic, readwrite, nullable) CSPort *primarySerial; #if !defined(WITH_QEMU_TCI) @@ -147,14 +147,26 @@ extern NSString *const kUTMErrorDomain; - (void)spiceConnected:(CSConnection *)connection { NSAssert(connection == self.spiceConnection, @"Unknown connection"); self.isConnected = YES; - self.primaryInput = connection.input; - [self.delegate spiceDidChangeInput:connection.input]; #if !defined(WITH_QEMU_TCI) self.primaryUsbManager = connection.usbManager; [self.delegate spiceDidChangeUsbManager:connection.usbManager]; #endif } +- (void)spiceInputAvailable:(CSConnection *)connection input:(CSInput *)input { + if (self.primaryInput == nil) { + self.primaryInput = input; + [self.delegate spiceDidCreateInput:input]; + } +} + +- (void)spiceInputUnavailable:(CSConnection *)connection input:(CSInput *)input { + if (self.primaryInput == input) { + self.primaryInput = nil; + [self.delegate spiceDidDestroyInput:input]; + } +} + - (void)spiceDisconnected:(CSConnection *)connection { NSAssert(connection == self.spiceConnection, @"Unknown connection"); self.isConnected = NO; @@ -171,15 +183,17 @@ extern NSString *const kUTMErrorDomain; }); } -- (void)spiceDisplayCreated:(CSConnection *)connection display:(CSDisplayMetal *)display { +- (void)spiceDisplayCreatedOrUpdated:(CSConnection *)connection display:(CSDisplay *)display { NSAssert(connection == self.spiceConnection, @"Unknown connection"); - [self.delegate spiceDidCreateDisplay:display]; - if (display.isPrimaryDisplay) { + if (self.primaryDisplay == display) { + [self.delegate spiceDidChangeDisplay:display]; + } else if (display.isPrimaryDisplay) { self.primaryDisplay = display; + [self.delegate spiceDidCreateDisplay:display]; } } -- (void)spiceDisplayDestroyed:(CSConnection *)connection display:(CSDisplayMetal *)display { +- (void)spiceDisplayDestroyed:(CSConnection *)connection display:(CSDisplay *)display { NSAssert(connection == self.spiceConnection, @"Unknown connection"); [self.delegate spiceDidDestroyDisplay:display]; } @@ -248,16 +262,11 @@ extern NSString *const kUTMErrorDomain; _delegate = delegate; // make sure to send initial data if (self.primaryInput) { - [self.delegate spiceDidChangeInput:self.primaryInput]; + [self.delegate spiceDidCreateInput:self.primaryInput]; } if (self.primaryDisplay) { [self.delegate spiceDidCreateDisplay:self.primaryDisplay]; } - for (CSDisplayMetal *display in self.spiceConnection.monitors) { - if (display != self.primaryDisplay) { - [self.delegate spiceDidCreateDisplay:display]; - } - } if (self.primarySerial) { [self.delegate spiceDidCreateSerial:self.primarySerial]; } diff --git a/Managers/UTMSpiceIODelegate.h b/Managers/UTMSpiceIODelegate.h index af9eddc0..de997ba4 100644 --- a/Managers/UTMSpiceIODelegate.h +++ b/Managers/UTMSpiceIODelegate.h @@ -16,7 +16,7 @@ #import -@class CSDisplayMetal; +@class CSDisplay; @class CSInput; @class CSPort; @class CSUSBManager; @@ -25,13 +25,15 @@ NS_ASSUME_NONNULL_BEGIN @protocol UTMSpiceIODelegate -- (void)spiceDidChangeInput:(CSInput *)input; -- (void)spiceDidCreateDisplay:(CSDisplayMetal *)display; -- (void)spiceDidDestroyDisplay:(CSDisplayMetal *)display; -- (void)spiceDidCreateSerial:(CSPort *)serial; -- (void)spiceDidDestroySerial:(CSPort *)serial; +- (void)spiceDidCreateInput:(CSInput *)input NS_SWIFT_NAME(spiceDidCreateInput(_:)); +- (void)spiceDidDestroyInput:(CSInput *)input NS_SWIFT_NAME(spiceDidDestroyInput(_:)); +- (void)spiceDidCreateDisplay:(CSDisplay *)display NS_SWIFT_NAME(spiceDidCreateDisplay(_:)); +- (void)spiceDidDestroyDisplay:(CSDisplay *)display NS_SWIFT_NAME(spiceDidDestroyDisplay(_:)); +- (void)spiceDidChangeDisplay:(CSDisplay *)display NS_SWIFT_NAME(spiceDidChangeDisplay(_:)); +- (void)spiceDidCreateSerial:(CSPort *)serial NS_SWIFT_NAME(spiceDidCreateSerial(_:)); +- (void)spiceDidDestroySerial:(CSPort *)serial NS_SWIFT_NAME(spiceDidDestroySerial(_:)); #if !defined(WITH_QEMU_TCI) -- (void)spiceDidChangeUsbManager:(CSUSBManager *)usbManager; +- (void)spiceDidChangeUsbManager:(nullable CSUSBManager *)usbManager NS_SWIFT_NAME(spiceDidChangeUsbManager(_:)); #endif @optional diff --git a/Managers/UTMVirtualMachineDelegate.h b/Managers/UTMVirtualMachineDelegate.h index f11fdb8e..fb28b0b3 100644 --- a/Managers/UTMVirtualMachineDelegate.h +++ b/Managers/UTMVirtualMachineDelegate.h @@ -16,7 +16,7 @@ @protocol UTMConfigurable; @class UTMVirtualMachine; -@class CSDisplayMetal; +@class CSDisplay; @class CSInput; NS_ASSUME_NONNULL_BEGIN diff --git a/Platform/iOS/Display/VMCursor.m b/Platform/iOS/Display/VMCursor.m index 3bce598c..fed24dae 100644 --- a/Platform/iOS/Display/VMCursor.m +++ b/Platform/iOS/Display/VMCursor.m @@ -16,7 +16,7 @@ #import "VMCursor.h" #import "VMDisplayMetalViewController+Touch.h" -#import "CSDisplayMetal.h" +#import "CSDisplay.h" @interface VMCursor () @@ -64,8 +64,8 @@ - (CGRect)bounds { CGRect bounds = CGRectZero; - bounds.size.width = MAX(1, _controller.vmDisplay.cursorSize.width); - bounds.size.height = MAX(1, _controller.vmDisplay.cursorSize.height); + bounds.size.width = MAX(1, _controller.vmDisplay.cursor.cursorSize.width); + bounds.size.height = MAX(1, _controller.vmDisplay.cursor.cursorSize.height); return bounds; } diff --git a/Platform/iOS/Display/VMDisplayMetalViewController+Gamepad.m b/Platform/iOS/Display/VMDisplayMetalViewController+Gamepad.m index a3945b17..7fec42f1 100644 --- a/Platform/iOS/Display/VMDisplayMetalViewController+Gamepad.m +++ b/Platform/iOS/Display/VMDisplayMetalViewController+Gamepad.m @@ -19,7 +19,7 @@ #import "VMScroll.h" #import "VMDisplayMetalViewController+Gamepad.h" #import "VMDisplayMetalViewController+Touch.h" -#import "CSDisplayMetal.h" +#import "CSDisplay.h" #import "UTMQemuConfiguration.h" #import "UTMQemuConfiguration+Constants.h" #import "UTMLogging.h" diff --git a/Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m b/Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m index a04c91f5..c7cfc0ea 100644 --- a/Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m +++ b/Platform/iOS/Display/VMDisplayMetalViewController+Pointer.m @@ -20,7 +20,7 @@ #import "VMDisplayMetalViewController+Touch.h" #import "VMDisplayMetalViewController+Pointer.h" #import "VMCursor.h" -#import "CSDisplayMetal.h" +#import "CSDisplay.h" #import "VMScroll.h" #import "UTMQemuVirtualMachine.h" #import "UTMQemuVirtualMachine+SPICE.h" diff --git a/Platform/iOS/Display/VMDisplayMetalViewController+Touch.m b/Platform/iOS/Display/VMDisplayMetalViewController+Touch.m index b978e3c4..82ac6a4b 100644 --- a/Platform/iOS/Display/VMDisplayMetalViewController+Touch.m +++ b/Platform/iOS/Display/VMDisplayMetalViewController+Touch.m @@ -20,7 +20,7 @@ #import "VMDisplayMetalViewController+Pencil.h" #import "VMCursor.h" #import "VMScroll.h" -#import "CSDisplayMetal.h" +#import "CSDisplay.h" #import "UTMQemuConfiguration.h" #import "UTMQemuConfiguration+Miscellaneous.h" #import "UTMSpiceIO.h" @@ -353,7 +353,7 @@ static CGFloat CGPointToPixel(CGFloat point) { translated = [self clipCursorToDisplay:translated]; if (!self.vmInput.serverModeCursor) { [self.vmInput sendMousePosition:self.mouseButtonDown absolutePoint:translated]; - [self.vmDisplay forceCursorPosition:translated]; // required to show cursor on screen + [self.vmDisplay.cursor moveTo:translated]; // required to show cursor on screen } else { UTMLog(@"Warning: ignored mouse set (%f, %f) while mouse is in server mode", translated.x, translated.y); } @@ -625,7 +625,7 @@ static CGFloat CGPointToPixel(CGFloat point) { - (BOOL)switchMouseType:(VMMouseType)type { BOOL shouldHideCursor = (type == VMMouseTypeAbsoluteHideCursor); BOOL shouldUseServerMouse = (type == VMMouseTypeRelative); - self.vmDisplay.inhibitCursor = shouldHideCursor; + self.vmDisplay.cursor.isInhibited = shouldHideCursor; if (shouldUseServerMouse != self.vmInput.serverModeCursor) { UTMLog(@"Switching mouse mode to server:%d for type:%ld", shouldUseServerMouse, type); [self.vm requestInputTablet:!shouldUseServerMouse]; diff --git a/Platform/iOS/Display/VMDisplayMetalViewController.h b/Platform/iOS/Display/VMDisplayMetalViewController.h index b0ab283e..da190972 100644 --- a/Platform/iOS/Display/VMDisplayMetalViewController.h +++ b/Platform/iOS/Display/VMDisplayMetalViewController.h @@ -64,7 +64,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) IBOutlet VMKeyboardView *keyboardView; @property (weak, nonatomic) CSInput *vmInput; -@property (weak, nonatomic) CSDisplayMetal *vmDisplay; +@property (weak, nonatomic) CSDisplay *vmDisplay; @property (nonatomic, readonly) BOOL serverModeCursor; diff --git a/Platform/iOS/Display/VMDisplayMetalViewController.m b/Platform/iOS/Display/VMDisplayMetalViewController.m index e9363094..4fdae8c9 100644 --- a/Platform/iOS/Display/VMDisplayMetalViewController.m +++ b/Platform/iOS/Display/VMDisplayMetalViewController.m @@ -26,7 +26,7 @@ #import "UTMQemuConfiguration.h" #import "UTMQemuConfiguration+Display.h" #import "UTMLogging.h" -#import "CSDisplayMetal.h" +#import "CSDisplay.h" #import "UTM-Swift.h" @import CocoaSpiceRenderer; @@ -200,12 +200,20 @@ #pragma mark - SPICE IO Delegates -- (void)spiceDidChangeInput:(CSInput *)input { - self.vmInput = input; +- (void)spiceDidCreateInput:(CSInput *)input { + if (self.vmInput == nil) { + self.vmInput = input; + } } -- (void)spiceDidCreateDisplay:(CSDisplayMetal *)display { - if (display.isPrimaryDisplay) { +- (void)spiceDidDestroyInput:(CSInput *)input { + if (self.vmInput == input) { + self.vmInput = nil; + } +} + +- (void)spiceDidCreateDisplay:(CSDisplay *)display { + if (self.vmDisplay == nil && display.isPrimaryDisplay) { self.vmDisplay = display; _renderer.source = display; // restore last size @@ -224,8 +232,17 @@ } } -- (void)spiceDidDestroyDisplay:(CSDisplayMetal *)display { - // TODO: implement something here +- (void)spiceDidDestroyDisplay:(CSDisplay *)display { + if (self.vmDisplay == display) { + self.vmDisplay = nil; + _renderer.source = nil; + } +} + +- (void)spiceDidChangeDisplay:(CSDisplay *)display { + if (display == self.vmDisplay) { + + } } @end diff --git a/Platform/iOS/Display/VMDisplayViewController.m b/Platform/iOS/Display/VMDisplayViewController.m index 7e6845f9..b1e03d0b 100644 --- a/Platform/iOS/Display/VMDisplayViewController.m +++ b/Platform/iOS/Display/VMDisplayViewController.m @@ -99,13 +99,19 @@ #pragma mark - SPICE IO Delegates -- (void)spiceDidChangeInput:(CSInput *)input { +- (void)spiceDidCreateInput:(CSInput *)input { } -- (void)spiceDidCreateDisplay:(CSDisplayMetal *)display { +- (void)spiceDidDestroyInput:(CSInput *)input { } -- (void)spiceDidDestroyDisplay:(CSDisplayMetal *)display { +- (void)spiceDidCreateDisplay:(CSDisplay *)display { +} + +- (void)spiceDidChangeDisplay:(CSDisplay *)display { +} + +- (void)spiceDidDestroyDisplay:(CSDisplay *)display { } - (void)spiceDidCreateSerial:(CSPort *)serial { diff --git a/Platform/macOS/Display/VMDisplayMetalWindowController.swift b/Platform/macOS/Display/VMDisplayMetalWindowController.swift index 027dbe53..ea3f8de4 100644 --- a/Platform/macOS/Display/VMDisplayMetalWindowController.swift +++ b/Platform/macOS/Display/VMDisplayMetalWindowController.swift @@ -20,10 +20,9 @@ class VMDisplayMetalWindowController: VMDisplayQemuWindowController { var metalView: VMMetalView! var renderer: CSRenderer? - private weak var vmDisplay: CSDisplayMetal? + private weak var vmDisplay: CSDisplay? private weak var vmInput: CSInput? - private var displaySizeObserver: NSKeyValueObservation? private var displaySize: CGSize = .zero private var isDisplaySizeDynamic: Bool = false private var isFullScreen: Bool = false @@ -77,10 +76,6 @@ class VMDisplayMetalWindowController: VMDisplayQemuWindowController { override func enterLive() { metalView.isHidden = false screenshotView.isHidden = true - displaySizeObserver = observe(\.vmDisplay!.displaySize, options: [.initial, .new]) { (_, change) in - guard let size = change.newValue else { return } - self.displaySizeDidChange(size: size) - } if vmQemuConfig!.shareClipboardEnabled { UTMPasteboard.general.requestPollingMode(forHashable: self) // start clipboard polling } @@ -121,7 +116,6 @@ class VMDisplayMetalWindowController: VMDisplayQemuWindowController { self.globalEventMonitor = nil } releaseMouse() - displaySizeObserver = nil super.enterSuspended(isBusy: busy) } @@ -132,19 +126,36 @@ class VMDisplayMetalWindowController: VMDisplayQemuWindowController { // MARK: - SPICE IO extension VMDisplayMetalWindowController { - override func spiceDidChange(_ input: CSInput) { - vmInput = input - } - - override func spiceDidCreateDisplay(_ display: CSDisplayMetal) { - if display.isPrimaryDisplay { - vmDisplay = display - renderer!.source = vmDisplay + override func spiceDidCreateInput(_ input: CSInput) { + if vmInput == nil { + vmInput = input } } - override func spiceDidDestroyDisplay(_ display: CSDisplayMetal) { - //TODO: implement something here + override func spiceDidDestroyInput(_ input: CSInput) { + if vmInput == input { + vmInput = nil + } + } + + override func spiceDidCreateDisplay(_ display: CSDisplay) { + if vmDisplay == nil && display.isPrimaryDisplay { + vmDisplay = display + renderer!.source = display + } + } + + override func spiceDidDestroyDisplay(_ display: CSDisplay) { + if vmDisplay == display { + vmDisplay = nil + renderer!.source = nil + } + } + + override func spiceDidChangeDisplay(_ display: CSDisplay) { + if vmDisplay == display { + displaySizeDidChange(size: display.displaySize) + } } override func spiceDynamicResolutionSupportDidChange(_ supported: Bool) { @@ -345,7 +356,7 @@ extension VMDisplayMetalWindowController: VMMetalViewInputDelegate { let point = CGPoint(x: newX, y: newY) logger.trace("move cursor: cocoa (\(absolutePoint.x), \(absolutePoint.y)), native (\(newX), \(newY))") vmInput.sendMousePosition(button, absolutePoint: point) - vmDisplay?.forceCursorPosition(point) // required to show cursor on screen + vmDisplay?.cursor?.move(to: point) // required to show cursor on screen } func mouseMove(relativePoint: CGPoint, button: CSInputButton) { diff --git a/Platform/macOS/Display/VMDisplayQemuDisplayController.swift b/Platform/macOS/Display/VMDisplayQemuDisplayController.swift index f1409e3d..956236bd 100644 --- a/Platform/macOS/Display/VMDisplayQemuDisplayController.swift +++ b/Platform/macOS/Display/VMDisplayQemuDisplayController.swift @@ -208,24 +208,34 @@ extension VMDisplayQemuWindowController { // MARK: - SPICE base implementation extension VMDisplayQemuWindowController: UTMSpiceIODelegate { - func spiceDidChange(_ input: CSInput) { + func spiceDidCreateInput(_ input: CSInput) { // Implemented in subclass } - func spiceDidCreateDisplay(_ display: CSDisplayMetal) { + func spiceDidDestroyInput(_ input: CSInput) { // Implemented in subclass } - func spiceDidDestroyDisplay(_ display: CSDisplayMetal) { + func spiceDidCreateDisplay(_ display: CSDisplay) { // Implemented in subclass } - func spiceDidChange(_ usbManager: CSUSBManager) { + func spiceDidChangeDisplay(_ display: CSDisplay) { + // Implemented in subclass + } + + func spiceDidDestroyDisplay(_ display: CSDisplay) { + // Implemented in subclass + } + + func spiceDidChangeUsbManager(_ usbManager: CSUSBManager?) { if usbManager != vmUsbManager { connectedUsbDevices.removeAll() allUsbDevices.removeAll() vmUsbManager = usbManager - usbManager.delegate = self + if let usbManager = usbManager { + usbManager.delegate = self + } } } diff --git a/UTM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/UTM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d72dfe44..e1e6b0a3 100644 --- a/UTM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/UTM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,7 +15,7 @@ "repositoryURL": "https://github.com/utmapp/CocoaSpice.git", "state": { "branch": "main", - "revision": "6a210bc6dd50d12bd57f990bd4d062d0fd93d529", + "revision": "5070355c1ca5706c50bd74e8d65f89debd7bf8a0", "version": null } }, @@ -58,4 +58,4 @@ ] }, "version": 1 -} \ No newline at end of file +}