// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "remoting/host/continue_window.h"
#import <Cocoa/Cocoa.h>
#include <memory>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/sys_string_conversions.h"
#include "remoting/base/string_resources.h"
#include "ui/base/l10n/l10n_util_mac.h"
// Handles the ContinueWindow.
@interface ContinueWindowMacController : NSObject {
@private
NSMutableArray<NSWindow*>* __strong _shades;
NSAlert* __strong _continue_alert;
raw_ptr<remoting::ContinueWindow> _continue_window;
}
- (instancetype)initWithWindow:(remoting::ContinueWindow*)continue_window;
- (void)show;
- (void)hide;
- (void)onCancel:(id)sender;
- (void)onContinue:(id)sender;
@end
namespace remoting {
// A bridge between C++ and ObjC implementations of ContinueWindow.
// Everything important occurs in ContinueWindowMacController.
class ContinueWindowMac : public ContinueWindow {
public:
ContinueWindowMac();
ContinueWindowMac(const ContinueWindowMac&) = delete;
ContinueWindowMac& operator=(const ContinueWindowMac&) = delete;
~ContinueWindowMac() override;
protected:
// ContinueWindow overrides.
void ShowUi() override;
void HideUi() override;
private:
ContinueWindowMacController* __strong controller_;
};
ContinueWindowMac::ContinueWindowMac() = default;
ContinueWindowMac::~ContinueWindowMac() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (controller_) {
HideUi();
}
}
void ContinueWindowMac::ShowUi() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@autoreleasepool {
controller_ = [[ContinueWindowMacController alloc] initWithWindow:this];
[controller_ show];
}
}
void ContinueWindowMac::HideUi() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@autoreleasepool {
[controller_ hide];
controller_ = nil;
}
}
// static
std::unique_ptr<HostWindow> HostWindow::CreateContinueWindow() {
return std::make_unique<ContinueWindowMac>();
}
} // namespace remoting
@implementation ContinueWindowMacController
- (instancetype)initWithWindow:(remoting::ContinueWindow*)continue_window {
if ((self = [super init])) {
_continue_window = continue_window;
}
return self;
}
- (void)show {
// Generate window shade
NSArray* screens = NSScreen.screens;
_shades = [[NSMutableArray alloc] initWithCapacity:screens.count];
for (NSScreen* screen in screens) {
NSWindow* shade =
[[NSWindow alloc] initWithContentRect:screen.frame
styleMask:NSWindowStyleMaskBorderless
backing:NSBackingStoreBuffered
defer:NO
screen:screen];
shade.releasedWhenClosed = NO;
shade.alphaValue = 0.8;
shade.opaque = NO;
shade.backgroundColor = NSColor.blackColor;
// Raise the window shade above just about everything else.
// Leave the dock and menu bar exposed so the user has some basic level
// of control (like they can quit Chromium).
shade.level = NSModalPanelWindowLevel - 1;
[shade orderFront:nil];
[_shades addObject:shade];
}
// Create alert.
_continue_alert = [[NSAlert alloc] init];
_continue_alert.messageText = l10n_util::GetNSString(IDS_CONTINUE_PROMPT);
NSButton* continue_button = [_continue_alert
addButtonWithTitle:l10n_util::GetNSString(IDS_CONTINUE_BUTTON)];
continue_button.action = @selector(onContinue:);
continue_button.target = self;
NSButton* cancel_button = [_continue_alert
addButtonWithTitle:l10n_util::GetNSString(IDS_STOP_SHARING_BUTTON)];
cancel_button.action = @selector(onCancel:);
cancel_button.target = self;
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* imagePath = [bundle pathForResource:@"chromoting128" ofType:@"png"];
NSImage* image = [[NSImage alloc] initByReferencingFile:imagePath];
_continue_alert.icon = image;
[_continue_alert layout];
// Force alert to be at the proper level and location.
NSWindow* continue_window = _continue_alert.window;
[continue_window center];
continue_window.level = NSModalPanelWindowLevel;
[continue_window orderWindow:NSWindowAbove
relativeTo:_shades.lastObject.windowNumber];
[continue_window makeKeyWindow];
}
- (void)hide {
// Remove window shade.
for (NSWindow* window in _shades) {
[window close];
}
_shades = nil;
if (_continue_alert) {
[_continue_alert.window close];
_continue_alert = nil;
}
}
- (void)onCancel:(id)sender {
[self hide];
_continue_window->DisconnectSession();
}
- (void)onContinue:(id)sender {
[self hide];
_continue_window->ContinueSession();
}
@end