Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / apps / native_app_window_cocoa.mm
blobc4a17b421a7942b0f5f7120cfe4650f5d78a2f73
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 "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h"
7 #include "base/command_line.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/mac/mac_util.h"
10 #include "base/mac/sdk_forward_declarations.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
13 #include "chrome/browser/profiles/profile.h"
14 #import "chrome/browser/ui/cocoa/apps/titlebar_background_view.h"
15 #include "chrome/browser/ui/cocoa/browser_window_utils.h"
16 #import "chrome/browser/ui/cocoa/chrome_event_processing_window.h"
17 #include "chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h"
18 #include "chrome/browser/ui/cocoa/extensions/extension_view_mac.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "content/public/browser/native_web_keyboard_event.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/web_contents.h"
23 #include "extensions/common/extension.h"
24 #include "skia/ext/skia_utils_mac.h"
25 #include "third_party/skia/include/core/SkRegion.h"
26 #import "ui/gfx/mac/nswindow_frame_controls.h"
27 #include "ui/gfx/skia_util.h"
29 // NOTE: State Before Update.
31 // Internal state, such as |is_maximized_|, must be set before the window
32 // state is changed so that it is accurate when e.g. a resize results in a call
33 // to |OnNativeWindowChanged|.
35 // NOTE: Maximize and Zoom.
37 // Zooming is implemented manually in order to implement maximize functionality
38 // and to support non resizable windows. The window will be resized explicitly
39 // in the |WindowWillZoom| call.
41 // Attempting maximize and restore functionality with non resizable windows
42 // using the native zoom method did not work, even with
43 // windowWillUseStandardFrame, as the window would not restore back to the
44 // desired size.
46 using extensions::AppWindow;
48 @interface NSWindow (NSPrivateApis)
49 - (void)setBottomCornerRounded:(BOOL)rounded;
50 - (BOOL)_isTitleHidden;
51 @end
53 namespace {
55 const int kActivateThrottlePeriodSeconds = 2;
57 NSRect GfxToCocoaBounds(gfx::Rect bounds) {
58   typedef AppWindow::BoundsSpecification BoundsSpecification;
60   NSRect main_screen_rect = [[[NSScreen screens] objectAtIndex:0] frame];
62   // If coordinates are unspecified, center window on primary screen.
63   if (bounds.x() == BoundsSpecification::kUnspecifiedPosition)
64     bounds.set_x(floor((NSWidth(main_screen_rect) - bounds.width()) / 2));
65   if (bounds.y() == BoundsSpecification::kUnspecifiedPosition)
66     bounds.set_y(floor((NSHeight(main_screen_rect) - bounds.height()) / 2));
68   // Convert to Mac coordinates.
69   NSRect cocoa_bounds = NSRectFromCGRect(bounds.ToCGRect());
70   cocoa_bounds.origin.y = NSHeight(main_screen_rect) - NSMaxY(cocoa_bounds);
71   return cocoa_bounds;
74 // Return a vector of non-draggable regions that fill a window of size
75 // |width| by |height|, but leave gaps where the window should be draggable.
76 std::vector<gfx::Rect> CalculateNonDraggableRegions(
77     const std::vector<extensions::DraggableRegion>& regions,
78     int width,
79     int height) {
80   std::vector<gfx::Rect> result;
81   if (regions.empty()) {
82     result.push_back(gfx::Rect(0, 0, width, height));
83   } else {
84     scoped_ptr<SkRegion> draggable(
85         AppWindow::RawDraggableRegionsToSkRegion(regions));
86     scoped_ptr<SkRegion> non_draggable(new SkRegion);
87     non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op);
88     non_draggable->op(*draggable, SkRegion::kDifference_Op);
89     for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) {
90       result.push_back(gfx::SkIRectToRect(it.rect()));
91     }
92   }
93   return result;
96 }  // namespace
98 @implementation NativeAppWindowController
100 @synthesize appWindow = appWindow_;
102 - (void)setTitlebarBackgroundView:(NSView*)view {
103   titlebar_background_view_.reset([view retain]);
106 - (void)windowWillClose:(NSNotification*)notification {
107   if (appWindow_)
108     appWindow_->WindowWillClose();
111 - (void)windowDidBecomeKey:(NSNotification*)notification {
112   if (appWindow_)
113     appWindow_->WindowDidBecomeKey();
116 - (void)windowDidResignKey:(NSNotification*)notification {
117   if (appWindow_)
118     appWindow_->WindowDidResignKey();
121 - (void)windowDidBecomeMain:(NSNotification*)notification {
122   [titlebar_background_view_ setNeedsDisplay:YES];
125 - (void)windowDidResignMain:(NSNotification*)notification {
126   [titlebar_background_view_ setNeedsDisplay:YES];
129 - (void)windowDidResize:(NSNotification*)notification {
130   if (appWindow_)
131     appWindow_->WindowDidResize();
134 - (void)windowDidEndLiveResize:(NSNotification*)notification {
135   if (appWindow_)
136     appWindow_->WindowDidFinishResize();
139 - (void)windowDidEnterFullScreen:(NSNotification*)notification {
140   if (appWindow_)
141     appWindow_->WindowDidEnterFullscreen();
144 - (void)windowDidExitFullScreen:(NSNotification*)notification {
145   if (appWindow_)
146     appWindow_->WindowDidExitFullscreen();
149 - (void)windowDidMove:(NSNotification*)notification {
150   if (appWindow_)
151     appWindow_->WindowDidMove();
154 - (void)windowDidMiniaturize:(NSNotification*)notification {
155   if (appWindow_)
156     appWindow_->WindowDidMiniaturize();
159 - (void)windowDidDeminiaturize:(NSNotification*)notification {
160   if (appWindow_)
161     appWindow_->WindowDidDeminiaturize();
164 - (BOOL)windowShouldZoom:(NSWindow*)window
165                  toFrame:(NSRect)newFrame {
166   if (appWindow_)
167     appWindow_->WindowWillZoom();
168   return NO;  // See top of file NOTE: Maximize and Zoom.
171 // Allow non resizable windows (without NSResizableWindowMask) to enter
172 // fullscreen by passing through the full size in willUseFullScreenContentSize.
173 - (NSSize)window:(NSWindow *)window
174     willUseFullScreenContentSize:(NSSize)proposedSize {
175   return proposedSize;
178 - (BOOL)handledByExtensionCommand:(NSEvent*)event
179     priority:(ui::AcceleratorManager::HandlerPriority)priority {
180   if (appWindow_)
181     return appWindow_->HandledByExtensionCommand(event, priority);
182   return NO;
185 @end
187 @interface AppNSWindow : ChromeEventProcessingWindow
188 @end
190 @implementation AppNSWindow
192 // Similar to ChromeBrowserWindow, don't draw the title, but allow it to be seen
193 // in menus, Expose, etc.
194 - (BOOL)_isTitleHidden {
195   return YES;
198 @end
200 @interface AppFramelessNSWindow : AppNSWindow
201 @end
203 @implementation AppFramelessNSWindow
205 + (NSRect)frameRectForContentRect:(NSRect)contentRect
206                         styleMask:(NSUInteger)mask {
207   return contentRect;
210 + (NSRect)contentRectForFrameRect:(NSRect)frameRect
211                         styleMask:(NSUInteger)mask {
212   return frameRect;
215 - (NSRect)frameRectForContentRect:(NSRect)contentRect {
216   return contentRect;
219 - (NSRect)contentRectForFrameRect:(NSRect)frameRect {
220   return frameRect;
223 @end
225 @interface ControlRegionView : NSView
226 @end
228 @implementation ControlRegionView
230 - (BOOL)mouseDownCanMoveWindow {
231   return NO;
234 - (NSView*)hitTest:(NSPoint)aPoint {
235   return nil;
238 @end
240 @interface NSView (WebContentsView)
241 - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
242 @end
244 NativeAppWindowCocoa::NativeAppWindowCocoa(
245     AppWindow* app_window,
246     const AppWindow::CreateParams& params)
247     : app_window_(app_window),
248       has_frame_(params.frame == AppWindow::FRAME_CHROME),
249       is_hidden_with_app_(false),
250       is_maximized_(false),
251       is_fullscreen_(false),
252       is_resizable_(params.resizable),
253       shows_resize_controls_(true),
254       shows_fullscreen_controls_(true),
255       has_frame_color_(params.has_frame_color),
256       active_frame_color_(params.active_frame_color),
257       inactive_frame_color_(params.inactive_frame_color) {
258   Observe(WebContents());
260   Class window_class = has_frame_ ?
261       [AppNSWindow class] : [AppFramelessNSWindow class];
263   // Estimate the initial bounds of the window. Once the frame insets are known,
264   // the window bounds and constraints can be set precisely.
265   NSRect cocoa_bounds = GfxToCocoaBounds(
266       params.GetInitialWindowBounds(gfx::Insets()));
267   NSWindow* window =
268       [[window_class alloc] initWithContentRect:cocoa_bounds
269                                       styleMask:GetWindowStyleMask()
270                                         backing:NSBackingStoreBuffered
271                                           defer:NO];
273   std::string name;
274   const extensions::Extension* extension = app_window_->GetExtension();
275   if (extension)
276     name = extension->name();
277   [window setTitle:base::SysUTF8ToNSString(name)];
278   [[window contentView] setWantsLayer:YES];
280   if (base::mac::IsOSSnowLeopard() &&
281       [window respondsToSelector:@selector(setBottomCornerRounded:)])
282     [window setBottomCornerRounded:NO];
284   if (params.always_on_top)
285     gfx::SetNSWindowAlwaysOnTop(window, true);
287   gfx::SetNSWindowVisibleOnAllWorkspaces(window,
288                                          params.visible_on_all_workspaces);
290   window_controller_.reset(
291       [[NativeAppWindowController alloc] initWithWindow:window]);
293   if (has_frame_ && has_frame_color_) {
294     TitlebarBackgroundView* view =
295         [TitlebarBackgroundView addToNSWindow:window
296                                   activeColor:active_frame_color_
297                                 inactiveColor:inactive_frame_color_];
298     [window_controller_ setTitlebarBackgroundView:view];
299   }
301   NSView* view = WebContents()->GetNativeView();
302   [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
304   InstallView();
306   [window setDelegate:window_controller_];
307   [window_controller_ setAppWindow:this];
309   // We can now compute the precise window bounds and constraints.
310   gfx::Insets insets = GetFrameInsets();
311   SetBounds(params.GetInitialWindowBounds(insets));
312   SetContentSizeConstraints(params.GetContentMinimumSize(insets),
313                             params.GetContentMaximumSize(insets));
315   // Initialize |restored_bounds_|.
316   restored_bounds_ = [window frame];
318   extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryCocoa(
319       Profile::FromBrowserContext(app_window_->browser_context()),
320       window,
321       extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
322       NULL));
325 NSUInteger NativeAppWindowCocoa::GetWindowStyleMask() const {
326   NSUInteger style_mask = NSTitledWindowMask | NSClosableWindowMask |
327                           NSMiniaturizableWindowMask |
328                           NSTexturedBackgroundWindowMask;
329   if (shows_resize_controls_)
330     style_mask |= NSResizableWindowMask;
331   return style_mask;
334 void NativeAppWindowCocoa::InstallView() {
335   NSView* view = WebContents()->GetNativeView();
336   if (has_frame_) {
337     [view setFrame:[[window() contentView] bounds]];
338     [[window() contentView] addSubview:view];
339     if (!shows_fullscreen_controls_)
340       [[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO];
341     if (!shows_resize_controls_)
342       [window() setShowsResizeIndicator:NO];
343   } else {
344     // TODO(jeremya): find a cleaner way to send this information to the
345     // WebContentsViewCocoa view.
346     DCHECK([view
347         respondsToSelector:@selector(setMouseDownCanMoveWindow:)]);
348     [view setMouseDownCanMoveWindow:YES];
350     NSView* frameView = [[window() contentView] superview];
351     [view setFrame:[frameView bounds]];
352     [frameView addSubview:view];
354     [[window() standardWindowButton:NSWindowZoomButton] setHidden:YES];
355     [[window() standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
356     [[window() standardWindowButton:NSWindowCloseButton] setHidden:YES];
358     // Some third-party OS X utilities check the zoom button's enabled state to
359     // determine whether to show custom UI on hover, so we disable it here to
360     // prevent them from doing so in a frameless app window.
361     [[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO];
363     UpdateDraggableRegionViews();
364   }
367 void NativeAppWindowCocoa::UninstallView() {
368   NSView* view = WebContents()->GetNativeView();
369   [view removeFromSuperview];
372 bool NativeAppWindowCocoa::IsActive() const {
373   return [window() isKeyWindow];
376 bool NativeAppWindowCocoa::IsMaximized() const {
377   return is_maximized_ && !IsMinimized();
380 bool NativeAppWindowCocoa::IsMinimized() const {
381   return [window() isMiniaturized];
384 bool NativeAppWindowCocoa::IsFullscreen() const {
385   return is_fullscreen_;
388 void NativeAppWindowCocoa::SetFullscreen(int fullscreen_types) {
389   bool fullscreen = (fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
390   if (fullscreen == is_fullscreen_)
391     return;
392   is_fullscreen_ = fullscreen;
394   if (base::mac::IsOSLionOrLater()) {
395     // If going fullscreen, but the window is constrained (fullscreen UI control
396     // is disabled), temporarily enable it. It will be disabled again on leaving
397     // fullscreen.
398     if (fullscreen && !shows_fullscreen_controls_)
399       gfx::SetNSWindowCanFullscreen(window(), true);
400     [window() toggleFullScreen:nil];
401     return;
402   }
404   DCHECK(base::mac::IsOSSnowLeopard());
406   // Fade to black.
407   const CGDisplayReservationInterval kFadeDurationSeconds = 0.6;
408   bool did_fade_out = false;
409   CGDisplayFadeReservationToken token;
410   if (CGAcquireDisplayFadeReservation(kFadeDurationSeconds, &token) ==
411       kCGErrorSuccess) {
412     did_fade_out = true;
413     CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendNormal,
414         kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, /*synchronous=*/true);
415   }
417   // Since frameless windows insert the WebContentsView into the NSThemeFrame
418   // ([[window contentView] superview]), and since that NSThemeFrame is
419   // destroyed and recreated when we change the styleMask of the window, we
420   // need to remove the view from the window when we change the style, and
421   // add it back afterwards.
422   UninstallView();
423   if (fullscreen) {
424     UpdateRestoredBounds();
425     [window() setStyleMask:NSBorderlessWindowMask];
426     [window() setFrame:[window()
427         frameRectForContentRect:[[window() screen] frame]]
428                display:YES];
429     base::mac::RequestFullScreen(base::mac::kFullScreenModeAutoHideAll);
430   } else {
431     base::mac::ReleaseFullScreen(base::mac::kFullScreenModeAutoHideAll);
432     [window() setStyleMask:GetWindowStyleMask()];
433     [window() setFrame:restored_bounds_ display:YES];
434   }
435   InstallView();
437   // Fade back in.
438   if (did_fade_out) {
439     CGDisplayFade(token, kFadeDurationSeconds / 2, kCGDisplayBlendSolidColor,
440         kCGDisplayBlendNormal, 0.0, 0.0, 0.0, /*synchronous=*/false);
441     CGReleaseDisplayFadeReservation(token);
442   }
445 bool NativeAppWindowCocoa::IsFullscreenOrPending() const {
446   return is_fullscreen_;
449 gfx::NativeWindow NativeAppWindowCocoa::GetNativeWindow() const {
450   return window();
453 gfx::Rect NativeAppWindowCocoa::GetRestoredBounds() const {
454   // Flip coordinates based on the primary screen.
455   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
456   NSRect frame = restored_bounds_;
457   gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
458   bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
459   return bounds;
462 ui::WindowShowState NativeAppWindowCocoa::GetRestoredState() const {
463   if (IsMaximized())
464     return ui::SHOW_STATE_MAXIMIZED;
465   if (IsFullscreen())
466     return ui::SHOW_STATE_FULLSCREEN;
467   return ui::SHOW_STATE_NORMAL;
470 gfx::Rect NativeAppWindowCocoa::GetBounds() const {
471   // Flip coordinates based on the primary screen.
472   NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
473   NSRect frame = [window() frame];
474   gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));
475   bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));
476   return bounds;
479 void NativeAppWindowCocoa::Show() {
480   if (is_hidden_with_app_) {
481     apps::ExtensionAppShimHandler::UnhideWithoutActivationForWindow(
482         app_window_);
483     is_hidden_with_app_ = false;
484   }
486   // Workaround for http://crbug.com/459306. When requests to change key windows
487   // on Mac overlap, AppKit may attempt to make two windows simultaneously have
488   // key status. This causes key events to go the wrong window, and key status
489   // to get "stuck" until Chrome is deactivated. To reduce the possibility of
490   // this occurring, throttle activation requests. To balance a possible Hide(),
491   // always show the window, but don't make it key.
492   base::Time now = base::Time::Now();
493   if (now - last_activate_ <
494       base::TimeDelta::FromSeconds(kActivateThrottlePeriodSeconds)) {
495     [window() orderFront:window_controller_];
496     return;
497   }
499   last_activate_ = now;
501   [window() makeKeyAndOrderFront:nil];
502   [NSApp activateIgnoringOtherApps:YES];
505 void NativeAppWindowCocoa::ShowInactive() {
506   [window() orderFront:window_controller_];
509 void NativeAppWindowCocoa::Hide() {
510   HideWithoutMarkingHidden();
513 void NativeAppWindowCocoa::Close() {
514   [window() close];
517 void NativeAppWindowCocoa::Activate() {
518   Show();
521 void NativeAppWindowCocoa::Deactivate() {
522   // TODO(jcivelli): http://crbug.com/51364 Implement me.
523   NOTIMPLEMENTED();
526 void NativeAppWindowCocoa::Maximize() {
527   if (is_fullscreen_)
528     return;
530   UpdateRestoredBounds();
531   is_maximized_ = true;  // See top of file NOTE: State Before Update.
532   [window() setFrame:[[window() screen] visibleFrame] display:YES animate:YES];
533   if (IsMinimized())
534     [window() deminiaturize:window_controller_];
537 void NativeAppWindowCocoa::Minimize() {
538   [window() miniaturize:window_controller_];
541 void NativeAppWindowCocoa::Restore() {
542   DCHECK(!IsFullscreenOrPending());   // SetFullscreen, not Restore, expected.
544   if (is_maximized_) {
545     is_maximized_ = false;  // See top of file NOTE: State Before Update.
546     [window() setFrame:restored_bounds() display:YES animate:YES];
547   }
548   if (IsMinimized())
549     [window() deminiaturize:window_controller_];
552 void NativeAppWindowCocoa::SetBounds(const gfx::Rect& bounds) {
553   // Enforce minimum/maximum bounds.
554   gfx::Rect checked_bounds = bounds;
556   NSSize min_size = [window() minSize];
557   if (bounds.width() < min_size.width)
558     checked_bounds.set_width(min_size.width);
559   if (bounds.height() < min_size.height)
560     checked_bounds.set_height(min_size.height);
561   NSSize max_size = [window() maxSize];
562   if (checked_bounds.width() > max_size.width)
563     checked_bounds.set_width(max_size.width);
564   if (checked_bounds.height() > max_size.height)
565     checked_bounds.set_height(max_size.height);
567   NSRect cocoa_bounds = GfxToCocoaBounds(checked_bounds);
568   [window() setFrame:cocoa_bounds display:YES];
569   // setFrame: without animate: does not trigger a windowDidEndLiveResize: so
570   // call it here.
571   WindowDidFinishResize();
574 void NativeAppWindowCocoa::UpdateWindowIcon() {
575   // TODO(junmin): implement.
578 void NativeAppWindowCocoa::UpdateWindowTitle() {
579   base::string16 title = app_window_->GetTitle();
580   [window() setTitle:base::SysUTF16ToNSString(title)];
583 void NativeAppWindowCocoa::UpdateShape(scoped_ptr<SkRegion> region) {
584   NOTIMPLEMENTED();
587 void NativeAppWindowCocoa::UpdateDraggableRegions(
588     const std::vector<extensions::DraggableRegion>& regions) {
589   // Draggable region is not supported for non-frameless window.
590   if (has_frame_)
591     return;
593   draggable_regions_ = regions;
594   UpdateDraggableRegionViews();
597 SkRegion* NativeAppWindowCocoa::GetDraggableRegion() {
598   return NULL;
601 void NativeAppWindowCocoa::HandleKeyboardEvent(
602     const content::NativeWebKeyboardEvent& event) {
603   if (event.skip_in_browser ||
604       event.type == content::NativeWebKeyboardEvent::Char) {
605     return;
606   }
607   [window() redispatchKeyEvent:event.os_event];
610 void NativeAppWindowCocoa::UpdateDraggableRegionViews() {
611   if (has_frame_)
612     return;
614   // All ControlRegionViews should be added as children of the WebContentsView,
615   // because WebContentsView will be removed and re-added when entering and
616   // leaving fullscreen mode.
617   NSView* webView = WebContents()->GetNativeView();
618   NSInteger webViewWidth = NSWidth([webView bounds]);
619   NSInteger webViewHeight = NSHeight([webView bounds]);
621   // Remove all ControlRegionViews that are added last time.
622   // Note that [webView subviews] returns the view's mutable internal array and
623   // it should be copied to avoid mutating the original array while enumerating
624   // it.
625   base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
626   for (NSView* subview in subviews.get())
627     if ([subview isKindOfClass:[ControlRegionView class]])
628       [subview removeFromSuperview];
630   // Draggable regions is implemented by having the whole web view draggable
631   // (mouseDownCanMoveWindow) and overlaying regions that are not draggable.
632   std::vector<gfx::Rect> system_drag_exclude_areas =
633       CalculateNonDraggableRegions(
634           draggable_regions_, webViewWidth, webViewHeight);
636   // Create and add a ControlRegionView for each region that needs to be
637   // excluded from the dragging.
638   for (std::vector<gfx::Rect>::const_iterator iter =
639            system_drag_exclude_areas.begin();
640        iter != system_drag_exclude_areas.end();
641        ++iter) {
642     base::scoped_nsobject<NSView> controlRegion(
643         [[ControlRegionView alloc] initWithFrame:NSZeroRect]);
644     [controlRegion setFrame:NSMakeRect(iter->x(),
645                                        webViewHeight - iter->bottom(),
646                                        iter->width(),
647                                        iter->height())];
648     [webView addSubview:controlRegion];
649   }
652 void NativeAppWindowCocoa::FlashFrame(bool flash) {
653   apps::ExtensionAppShimHandler::RequestUserAttentionForWindow(
654       app_window_,
655       flash ? apps::APP_SHIM_ATTENTION_CRITICAL
656             : apps::APP_SHIM_ATTENTION_CANCEL);
659 bool NativeAppWindowCocoa::IsAlwaysOnTop() const {
660   return gfx::IsNSWindowAlwaysOnTop(window());
663 void NativeAppWindowCocoa::RenderViewCreated(content::RenderViewHost* rvh) {
664   if (IsActive())
665     WebContents()->RestoreFocus();
668 bool NativeAppWindowCocoa::IsFrameless() const {
669   return !has_frame_;
672 bool NativeAppWindowCocoa::HasFrameColor() const {
673   return has_frame_color_;
676 SkColor NativeAppWindowCocoa::ActiveFrameColor() const {
677   return active_frame_color_;
680 SkColor NativeAppWindowCocoa::InactiveFrameColor() const {
681   return inactive_frame_color_;
684 gfx::Insets NativeAppWindowCocoa::GetFrameInsets() const {
685   if (!has_frame_)
686     return gfx::Insets();
688   // Flip the coordinates based on the main screen.
689   NSInteger screen_height =
690       NSHeight([[[NSScreen screens] objectAtIndex:0] frame]);
692   NSRect frame_nsrect = [window() frame];
693   gfx::Rect frame_rect(NSRectToCGRect(frame_nsrect));
694   frame_rect.set_y(screen_height - NSMaxY(frame_nsrect));
696   NSRect content_nsrect = [window() contentRectForFrameRect:frame_nsrect];
697   gfx::Rect content_rect(NSRectToCGRect(content_nsrect));
698   content_rect.set_y(screen_height - NSMaxY(content_nsrect));
700   return frame_rect.InsetsFrom(content_rect);
703 bool NativeAppWindowCocoa::CanHaveAlphaEnabled() const {
704   return false;
707 gfx::NativeView NativeAppWindowCocoa::GetHostView() const {
708   return WebContents()->GetNativeView();
711 gfx::Point NativeAppWindowCocoa::GetDialogPosition(const gfx::Size& size) {
712   NOTIMPLEMENTED();
713   return gfx::Point();
716 gfx::Size NativeAppWindowCocoa::GetMaximumDialogSize() {
717   NOTIMPLEMENTED();
718   return gfx::Size();
721 void NativeAppWindowCocoa::AddObserver(
722     web_modal::ModalDialogHostObserver* observer) {
723   NOTIMPLEMENTED();
726 void NativeAppWindowCocoa::RemoveObserver(
727     web_modal::ModalDialogHostObserver* observer) {
728   NOTIMPLEMENTED();
731 void NativeAppWindowCocoa::WindowWillClose() {
732   [window_controller_ setAppWindow:NULL];
733   app_window_->OnNativeWindowChanged();
734   app_window_->OnNativeClose();
737 void NativeAppWindowCocoa::WindowDidBecomeKey() {
738   content::RenderWidgetHostView* rwhv =
739       WebContents()->GetRenderWidgetHostView();
740   if (rwhv)
741     rwhv->SetActive(true);
742   app_window_->OnNativeWindowActivated();
744   WebContents()->RestoreFocus();
747 void NativeAppWindowCocoa::WindowDidResignKey() {
748   // If our app is still active and we're still the key window, ignore this
749   // message, since it just means that a menu extra (on the "system status bar")
750   // was activated; we'll get another |-windowDidResignKey| if we ever really
751   // lose key window status.
752   if ([NSApp isActive] && ([NSApp keyWindow] == window()))
753     return;
755   WebContents()->StoreFocus();
757   content::RenderWidgetHostView* rwhv =
758       WebContents()->GetRenderWidgetHostView();
759   if (rwhv)
760     rwhv->SetActive(false);
763 void NativeAppWindowCocoa::WindowDidFinishResize() {
764   // Update |is_maximized_| if needed:
765   // - Exit maximized state if resized.
766   // - Consider us maximized if resize places us back to maximized location.
767   //   This happens when returning from fullscreen.
768   NSRect frame = [window() frame];
769   NSRect screen = [[window() screen] visibleFrame];
770   if (!NSEqualSizes(frame.size, screen.size))
771     is_maximized_ = false;
772   else if (NSEqualPoints(frame.origin, screen.origin))
773     is_maximized_ = true;
775   UpdateRestoredBounds();
778 void NativeAppWindowCocoa::WindowDidResize() {
779   app_window_->OnNativeWindowChanged();
780   UpdateDraggableRegionViews();
783 void NativeAppWindowCocoa::WindowDidMove() {
784   UpdateRestoredBounds();
785   app_window_->OnNativeWindowChanged();
788 void NativeAppWindowCocoa::WindowDidMiniaturize() {
789   app_window_->OnNativeWindowChanged();
792 void NativeAppWindowCocoa::WindowDidDeminiaturize() {
793   app_window_->OnNativeWindowChanged();
796 void NativeAppWindowCocoa::WindowDidEnterFullscreen() {
797   is_maximized_ = false;
798   is_fullscreen_ = true;
799   app_window_->OnNativeWindowChanged();
802 void NativeAppWindowCocoa::WindowDidExitFullscreen() {
803   is_fullscreen_ = false;
804   if (!shows_fullscreen_controls_)
805     gfx::SetNSWindowCanFullscreen(window(), false);
807   WindowDidFinishResize();
809   app_window_->OnNativeWindowChanged();
812 void NativeAppWindowCocoa::WindowWillZoom() {
813   // See top of file NOTE: Maximize and Zoom.
814   if (IsMaximized())
815     Restore();
816   else
817     Maximize();
820 bool NativeAppWindowCocoa::HandledByExtensionCommand(
821     NSEvent* event,
822     ui::AcceleratorManager::HandlerPriority priority) {
823   return extension_keybinding_registry_->ProcessKeyEvent(
824       content::NativeWebKeyboardEvent(event), priority);
827 void NativeAppWindowCocoa::ShowWithApp() {
828   is_hidden_with_app_ = false;
829   if (!app_window_->is_hidden())
830     ShowInactive();
833 void NativeAppWindowCocoa::HideWithApp() {
834   is_hidden_with_app_ = true;
835   HideWithoutMarkingHidden();
838 gfx::Size NativeAppWindowCocoa::GetContentMinimumSize() const {
839   return size_constraints_.GetMinimumSize();
842 gfx::Size NativeAppWindowCocoa::GetContentMaximumSize() const {
843   return size_constraints_.GetMaximumSize();
846 void NativeAppWindowCocoa::SetContentSizeConstraints(
847     const gfx::Size& min_size, const gfx::Size& max_size) {
848   // Update the size constraints.
849   size_constraints_.set_minimum_size(min_size);
850   size_constraints_.set_maximum_size(max_size);
852   // Update the window controls.
853   shows_resize_controls_ =
854       is_resizable_ && !size_constraints_.HasFixedSize();
855   shows_fullscreen_controls_ =
856       is_resizable_ && !size_constraints_.HasMaximumSize() && has_frame_;
858   gfx::ApplyNSWindowSizeConstraints(window(), min_size, max_size,
859                                     shows_resize_controls_,
860                                     shows_fullscreen_controls_);
863 void NativeAppWindowCocoa::SetAlwaysOnTop(bool always_on_top) {
864   gfx::SetNSWindowAlwaysOnTop(window(), always_on_top);
867 void NativeAppWindowCocoa::SetVisibleOnAllWorkspaces(bool always_visible) {
868   gfx::SetNSWindowVisibleOnAllWorkspaces(window(), always_visible);
871 void NativeAppWindowCocoa::SetInterceptAllKeys(bool want_all_key) {
872   // TODO(sriramsr): implement for OSX (http://crbug.com/166928).
873   NOTIMPLEMENTED();
876 NativeAppWindowCocoa::~NativeAppWindowCocoa() {
879 AppNSWindow* NativeAppWindowCocoa::window() const {
880   NSWindow* window = [window_controller_ window];
881   CHECK(!window || [window isKindOfClass:[AppNSWindow class]]);
882   return static_cast<AppNSWindow*>(window);
885 content::WebContents* NativeAppWindowCocoa::WebContents() const {
886   return app_window_->web_contents();
889 void NativeAppWindowCocoa::UpdateRestoredBounds() {
890   if (IsRestored(*this))
891     restored_bounds_ = [window() frame];
894 void NativeAppWindowCocoa::HideWithoutMarkingHidden() {
895   [window() orderOut:window_controller_];