1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/logging.h"
10 #include "ui/gfx/geometry/rect.h"
11 #include "ui/gfx/geometry/vector2d.h"
12 #import "ui/gfx/mac/coordinate_conversion.h"
13 #import "ui/views/cocoa/bridged_native_widget.h"
15 // Bridges an AppKit observer to observe when the (non-views) NSWindow owning a
16 // views::Widget will close.
17 @interface WidgetOwnerNSWindowAdapterBridge : NSObject {
19 views::WidgetOwnerNSWindowAdapter* adapter_; // Weak. Owns us.
21 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter;
22 - (void)windowWillClose:(NSNotification*)notification;
25 @implementation WidgetOwnerNSWindowAdapterBridge
27 - (instancetype)initWithAdapter:(views::WidgetOwnerNSWindowAdapter*)adapter {
28 if ((self = [super init]))
33 - (void)windowWillClose:(NSNotification*)notification {
34 adapter_->OnWindowWillClose();
41 WidgetOwnerNSWindowAdapter::WidgetOwnerNSWindowAdapter(
42 BridgedNativeWidget* child,
45 anchor_view_([anchor_view retain]),
47 [[WidgetOwnerNSWindowAdapterBridge alloc] initWithAdapter:this]) {
49 // Although the |anchor_view| must be in an NSWindow when the child dialog is
50 // created, it's permitted for the |anchor_view| to be removed from its view
51 // hierarchy before the child dialog window is fully removed from screen. When
52 // this happens, [anchor_view_ window] will become nil, so retain both.
53 anchor_window_.reset([[anchor_view_ window] retain]);
54 DCHECK(anchor_window_);
56 [[NSNotificationCenter defaultCenter]
57 addObserver:observer_bridge_
58 selector:@selector(windowWillClose:)
59 name:NSWindowWillCloseNotification
60 object:anchor_window_];
63 void WidgetOwnerNSWindowAdapter::OnWindowWillClose() {
64 [child_->ns_window() close];
65 // Note: |this| will be deleted here.
68 NSWindow* WidgetOwnerNSWindowAdapter::GetNSWindow() {
69 return anchor_window_;
72 gfx::Vector2d WidgetOwnerNSWindowAdapter::GetChildWindowOffset() const {
73 NSRect rect_in_window =
74 [anchor_view_ convertRect:[anchor_view_ bounds] toView:nil];
75 // Ensure we anchor off the top-left of |anchor_view_| (rect_in_window.origin
76 // is the bottom-left of the view).
77 // TODO(tapted): Use -[NSWindow convertRectToScreen:] when we ditch 10.6.
78 NSRect rect_in_screen = NSZeroRect;
79 rect_in_screen.origin =
80 [anchor_window_ convertBaseToScreen:NSMakePoint(NSMinX(rect_in_window),
81 NSMaxY(rect_in_window))];
82 return gfx::ScreenRectFromNSRect(rect_in_screen).OffsetFromOrigin();
85 bool WidgetOwnerNSWindowAdapter::IsVisibleParent() const {
86 return [anchor_window_ isVisible];
89 void WidgetOwnerNSWindowAdapter::RemoveChildWindow(BridgedNativeWidget* child) {
90 DCHECK_EQ(child, child_);
91 [GetNSWindow() removeChildWindow:child->ns_window()];
95 WidgetOwnerNSWindowAdapter::~WidgetOwnerNSWindowAdapter() {
96 [[NSNotificationCenter defaultCenter] removeObserver:observer_bridge_];