Update ASan/Android runtime and setup script to LLVM r200682.
[chromium-blink-merge.git] / content / shell / browser / shell_mac.mm
blobe31ba098753db0a8177945542c09e90e85cf593c
1 // Copyright 2013 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 #include "content/shell/browser/shell.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #import "base/mac/scoped_nsobject.h"
11 #include "base/strings/string_piece.h"
12 #include "base/strings/sys_string_conversions.h"
13 #include "content/public/browser/native_web_keyboard_event.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_view.h"
16 #include "content/shell/app/resource.h"
17 #import "ui/base/cocoa/underlay_opengl_hosting_window.h"
18 #include "url/gurl.h"
20 #if !defined(MAC_OS_X_VERSION_10_7) || \
21     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
23 enum {
24   NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
25   NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
28 #endif // MAC_OS_X_VERSION_10_7
30 // Receives notification that the window is closing so that it can start the
31 // tear-down process. Is responsible for deleting itself when done.
32 @interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> {
33  @private
34   content::Shell* shell_;
36 - (id)initWithShell:(content::Shell*)shell;
37 @end
39 @implementation ContentShellWindowDelegate
41 - (id)initWithShell:(content::Shell*)shell {
42   if ((self = [super init])) {
43     shell_ = shell;
44   }
45   return self;
48 // Called when the window is about to close. Perform the self-destruction
49 // sequence by getting rid of the shell and removing it and the window from
50 // the various global lists. By returning YES, we allow the window to be
51 // removed from the screen.
52 - (BOOL)windowShouldClose:(id)window {
53   [window autorelease];
54   delete shell_;
55   [self release];
57   return YES;
60 - (void)performAction:(id)sender {
61   shell_->ActionPerformed([sender tag]);
64 - (void)takeURLStringValueFrom:(id)sender {
65   shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue]));
68 @end
70 @interface CrShellWindow : UnderlayOpenGLHostingWindow {
71  @private
72   content::Shell* shell_;
74 - (void)setShell:(content::Shell*)shell;
75 - (void)showDevTools:(id)sender;
76 @end
78 @implementation CrShellWindow
80 - (void)setShell:(content::Shell*)shell {
81   shell_ = shell;
84 - (void)showDevTools:(id)sender {
85   shell_->ShowDevTools();
88 @end
90 namespace {
92 NSString* kWindowTitle = @"Content Shell";
94 // Layout constants (in view coordinates)
95 const CGFloat kButtonWidth = 72;
96 const CGFloat kURLBarHeight = 24;
98 // The minimum size of the window's content (in view coordinates)
99 const CGFloat kMinimumWindowWidth = 400;
100 const CGFloat kMinimumWindowHeight = 300;
102 void MakeShellButton(NSRect* rect,
103                      NSString* title,
104                      NSView* parent,
105                      int control,
106                      NSView* target,
107                      NSString* key,
108                      NSUInteger modifier) {
109   base::scoped_nsobject<NSButton> button(
110       [[NSButton alloc] initWithFrame:*rect]);
111   [button setTitle:title];
112   [button setBezelStyle:NSSmallSquareBezelStyle];
113   [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
114   [button setTarget:target];
115   [button setAction:@selector(performAction:)];
116   [button setTag:control];
117   [button setKeyEquivalent:key];
118   [button setKeyEquivalentModifierMask:modifier];
119   [parent addSubview:button];
120   rect->origin.x += kButtonWidth;
123 }  // namespace
125 namespace content {
127 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
130 void Shell::PlatformExit() {
133 void Shell::PlatformCleanUp() {
136 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
137   if (headless_)
138     return;
140   int id;
141   switch (control) {
142     case BACK_BUTTON:
143       id = IDC_NAV_BACK;
144       break;
145     case FORWARD_BUTTON:
146       id = IDC_NAV_FORWARD;
147       break;
148     case STOP_BUTTON:
149       id = IDC_NAV_STOP;
150       break;
151     default:
152       NOTREACHED() << "Unknown UI control";
153       return;
154   }
155   [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled];
158 void Shell::PlatformSetAddressBarURL(const GURL& url) {
159   if (headless_)
160     return;
162   NSString* url_string = base::SysUTF8ToNSString(url.spec());
163   [url_edit_view_ setStringValue:url_string];
166 void Shell::PlatformSetIsLoading(bool loading) {
169 void Shell::PlatformCreateWindow(int width, int height) {
170   if (headless_) {
171     content_size_ = gfx::Size(width, height);
172     return;
173   }
175   NSRect initial_window_bounds =
176       NSMakeRect(0, 0, width, height + kURLBarHeight);
177   NSRect content_rect = initial_window_bounds;
178   NSUInteger style_mask = NSTitledWindowMask |
179                           NSClosableWindowMask |
180                           NSMiniaturizableWindowMask |
181                           NSResizableWindowMask;
182   CrShellWindow* window =
183       [[CrShellWindow alloc] initWithContentRect:content_rect
184                                        styleMask:style_mask
185                                          backing:NSBackingStoreBuffered
186                                            defer:NO];
187   window_ = window;
188   [window setShell:this];
189   [window_ setTitle:kWindowTitle];
190   NSView* content = [window_ contentView];
192   // If the window is allowed to get too small, it will wreck the view bindings.
193   NSSize min_size = NSMakeSize(kMinimumWindowWidth, kMinimumWindowHeight);
194   min_size = [content convertSize:min_size toView:nil];
195   // Note that this takes window coordinates.
196   [window_ setContentMinSize:min_size];
198   // Set the shell window to participate in Lion Fullscreen mode. Set
199   // Setting this flag has no effect on Snow Leopard or earlier.
200   NSUInteger collectionBehavior = [window_ collectionBehavior];
201   collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
202   [window_ setCollectionBehavior:collectionBehavior];
204   // Rely on the window delegate to clean us up rather than immediately
205   // releasing when the window gets closed. We use the delegate to do
206   // everything from the autorelease pool so the shell isn't on the stack
207   // during cleanup (ie, a window close from javascript).
208   [window_ setReleasedWhenClosed:NO];
210   // Create a window delegate to watch for when it's asked to go away. It will
211   // clean itself up so we don't need to hold a reference.
212   ContentShellWindowDelegate* delegate =
213       [[ContentShellWindowDelegate alloc] initWithShell:this];
214   [window_ setDelegate:delegate];
216   NSRect button_frame =
217       NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight,
218                  kButtonWidth, kURLBarHeight);
220   MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK,
221                   (NSView*)delegate, @"[", NSCommandKeyMask);
222   MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD,
223                   (NSView*)delegate, @"]", NSCommandKeyMask);
224   MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD,
225                   (NSView*)delegate, @"r", NSCommandKeyMask);
226   MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP,
227                   (NSView*)delegate, @".", NSCommandKeyMask);
229   button_frame.size.width =
230       NSWidth(initial_window_bounds) - NSMinX(button_frame);
231   base::scoped_nsobject<NSTextField> url_edit_view(
232       [[NSTextField alloc] initWithFrame:button_frame]);
233   [content addSubview:url_edit_view];
234   [url_edit_view setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
235   [url_edit_view setTarget:delegate];
236   [url_edit_view setAction:@selector(takeURLStringValueFrom:)];
237   [[url_edit_view cell] setWraps:NO];
238   [[url_edit_view cell] setScrollable:YES];
239   url_edit_view_ = url_edit_view.get();
241   // show the window
242   [window_ makeKeyAndOrderFront:nil];
245 void Shell::PlatformSetContents() {
246   NSView* web_view = web_contents_->GetView()->GetNativeView();
247   [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
249   if (headless_) {
250     SizeTo(content_size_);
251     return;
252   }
254   NSView* content = [window_ contentView];
255   [content addSubview:web_view];
257   NSRect frame = [content bounds];
258   frame.size.height -= kURLBarHeight;
259   [web_view setFrame:frame];
260   [web_view setNeedsDisplay:YES];
263 void Shell::SizeTo(const gfx::Size& content_size) {
264   if (!headless_) {
265     NOTREACHED();
266     return;
267   }
268   NSView* web_view = web_contents_->GetView()->GetNativeView();
269   NSRect frame = NSMakeRect(0, 0, content_size.width(), content_size.height());
270   [web_view setFrame:frame];
273 void Shell::PlatformResizeSubViews() {
274   // Not needed; subviews are bound.
277 void Shell::PlatformSetTitle(const base::string16& title) {
278   if (headless_)
279     return;
281   NSString* title_string = base::SysUTF16ToNSString(title);
282   [window_ setTitle:title_string];
285 void Shell::Close() {
286   if (headless_)
287     delete this;
288   else
289     [window_ performClose:nil];
292 void Shell::ActionPerformed(int control) {
293   switch (control) {
294     case IDC_NAV_BACK:
295       GoBackOrForward(-1);
296       break;
297     case IDC_NAV_FORWARD:
298       GoBackOrForward(1);
299       break;
300     case IDC_NAV_RELOAD:
301       Reload();
302       break;
303     case IDC_NAV_STOP:
304       Stop();
305       break;
306   }
309 void Shell::URLEntered(std::string url_string) {
310   if (!url_string.empty()) {
311     GURL url(url_string);
312     if (!url.has_scheme())
313       url = GURL("http://" + url_string);
314     LoadURL(url);
315   }
318 void Shell::HandleKeyboardEvent(WebContents* source,
319                                 const NativeWebKeyboardEvent& event) {
320   if (event.skip_in_browser)
321     return;
323   // The event handling to get this strictly right is a tangle; cheat here a bit
324   // by just letting the menus have a chance at it.
325   if ([event.os_event type] == NSKeyDown) {
326     if (([event.os_event modifierFlags] & NSCommandKeyMask) &&
327         [[event.os_event characters] isEqual:@"l"]) {
328       [window_ makeFirstResponder:url_edit_view_];
329       return;
330     }
332     [[NSApp mainMenu] performKeyEquivalent:event.os_event];
333   }
336 }  // namespace content