| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2009 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 #import "chrome/browser/cocoa/extensions/extension_popup_controller.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "chrome/browser/browser.h" |
| 10 #import "chrome/browser/cocoa/browser_window_cocoa.h" |
| 11 #import "chrome/browser/cocoa/extension_view_mac.h" |
| 12 #import "chrome/browser/cocoa/info_bubble_window.h" |
| 13 #include "chrome/browser/profile.h" |
| 14 |
| 15 // The minimum/maximum dimensions of the popup. |
| 16 // The minimum is just a little larger than the size of the button itself. |
| 17 // The maximum is an arbitrary number that should be smaller than most screens. |
| 18 namespace { |
| 19 const CGFloat kMinWidth = 25; |
| 20 const CGFloat kMinHeight = 25; |
| 21 const CGFloat kMaxWidth = 800; |
| 22 const CGFloat kMaxHeight = 600; |
| 23 } // namespace |
| 24 |
| 25 @interface ExtensionPopupController(Private) |
| 26 // Callers should be using the public static method for initialization. |
| 27 // NOTE: This takes ownership of |host|. |
| 28 - (id)initWithHost:(ExtensionHost*)host |
| 29 parentWindow:(NSWindow*)parentWindow |
| 30 anchoredAt:(NSPoint)anchoredAt |
| 31 arrowLocation:(BubbleArrowLocation)arrowLocation; |
| 32 |
| 33 // Called when the extension's hosted NSView has been resized. |
| 34 - (void)extensionViewFrameChanged; |
| 35 @end |
| 36 |
| 37 @implementation ExtensionPopupController |
| 38 |
| 39 - (id)initWithHost:(ExtensionHost*)host |
| 40 parentWindow:(NSWindow*)parentWindow |
| 41 anchoredAt:(NSPoint)anchoredAt |
| 42 arrowLocation:(BubbleArrowLocation)arrowLocation { |
| 43 parentWindow_ = parentWindow; |
| 44 anchor_ = anchoredAt; |
| 45 host_.reset(host); |
| 46 |
| 47 scoped_nsobject<InfoBubbleView> view([[InfoBubbleView alloc] init]); |
| 48 if (!view.get()) |
| 49 return nil; |
| 50 [view setArrowLocation:arrowLocation]; |
| 51 [view setBubbleType:kWhiteInfoBubble]; |
| 52 |
| 53 host->view()->set_is_toolstrip(NO); |
| 54 |
| 55 extensionView_ = host->view()->native_view(); |
| 56 [[NSNotificationCenter defaultCenter] |
| 57 addObserver:self |
| 58 selector:@selector(extensionViewFrameChanged) |
| 59 name:NSViewFrameDidChangeNotification |
| 60 object:extensionView_]; |
| 61 |
| 62 [view addSubview:extensionView_]; |
| 63 scoped_nsobject<InfoBubbleWindow> window( |
| 64 [[InfoBubbleWindow alloc] |
| 65 initWithContentRect:NSZeroRect |
| 66 styleMask:NSBorderlessWindowMask |
| 67 backing:NSBackingStoreBuffered |
| 68 defer:YES]); |
| 69 if (!window.get()) |
| 70 return nil; |
| 71 |
| 72 [window setDelegate:self]; |
| 73 [window setContentView:view]; |
| 74 self = [super initWithWindow:window]; |
| 75 |
| 76 return self; |
| 77 } |
| 78 |
| 79 - (void)dealloc { |
| 80 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 81 [super dealloc]; |
| 82 } |
| 83 |
| 84 - (void)windowWillClose:(NSNotification *)notification { |
| 85 [self autorelease]; |
| 86 } |
| 87 |
| 88 - (ExtensionHost*)host { |
| 89 return host_.get(); |
| 90 } |
| 91 |
| 92 - (void)windowDidResignKey:(NSNotification *)notification { |
| 93 DCHECK_EQ([notification object], [self window]); |
| 94 [self close]; |
| 95 } |
| 96 |
| 97 - (void)close { |
| 98 [parentWindow_ removeChildWindow:[self window]]; |
| 99 [super close]; |
| 100 } |
| 101 |
| 102 + (ExtensionPopupController*)showURL:(GURL)url |
| 103 inBrowser:(Browser*)browser |
| 104 anchoredAt:(NSPoint)anchoredAt |
| 105 arrowLocation:(BubbleArrowLocation)arrowLocation { |
| 106 DCHECK(browser); |
| 107 if (!browser) |
| 108 return nil; |
| 109 |
| 110 ExtensionProcessManager* manager = |
| 111 browser->profile()->GetExtensionProcessManager(); |
| 112 DCHECK(manager); |
| 113 if (!manager) |
| 114 return nil; |
| 115 |
| 116 ExtensionHost* host = manager->CreatePopup(url, browser); |
| 117 DCHECK(host); |
| 118 if (!host) |
| 119 return nil; |
| 120 |
| 121 // Takes ownership of |host|. Also will autorelease itself when the popup is |
| 122 // closed, so no need to do that here. |
| 123 ExtensionPopupController* popup = [[ExtensionPopupController alloc] |
| 124 initWithHost:host |
| 125 parentWindow:browser->window()->GetNativeHandle() |
| 126 anchoredAt:anchoredAt |
| 127 arrowLocation:arrowLocation]; |
| 128 |
| 129 return popup; |
| 130 } |
| 131 |
| 132 - (void)extensionViewFrameChanged { |
| 133 // Constrain the size of the view. |
| 134 [extensionView_ setFrameSize:NSMakeSize( |
| 135 std::max(kMinWidth, std::min(kMaxWidth, NSWidth([extensionView_ frame]))), |
| 136 std::max(kMinHeight, |
| 137 std::min(kMaxHeight, NSHeight([extensionView_ frame]))))]; |
| 138 |
| 139 // Pad the window by half of the rounded corner radius to prevent the |
| 140 // extension's view from bleeding out over the corners. |
| 141 CGFloat inset = kBubbleCornerRadius / 2.0; |
| 142 [extensionView_ setFrameOrigin:NSMakePoint(inset, inset)]; |
| 143 |
| 144 NSRect frame = [extensionView_ frame]; |
| 145 frame.size.height += kBubbleArrowHeight + kBubbleCornerRadius; |
| 146 frame.size.width += kBubbleCornerRadius; |
| 147 // Adjust the origin according to the height and width so that the arrow is |
| 148 // positioned correctly at the middle and slightly down from the button. |
| 149 NSPoint windowOrigin = anchor_; |
| 150 windowOrigin.x -= NSWidth(frame) - kBubbleArrowXOffset - |
| 151 (kBubbleArrowWidth / 2.0); |
| 152 windowOrigin.y -= NSHeight(frame) - (kBubbleArrowHeight / 2.0); |
| 153 frame.origin = windowOrigin; |
| 154 [[self window] setFrame:frame display:YES]; |
| 155 |
| 156 // A NSViewFrameDidChangeNotification won't be sent until the extension view |
| 157 // content is loaded. The window is hidden on init, so show it the first time |
| 158 // the notification is fired (and consequently the view contents have loaded). |
| 159 // |
| 160 // TODO(andybons): It seems that if the frame changes again before the |
| 161 // animation of the window show is completed, the window size gets super |
| 162 // janky. Fix this. |
| 163 if (![[self window] isVisible]) { |
| 164 [self showWindow:self]; |
| 165 } |
| 166 } |
| 167 |
| 168 // We want this to be a child of a browser window. addChildWindow: (called from |
| 169 // this function) will bring the window on-screen; unfortunately, |
| 170 // [NSWindowController showWindow:] will also bring it on-screen (but will cause |
| 171 // unexpected changes to the window's position). We cannot have an |
| 172 // addChildWindow: and a subsequent showWindow:. Thus, we have our own version. |
| 173 - (void)showWindow:(id)sender { |
| 174 [parentWindow_ addChildWindow:[self window] ordered:NSWindowAbove]; |
| 175 [[self window] makeKeyAndOrderFront:self]; |
| 176 } |
| 177 |
| 178 @end |
| OLD | NEW |