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

Unified Diff: chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm

Issue 2586373003: MacViews: Allow toolkit-views for "Global Error" bubbles. (Closed)
Patch Set: addObserverForName 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm b/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
new file mode 100644
index 0000000000000000000000000000000000000000..fae302ed9a08ee6ed24f19e951e183453b4b5c3e
--- /dev/null
+++ b/chrome/browser/ui/cocoa/bubble_anchor_helper_views.mm
@@ -0,0 +1,109 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/cocoa/bubble_anchor_helper_views.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/widget/widget_observer.h"
+
+namespace {
+
+// Self-deleting object that hosts Objective-C observers watching for parent
+// window resizes to reposition a bubble Widget. Deletes itself when the bubble
+// Widget closes.
+class BubbleAnchorHelper : public views::WidgetObserver {
+ public:
+ explicit BubbleAnchorHelper(views::BubbleDialogDelegateView* bubble);
+
+ private:
+ // Observe |name| on the bubble parent window with a block to call ReAnchor().
+ void Observe(NSString* name);
+
+ // Whether offset from the left of the parent window is fixed.
+ bool IsMinXFixed() const {
+ return views::BubbleBorder::is_arrow_on_left(bubble_->arrow());
+ }
+
+ // Re-positions |bubble_| so that the offset to the parent window at
+ // construction time is preserved.
+ void ReAnchor();
+
+ // WidgetObserver:
+ void OnWidgetDestroying(views::Widget* widget) override;
+
+ base::scoped_nsobject<NSMutableArray> observer_tokens_;
+ views::BubbleDialogDelegateView* bubble_;
+ CGFloat horizontal_offset_; // Offset from the left or right.
+ CGFloat vertical_offset_; // Offset from the top.
+
+ DISALLOW_COPY_AND_ASSIGN(BubbleAnchorHelper);
+};
+
+} // namespace
+
+void KeepBubbleAnchored(views::BubbleDialogDelegateView* bubble) {
+ new BubbleAnchorHelper(bubble);
+}
+
+BubbleAnchorHelper::BubbleAnchorHelper(views::BubbleDialogDelegateView* bubble)
+ : observer_tokens_([[NSMutableArray alloc] init]), bubble_(bubble) {
+ DCHECK(bubble->GetWidget());
+ DCHECK(bubble->parent_window());
+ bubble->GetWidget()->AddObserver(this);
+
+ NSRect parent_frame = [[bubble->parent_window() window] frame];
+ NSRect bubble_frame = [bubble->GetWidget()->GetNativeWindow() frame];
+
+ // Note: when anchored on the right, this doesn't support changes to the
+ // bubble size, just the parent size.
+ horizontal_offset_ =
+ (IsMinXFixed() ? NSMinX(parent_frame) : NSMaxX(parent_frame)) -
+ NSMinX(bubble_frame);
+ vertical_offset_ = NSMaxY(parent_frame) - NSMinY(bubble_frame);
+
+ Observe(NSWindowDidEnterFullScreenNotification);
+ Observe(NSWindowDidExitFullScreenNotification);
+ Observe(NSWindowDidResizeNotification);
+
+ // Also monitor move. Note that for user-initiated window moves this is not
+ // necessary: the bubble's child window status keeps the position pinned to
+ // the parent during the move (which is handy since AppKit doesn't send out
+ // notifications until the move completes). Programmatic -[NSWindow
+ // setFrame:..] calls, however, do not update child window positions for us.
+ Observe(NSWindowDidMoveNotification);
+}
+
+void BubbleAnchorHelper::Observe(NSString* name) {
+ NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
+ id token = [center addObserverForName:name
+ object:[bubble_->parent_window() window]
+ queue:nil
+ usingBlock:^(NSNotification* notification) {
+ ReAnchor();
+ }];
+ [observer_tokens_ addObject:token];
+}
+
+void BubbleAnchorHelper::ReAnchor() {
+ NSRect bubble_frame = [bubble_->GetWidget()->GetNativeWindow() frame];
+ NSRect parent_frame = [[bubble_->parent_window() window] frame];
+ if (IsMinXFixed())
+ bubble_frame.origin.x = NSMinX(parent_frame) - horizontal_offset_;
+ else
+ bubble_frame.origin.x = NSMaxX(parent_frame) - horizontal_offset_;
+ bubble_frame.origin.y = NSMaxY(parent_frame) - vertical_offset_;
+ [bubble_->GetWidget()->GetNativeWindow() setFrame:bubble_frame
+ display:YES
+ animate:NO];
+}
+
+void BubbleAnchorHelper::OnWidgetDestroying(views::Widget* widget) {
+ widget->RemoveObserver(this);
+ for (id token in observer_tokens_.get())
+ [[NSNotificationCenter defaultCenter] removeObserver:token];
+ delete this;
+}
« no previous file with comments | « chrome/browser/ui/cocoa/bubble_anchor_helper_views.h ('k') | chrome/browser/ui/cocoa/bubble_anchor_helper_views_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698