Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Side by Side Diff: chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm

Issue 2586373003: MacViews: Allow toolkit-views for "Global Error" bubbles. (Closed)
Patch Set: unstage Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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.
4
5 #include "chrome/browser/ui/cocoa/bubble_anchor_helper_views.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #import "base/mac/scoped_nsobject.h"
10 #include "ui/views/bubble/bubble_dialog_delegate.h"
11 #include "ui/views/widget/widget_observer.h"
12
13 @class BubbleAnchorHelperBridge;
14
15 namespace {
16
17 // Self-deleting object that hosts an Objective-C observer class watching for
18 // parent window resizes to reposition a bubble Widget. Deletes itself when the
19 // bubble Widget closes.
20 class BubbleAnchorHelper : public views::WidgetObserver {
21 public:
22 explicit BubbleAnchorHelper(views::BubbleDialogDelegateView* bubble);
23 ~BubbleAnchorHelper() override;
24
25 // Re-positions |bubble_| so that the offset to the parent window at
26 // construction time is preserved.
27 void ReAnchor();
28
29 // WidgetObserver:
30 void OnWidgetDestroying(views::Widget* widget) override;
31
32 private:
33 // Whether offset from the left of the parent window is fixed.
34 bool IsMinXFixed() const {
35 return views::BubbleBorder::is_arrow_on_left(bubble_->arrow());
36 }
37
38 base::scoped_nsobject<BubbleAnchorHelperBridge> bridge_;
39 views::BubbleDialogDelegateView* bubble_;
40 CGFloat horizontal_offset_; // Offset from the left or right.
41 CGFloat vertical_offset_; // Offset from the top.
42
43 DISALLOW_COPY_AND_ASSIGN(BubbleAnchorHelper);
44 };
45
46 } // namespace
47
48 void KeepBubbleAnchored(views::BubbleDialogDelegateView* bubble) {
49 new BubbleAnchorHelper(bubble);
50 }
51
52 // Observes changes to the size of a parent NSWindow and asks |helper| to re-
53 // anchor the bubble.
54 @interface BubbleAnchorHelperBridge : NSObject
55 - (instancetype)initWithAnchorHelper:(BubbleAnchorHelper*)helper
56 parentWindow:(NSWindow*)parentWindow;
57 - (void)clearOwner;
58 @end
59
60 BubbleAnchorHelper::BubbleAnchorHelper(views::BubbleDialogDelegateView* bubble)
61 : bubble_(bubble) {
62 DCHECK(bubble->GetWidget());
63 DCHECK(bubble->parent_window());
64 bubble->GetWidget()->AddObserver(this);
65
66 NSRect parent_frame = [[bubble->parent_window() window] frame];
67 NSRect bubble_frame = [bubble->GetWidget()->GetNativeWindow() frame];
68
69 // Note: when anchored on the right, this doesn't support changes to the
70 // bubble size, just the parent size.
71 horizontal_offset_ =
72 (IsMinXFixed() ? NSMinX(parent_frame) : NSMaxX(parent_frame)) -
73 NSMinX(bubble_frame);
74 vertical_offset_ = NSMaxY(parent_frame) - NSMinY(bubble_frame);
75
76 bridge_.reset([[BubbleAnchorHelperBridge alloc]
77 initWithAnchorHelper:this
78 parentWindow:[bubble->parent_window() window]]);
79 }
80
81 BubbleAnchorHelper::~BubbleAnchorHelper() {
82 [bridge_ clearOwner];
83 }
84
85 void BubbleAnchorHelper::ReAnchor() {
86 NSRect bubble_frame = [bubble_->GetWidget()->GetNativeWindow() frame];
87 NSRect parent_frame = [[bubble_->parent_window() window] frame];
88 if (IsMinXFixed())
89 bubble_frame.origin.x = NSMinX(parent_frame) - horizontal_offset_;
90 else
91 bubble_frame.origin.x = NSMaxX(parent_frame) - horizontal_offset_;
92 bubble_frame.origin.y = NSMaxY(parent_frame) - vertical_offset_;
93 [bubble_->GetWidget()->GetNativeWindow() setFrame:bubble_frame
94 display:YES
95 animate:NO];
96 }
97
98 void BubbleAnchorHelper::OnWidgetDestroying(views::Widget* widget) {
99 widget->RemoveObserver(this);
100 delete this;
101 }
102
103 @implementation BubbleAnchorHelperBridge {
104 BubbleAnchorHelper* owner_;
105 }
106
107 - (instancetype)initWithAnchorHelper:(BubbleAnchorHelper*)helper
Robert Sesek 2017/01/05 19:50:08 If you use the block-based -[NSNotificationCenter
tapted 2017/01/06 00:14:04 Oooh neato. Done.
108 parentWindow:(NSWindow*)parentWindow {
109 if ((self = [super init])) {
110 owner_ = helper;
111 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
112 [center addObserver:self
113 selector:@selector(reAnchor:)
114 name:NSWindowDidEnterFullScreenNotification
115 object:parentWindow];
116 [center addObserver:self
117 selector:@selector(reAnchor:)
118 name:NSWindowDidExitFullScreenNotification
119 object:parentWindow];
120 [center addObserver:self
121 selector:@selector(reAnchor:)
122 name:NSWindowDidResizeNotification
123 object:parentWindow];
124
125 // Also monitor move. Note that for user-initiated window moves this is not
126 // necessary: the bubble's child window status keeps the position pinned to
127 // the parent during the move (which is handy since AppKit doesn't send out
128 // notifications until the move completes). Programmatic -[NSWindow
129 // setFrame:..] calls, however, do not update child window positions for us.
130 [center addObserver:self
131 selector:@selector(reAnchor:)
132 name:NSWindowDidMoveNotification
133 object:parentWindow];
134 }
135 return self;
136 }
137
138 - (void)clearOwner {
139 [[NSNotificationCenter defaultCenter] removeObserver:self];
140 owner_ = nullptr;
141 }
142
143 - (void)reAnchor:(NSNotification*)notification {
144 if (owner_)
145 owner_->ReAnchor();
146 }
147
148 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698