diff --git a/example/gui-linux/main.go b/example/gui-linux/main.go index 5db3f99a..b98bdd71 100644 --- a/example/gui-linux/main.go +++ b/example/gui-linux/main.go @@ -77,6 +77,17 @@ func run(ctx context.Context) error { } }() + go func() { + if !vm.CanStop() { + log.Println("cannot stop vm forcefully") + return + } + time.Sleep(10 * time.Second) + log.Println("calling vm.Stop()") + + vm.Stop() + }() + // cleanup is this function is useful when finished graphic application. cleanup := func() { for i := 1; vm.CanRequestStop(); i++ { diff --git a/virtualization_view.m b/virtualization_view.m index 9fbf6d18..7e20fafd 100644 --- a/virtualization_view.m +++ b/virtualization_view.m @@ -165,11 +165,30 @@ - (instancetype)init @end +API_AVAILABLE(macos(12.0)) +@interface VMStateObserver : NSObject +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; +@end + +@implementation VMStateObserver +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; +{ + if ([keyPath isEqualToString:@"state"]) { + int newState = (int)[change[NSKeyValueChangeNewKey] integerValue]; + if (newState == VZVirtualMachineStateStopped || newState == VZVirtualMachineStateError) { + [NSApp performSelectorOnMainThread:@selector(terminate:) withObject:context waitUntilDone:NO]; + [object removeObserver:self forKeyPath:@"state"]; + } + } +} +@end + @implementation AppDelegate { VZVirtualMachine *_virtualMachine; VZVirtualMachineView *_virtualMachineView; CGFloat _windowWidth; CGFloat _windowHeight; + VMStateObserver *_observer; } - (instancetype)initWithVirtualMachine:(VZVirtualMachine *)virtualMachine @@ -179,6 +198,11 @@ - (instancetype)initWithVirtualMachine:(VZVirtualMachine *)virtualMachine self = [super init]; _virtualMachine = virtualMachine; [_virtualMachine setDelegate:self]; + _observer = [[VMStateObserver alloc] init]; + [virtualMachine addObserver:_observer + forKeyPath:@"state" + options:NSKeyValueObservingOptionNew + context:(void *)self]; // Setup virtual machine view configs VZVirtualMachineView *view = [[[VZVirtualMachineView alloc] init] autorelease];