// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ui/base/test/windowed_nsnotification_observer.h"
#import <Cocoa/Cocoa.h>
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#import "base/task/single_thread_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/test_timeouts.h"
@interface WindowedNSNotificationObserver ()
- (void)onNotification:(NSNotification*)notification;
@end
@implementation WindowedNSNotificationObserver {
NSString* __strong _bundleId;
int _notificationCount;
raw_ptr<base::RunLoop> _runLoop;
}
@synthesize notificationCount = _notificationCount;
- (instancetype)initForNotification:(NSString*)name {
return [self initForNotification:name object:nil];
}
- (instancetype)initForNotification:(NSString*)name object:(id)sender {
if ((self = [super init])) {
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(onNotification:)
name:name
object:sender];
}
return self;
}
- (instancetype)initForWorkspaceNotification:(NSString*)name
bundleId:(NSString*)bundleId {
if ((self = [super init])) {
_bundleId = [bundleId copy];
[NSWorkspace.sharedWorkspace.notificationCenter
addObserver:self
selector:@selector(onNotification:)
name:name
object:nil];
}
return self;
}
- (void)dealloc {
if (_bundleId)
[NSWorkspace.sharedWorkspace.notificationCenter removeObserver:self];
else
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)onNotification:(NSNotification*)notification {
if (_bundleId) {
NSRunningApplication* application =
[notification userInfo][NSWorkspaceApplicationKey];
if (![application.bundleIdentifier isEqualToString:_bundleId]) {
return;
}
}
++_notificationCount;
if (_runLoop)
_runLoop->Quit();
}
- (BOOL)waitForCount:(int)minimumCount {
while (_notificationCount < minimumCount) {
const int oldCount = _notificationCount;
base::RunLoop runLoop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, runLoop.QuitClosure(), TestTimeouts::action_timeout());
_runLoop = &runLoop;
runLoop.Run();
_runLoop = nullptr;
// If there was no new notification, it must have been a timeout.
if (_notificationCount == oldCount)
break;
}
return _notificationCount >= minimumCount;
}
- (BOOL)wait {
return [self waitForCount:1];
}
@end