15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/cocoa/panels/panel_window_controller_cocoa.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import <Cocoa/Cocoa.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/auto_reset.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/bundle_locations.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/mac_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_nsautorelease_pool.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/chrome_command_ids.h"  // IDC_*
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chrome_browser_application_mac.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/browser_command_executor.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/browser_window_utils.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/panels/mouse_drag_controller.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/panels/panel_cocoa.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/panels/panel_titlebar_view_cocoa.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/panels/panel_utils_cocoa.h"
2403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#import "chrome/browser/ui/cocoa/sprite_view.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/tab_contents/favicon_util_mac.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel_bounds_animation.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/panels/panel_collection.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel_constants.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/panels/panel_manager.h"
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/panels/stacked_panel_collection.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/toolbar/encoding_menu_controller.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host_view.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/resources/grit/ui_resources.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinimumWindowSize = 1;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kBoundsAnimationSpeedPixelsPerSecond = 1000;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const double kBoundsAnimationMaxDurationSeconds = 0.18;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Edge thickness to trigger user resizing via system, in screen pixels.
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)const double kWidthOfMouseResizeArea = 15.0;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@interface PanelWindowControllerCocoa (PanelsCanBecomeKey)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Internal helper method for extracting the total number of panel windows
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the panel manager. Used to decide if panel can become the key window.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (int)numPanels;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@implementation PanelWindowCocoaImpl
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The panels cannot be reduced to 3-px windows on the edge of the screen
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// active area (above Dock). Default constraining logic makes at least a height
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the titlebar visible, so the user could still grab it. We do 'restore'
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// differently, and minimize panels to 3 px. Hence the need to override the
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// constraining logic.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frameRect;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Prevent panel window from becoming key - for example when it is minimized.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Panel windows use a higher priority NSWindowLevel to ensure they are always
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// visible, causing the OS to prefer panel windows when selecting a window
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to make the key window. To counter this preference, we override
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// -[NSWindow:canBecomeKeyWindow] to restrict when the panel can become the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// key window to a limited set of scenarios, such as when cycling through
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// windows, when panels are the only remaining windows, when an event
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// triggers window activation, etc. The panel may also be prevented from
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// becoming the key window, regardless of the above scenarios, such as when
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a panel is minimized.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)canBecomeKeyWindow {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give precedence to controller preventing activation of the window.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PanelWindowControllerCocoa* controller =
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::mac::ObjCCast<PanelWindowControllerCocoa>([self windowController]);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (![controller canBecomeKeyWindow])
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NO;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserCrApplication* app = base::mac::ObjCCast<BrowserCrApplication>(
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [BrowserCrApplication sharedApplication]);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A Panel window can become the key window only in limited scenarios.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This prevents the system from always preferring a Panel window due
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to its higher priority NSWindowLevel when selecting a window to make key.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ([app isHandlingSendEvent]  && [[app currentEvent] window] == self) ||
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [controller activationRequestedByPanel] ||
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [app isCyclingWindows] ||
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [app previousKeyWindow] == self ||
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [[app windows] count] == static_cast<NSUInteger>([controller numPanels]);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch- (void)performMiniaturize:(id)sender {
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  [[self windowController] minimizeButtonClicked:0];
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)mouseMoved:(NSEvent*)event {
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Cocoa does not support letting the application determine the edges that
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // can trigger the user resizing. To work around this, we track the mouse
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // location. When it is close to the edge/corner where the user resizing
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // is not desired, we force the min and max size of the window to be same
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // as current window size. For all other cases, we restore the min and max
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // size.
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  PanelWindowControllerCocoa* controller =
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      base::mac::ObjCCast<PanelWindowControllerCocoa>([self windowController]);
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  NSRect frame = [self frame];
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if ([controller canResizeByMouseAtCurrentLocation]) {
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Mac window server limits window sizes to 10000.
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    NSSize maxSize = NSMakeSize(10000, 10000);
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // If the user is resizing a stacked panel by its bottom edge, make sure its
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // height cannot grow more than what the panel below it could offer. This is
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // because growing a stacked panel by y amount will shrink the panel below
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // it by same amount and we do not want the panel below it being shrunk to
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // be smaller than the titlebar.
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Panel* panel = [controller panel];
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    NSPoint point = [NSEvent mouseLocation];
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.y < NSMinY(frame) + kWidthOfMouseResizeArea && panel->stack()) {
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      Panel* belowPanel = panel->stack()->GetPanelBelow(panel);
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if (belowPanel && !belowPanel->IsMinimized()) {
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        maxSize.height = panel->GetBounds().height() +
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            belowPanel->GetBounds().height() - panel::kTitlebarHeight;
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Enable the user-resizing by setting both min and max size to the right
12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // values.
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    [self setMinSize:NSMakeSize(panel::kPanelMinWidth,
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                panel::kPanelMinHeight)];
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    [self setMaxSize:maxSize];
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Disable the user-resizing by setting both min and max size to be same as
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // current window size.
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    [self setMinSize:frame.size];
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    [self setMaxSize:frame.size];
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [super mouseMoved:event];
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ChromeEventProcessingWindow expects its controller to implement the
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserCommandExecutor protocol.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@interface PanelWindowControllerCocoa (InternalAPI) <BrowserCommandExecutor>
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserCommandExecutor methods.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)executeCommand:(int)command;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@implementation PanelWindowControllerCocoa (InternalAPI)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This gets called whenever a browser-specific keyboard shortcut is performed
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the Panel window. We simply swallow all those events.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)executeCommand:(int)command {}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@implementation PanelWindowControllerCocoa
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (id)initWithPanel:(PanelCocoa*)window {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSString* nibpath =
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [base::mac::FrameworkBundle() pathForResource:@"Panel" ofType:@"nib"];
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((self = [super initWithWindowNibPath:nibpath owner:self])) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    windowShim_.reset(window);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animateOnBoundsChange_ = YES;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    canBecomeKeyWindow_ = YES;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    activationRequestedByPanel_ = NO;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return self;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (Panel*)panel {
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return windowShim_->panel();
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)awakeFromNib {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSWindow* window = [self window];
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(window);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(titlebar_view_);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(self, [window delegate]);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self updateWindowLevel];
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [self updateWindowCollectionBehavior];
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [titlebar_view_ attach];
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set initial size of the window to match the size of the panel to give
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the renderer the proper size to work with earlier, avoiding a resize
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // after the window is revealed.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect panelBounds = windowShim_->panel()->GetBounds();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect frame = [window frame];
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame.size.width = panelBounds.width();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frame.size.height = panelBounds.height();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [window setFrame:frame display:NO];
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // MacOS will turn the user-resizing to the user-dragging if the direction of
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // the dragging is orthogonal to the direction of the arrow cursor. We do not
20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // want this since it will bypass our dragging logic. The panel window is
20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // still draggable because we track and handle the dragging in our custom way.
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [[self window] setMovable:NO];
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [self updateTrackingArea];
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)updateWebContentsViewFrame {
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  content::WebContents* webContents = windowShim_->panel()->GetWebContents();
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!webContents)
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Compute the size of the web contents view. Don't assume it's similar to the
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // size of the contentView, because the contentView is managed by the Cocoa
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to be (window - standard titlebar), while we have taller custom titlebar
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // instead. In coordinate system of window's contentView.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect contentFrame = [self contentRectForFrameRect:[[self window] frame]];
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contentFrame.origin = NSZeroPoint;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
222010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  NSView* contentView = webContents->GetNativeView();
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!NSEqualRects([contentView frame], contentFrame))
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    [contentView setFrame:contentFrame];
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)disableWebContentsViewAutosizing {
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [[[self window] contentView] setAutoresizesSubviews:NO];
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)enableWebContentsViewAutosizing {
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [self updateWebContentsViewFrame];
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [[[self window] contentView] setAutoresizesSubviews:YES];
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)revealAnimatedWithFrame:(const NSRect&)frame {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSWindow* window = [self window];  // This ensures loading the nib.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable subview resizing while resizing the window to avoid renderer
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // resizes during intermediate stages of animation.
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [self disableWebContentsViewAutosizing];
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We grow the window from the bottom up to produce a 'reveal' animation.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect startFrame = NSMakeRect(NSMinX(frame), NSMinY(frame),
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 NSWidth(frame), kMinimumWindowSize);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [window setFrame:startFrame display:NO animate:NO];
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Shows the window without making it key, on top of its layer, even if
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chromium is not an active app.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [window orderFrontRegardless];
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(dcheng): Temporary hack to work around the fact that
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // orderFrontRegardless causes us to become the first responder. The usual
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Chrome assumption is that becoming the first responder = you have focus, so
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we always deactivate the controls here. If we're created as an active
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // panel, we'll get a NSWindowDidBecomeKeyNotification and reactivate the web
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // view properly. See crbug.com/97831 for more details.
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  WebContents* web_contents = windowShim_->panel()->GetWebContents();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RWHV may be NULL in unit tests.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (web_contents && web_contents->GetRenderWidgetHostView())
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_contents->GetRenderWidgetHostView()->SetActive(false);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This will re-enable the content resizing after it finishes.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self setPanelFrame:frame animate:YES];
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateTitleBar {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSString* newTitle = base::SysUTF16ToNSString(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windowShim_->panel()->GetWindowTitle());
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pendingWindowTitle_.reset(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [BrowserWindowUtils scheduleReplaceOldTitle:pendingWindowTitle_.get()
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     withNewTitle:newTitle
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        forWindow:[self window]]);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [titlebar_view_ setTitle:newTitle];
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self updateIcon];
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateIcon {
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::scoped_nsobject<NSView> iconView;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (throbberShouldSpin_) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the throbber is spinning now, no need to replace it.
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if ([[titlebar_view_ icon] isKindOfClass:[SpriteView class]])
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NSImage* iconImage =
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ResourceBundle::GetSharedInstance().GetNativeImageNamed(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            IDR_THROBBER).ToNSImage();
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    SpriteView* spriteView = [[SpriteView alloc] init];
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    [spriteView setImage:iconImage];
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    iconView.reset(spriteView);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image& page_icon = windowShim_->panel()->GetCurrentPageIcon();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NSRect iconFrame = [[titlebar_view_ icon] frame];
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NSImage* iconImage = page_icon.IsEmpty() ?
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToNSImage() :
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        page_icon.ToNSImage();
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NSImageView* imageView = [[NSImageView alloc] initWithFrame:iconFrame];
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    [imageView setImage:iconImage];
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    iconView.reset(imageView);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  [titlebar_view_ setIcon:iconView];
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateThrobber:(BOOL)shouldSpin {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (throbberShouldSpin_ == shouldSpin)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  throbberShouldSpin_ = shouldSpin;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the titlebar view has not been attached, bail out.
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!titlebar_view_)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self updateIcon];
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateTitleBarMinimizeRestoreButtonVisibility {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [titlebar_view_ setMinimizeButtonVisibility:panel->CanShowMinimizeButton()];
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [titlebar_view_ setRestoreButtonVisibility:panel->CanShowRestoreButton()];
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)webContentsInserted:(WebContents*)contents {
322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  NSView* view = contents->GetNativeView();
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [[[self window] contentView] addSubview:view];
324868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [self enableWebContentsViewAutosizing];
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)webContentsDetached:(WebContents*)contents {
330010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  [contents->GetNativeView() removeFromSuperview];
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (PanelTitlebarViewCocoa*)titlebarView {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return titlebar_view_;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called to validate menu and toolbar items when this window is key. All the
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// items we care about have been set with the |-commandDispatch:|
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// action and a target of FirstResponder in IB.
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Delegate to the NSApp delegate if Panel does not care about the command or
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// shortcut, to make sure the global items in Chrome main app menu still work.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ([item action] == @selector(commandDispatch:)) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NSInteger tag = [item tag];
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CommandUpdater* command_updater = windowShim_->panel()->command_updater();
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command_updater->SupportsCommand(tag))
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return command_updater->IsCommandEnabled(tag);
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return [[NSApp delegate] validateUserInterfaceItem:item];
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return NO;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called when the user picks a menu or toolbar item when this window is key.
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Calls through to the panel object to execute the command or delegates up.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)commandDispatch:(id)sender {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(sender);
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NSInteger tag = [sender tag];
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandUpdater* command_updater = windowShim_->panel()->command_updater();
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (command_updater->SupportsCommand(tag))
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    windowShim_->panel()->ExecuteCommandIfEnabled(tag);
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    [[NSApp delegate] commandDispatch:sender];
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handler for the custom Close button.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)closePanel {
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->Close();
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handler for the custom Minimize button.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)minimizeButtonClicked:(int)modifierFlags {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  panel->OnMinimizeButtonClicked((modifierFlags & NSShiftKeyMask) ?
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 panel::APPLY_TO_ALL : panel::NO_MODIFIER);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Handler for the custom Restore button.
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)restoreButtonClicked:(int)modifierFlags {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  panel->OnRestoreButtonClicked((modifierFlags & NSShiftKeyMask) ?
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                panel::APPLY_TO_ALL : panel::NO_MODIFIER);
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Called when the user wants to close the panel or from the shutdown process.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The Panel object is in control of whether or not we're allowed to close. It
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// may defer closing due to several states, such as onbeforeUnload handlers
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// needing to be fired. If closing is deferred, the Panel will handle the
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// processing required to get us to the closing state and (by watching for
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the web content going away) will again call to close the window when it's
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// finally ready.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)windowShouldClose:(id)sender {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give beforeunload handlers the chance to cancel the close before we hide
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the window below.
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!panel->ShouldCloseWindow())
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NO;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (panel->GetWebContents()) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Terminate any playing animations.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [self terminateBoundsAnimation];
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animateOnBoundsChange_ = NO;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make panel close the web content, allowing the renderer to shut down
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and call us back again.
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    panel->OnWindowClosing();
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NO;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No web content; it's ok to close the window.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return YES;
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When windowShouldClose returns YES (or if controller receives direct 'close'
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// signal), window will be unconditionally closed. Clean up.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)windowWillClose:(NSNotification*)notification {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!windowShim_->panel()->GetWebContents());
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Avoid callbacks from a nonblocking animation in progress, if any.
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self terminateBoundsAnimation];
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->DidCloseNativeWindow();
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call |-autorelease| after a zero-length delay to avoid deadlock from
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code in the current run loop that waits on PANEL_CLOSED notification.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The notification is sent when this object is freed, but this object
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cannot be freed until the current run loop completes.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self performSelector:@selector(autorelease)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             withObject:nil
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             afterDelay:0];
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)startDrag:(NSPoint)mouseLocation {
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert from Cocoa's screen coordinates to platform-indepedent screen
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinates because PanelManager method takes platform-indepedent screen
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinates.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->manager()->StartDragging(
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windowShim_->panel(),
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cocoa_utils::ConvertPointFromCocoaCoordinates(mouseLocation));
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)endDrag:(BOOL)cancelled {
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->manager()->EndDragging(cancelled);
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)drag:(NSPoint)mouseLocation {
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert from Cocoa's screen coordinates to platform-indepedent screen
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinates because PanelManager method takes platform-indepedent screen
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // coordinates.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->manager()->Drag(
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cocoa_utils::ConvertPointFromCocoaCoordinates(mouseLocation));
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)setPanelFrame:(NSRect)frame
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              animate:(BOOL)animate {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL jumpToDestination = (!animateOnBoundsChange_ || !animate);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no animation is in progress, apply bounds change instantly.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (jumpToDestination && ![self isAnimatingBounds]) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [[self window] setFrame:frame display:YES animate:NO];
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSDictionary *windowResize = [NSDictionary dictionaryWithObjectsAndKeys:
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [self window], NSViewAnimationTargetKey,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [NSValue valueWithRect:frame], NSViewAnimationEndFrameKey, nil];
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSArray *animations = [NSArray arrayWithObjects:windowResize, nil];
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If an animation is in progress, update the animation with new target
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bounds. Also, set the destination frame bounds to the new value.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (jumpToDestination && [self isAnimatingBounds]) {
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [boundsAnimation_ setViewAnimations:animations];
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [[self window] setFrame:frame display:YES animate:NO];
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Will be enabled back in animationDidEnd callback.
474868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  [self disableWebContentsViewAutosizing];
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Terminate previous animation, if it is still playing.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self terminateBoundsAnimation];
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  boundsAnimation_ =
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      [[NSViewAnimation alloc] initWithViewAnimations:animations];
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ setDelegate:self];
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect currentFrame = [[self window] frame];
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compute duration. We use constant speed of animation, however if the change
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is too large, we clip the duration (effectively increasing speed) to
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // limit total duration of animation. This makes 'small' transitions fast.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 'distance' is the max travel between 4 potentially traveling corners.
488a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double distanceX = std::max(std::abs(NSMinX(currentFrame) - NSMinX(frame)),
489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              std::abs(NSMaxX(currentFrame) - NSMaxX(frame)));
490a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double distanceY = std::max(std::abs(NSMinY(currentFrame) - NSMinY(frame)),
491a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              std::abs(NSMaxY(currentFrame) - NSMaxY(frame)));
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double distance = std::max(distanceX, distanceY);
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double duration = std::min(distance / kBoundsAnimationSpeedPixelsPerSecond,
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             kBoundsAnimationMaxDurationSeconds);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Detect animation that happens when expansion state is set to MINIMIZED
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and there is relatively big portion of the panel to hide from view.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initialize animation differently in this case, using fast-pause-slow
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // method, see below for more details.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (distanceY > 0 &&
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      windowShim_->panel()->expansion_state() == Panel::MINIMIZED) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animationStopToShowTitlebarOnly_ = 1.0 -
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (windowShim_->panel()->TitleOnlyHeight() - NSHeight(frame)) / distanceY;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (animationStopToShowTitlebarOnly_ > 0.7) {  // Relatively big movement.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      playingMinimizeAnimation_ = YES;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      duration = 1.5;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ setDuration: PanelManager::AdjustTimeInterval(duration)];
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ setFrameRate:0.0];
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ setAnimationBlockingMode: NSAnimationNonblocking];
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ startAnimation];
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (float)animation:(NSAnimation*)animation
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  valueForProgress:(NSAnimationProgress)progress {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PanelBoundsAnimation::ComputeAnimationValue(
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      progress, playingMinimizeAnimation_, animationStopToShowTitlebarOnly_);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)cleanupAfterAnimation {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  playingMinimizeAnimation_ = NO;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!windowShim_->panel()->IsMinimized())
523868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    [self enableWebContentsViewAutosizing];
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)animationDidEnd:(NSAnimation*)animation {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self cleanupAfterAnimation];
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only invoke this callback from animationDidEnd, since animationDidStop can
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be called when we interrupt/restart animation which is in progress.
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only need this notification when animation indeed finished moving
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the panel bounds.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  panel->manager()->OnPanelAnimationEnded(panel);
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)animationDidStop:(NSAnimation*)animation {
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self cleanupAfterAnimation];
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)terminateBoundsAnimation {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!boundsAnimation_)
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ stopAnimation];
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ setDelegate:nil];
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [boundsAnimation_ release];
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  boundsAnimation_ = nil;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)isAnimatingBounds {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return boundsAnimation_ && [boundsAnimation_ isAnimating];
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)onTitlebarMouseClicked:(int)modifierFlags {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  panel->OnTitlebarClicked((modifierFlags & NSShiftKeyMask) ?
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           panel::APPLY_TO_ALL : panel::NO_MODIFIER);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
560424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)- (void)onTitlebarDoubleClicked:(int)modifierFlags {
561424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Double-clicking is only allowed to minimize docked panels.
562424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Panel* panel = windowShim_->panel();
563424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (panel->collection()->type() != PanelCollection::DOCKED ||
564424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      panel->IsMinimized())
565424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return;
566424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  [self minimizeButtonClicked:modifierFlags];
567424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
568424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (int)titlebarHeightInScreenCoordinates {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSView* titlebar = [self titlebarView];
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NSHeight([titlebar convertRect:[titlebar bounds] toView:nil]);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dcheng): These two selectors are almost copy-and-paste from
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// BrowserWindowController. Figure out the appropriate way of code sharing,
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// whether it's refactoring more things into BrowserWindowUtils or making a
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// common base controller for browser windows.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)windowDidBecomeKey:(NSNotification*)notification {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to activate the controls (in the "WebView"). To do this, get the
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selected WebContents's RenderWidgetHostView and tell it to activate.
581868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (WebContents* contents = windowShim_->panel()->GetWebContents()) {
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::RenderWidgetHostView* rwhv =
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contents->GetRenderWidgetHostView())
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rwhv->SetActive(true);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->OnActiveStateChanged(true);
58858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
58958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Make the window user-resizable when it gains the focus.
59058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [[self window] setStyleMask:
59158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      [[self window] styleMask] | NSResizableWindowMask];
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)windowDidResignKey:(NSNotification*)notification {
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If our app is still active and we're still the key window, ignore this
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message, since it just means that a menu extra (on the "system status bar")
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // was activated; we'll get another |-windowDidResignKey| if we ever really
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lose key window status.
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ([NSApp isActive] && ([NSApp keyWindow] == [self window]))
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self onWindowDidResignKey];
60358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
60458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
60558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)windowWillStartLiveResize:(NSNotification*)notification {
60658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Check if the user-resizing is allowed for the triggering edge/corner.
60758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // This is an extra safe guard because we are not able to track the mouse
60858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // movement outside the window and Cocoa could trigger the user-resizing
60958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // when the mouse moves a bit outside the edge/corner.
61058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (![self canResizeByMouseAtCurrentLocation])
61158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
61258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  userResizing_ = YES;
61358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  windowShim_->panel()->OnPanelStartUserResizing();
61458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
61558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
61658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)windowDidEndLiveResize:(NSNotification*)notification {
61758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!userResizing_)
61858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
61958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  userResizing_ = NO;
62058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
62158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Panel* panel = windowShim_->panel();
62258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  panel->OnPanelEndUserResizing();
62358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
62458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  gfx::Rect newBounds =
62558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      cocoa_utils::ConvertRectFromCocoaCoordinates([[self window] frame]);
62658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (windowShim_->panel()->GetBounds() == newBounds)
62758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
62858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  windowShim_->set_cached_bounds_directly(newBounds);
62958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
63058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  panel->IncreaseMaxSize(newBounds.size());
63158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  panel->set_full_size(newBounds.size());
63258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
63358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  panel->collection()->RefreshLayout();
63458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
63558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
63658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)newSize {
63758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // As an extra safe guard, we avoid the user resizing if it is deemed not to
63858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // be allowed (see comment in windowWillStartLiveResize).
63958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if ([[self window] inLiveResize] && !userResizing_)
64058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return [[self window] frame].size;
64158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return newSize;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)- (void)windowDidResize:(NSNotification*)notification {
64558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  Panel* panel = windowShim_->panel();
64658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (userResizing_) {
64758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    panel->collection()->OnPanelResizedByMouse(
64858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        panel,
64958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        cocoa_utils::ConvertRectFromCocoaCoordinates([[self window] frame]));
65058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
65158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
65258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [self updateTrackingArea];
65358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
65458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (![self isAnimatingBounds] ||
65558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      panel->collection()->type() != PanelCollection::DOCKED)
65658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
65758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
658c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // Remove the web contents view from the view hierarchy when the panel is not
659c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // taller than the titlebar. Put it back when the panel grows taller than
660c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // the titlebar. Note that RenderWidgetHostViewMac works for the case that
661c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // the web contents view does not exist in the view hierarchy (i.e. the tab
662c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // is not the main one), but it does not work well, like causing occasional
663c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  // crashes (http://crbug.com/265932), if the web contents view is made hidden.
664c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  //
66558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // This is needed when the docked panels are being animated. When the
66658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // animation starts, the contents view autosizing is disabled. After the
66758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // animation ends, the contents view autosizing is reenabled and the frame
66858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // of contents view is updated. Thus it is likely that the contents view will
66958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // overlap with the titlebar view when the panel shrinks to be very small.
67058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // The implementation of the web contents view assumes that it will never
67158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // overlap with another view in order to paint the web contents view directly.
67258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  content::WebContents* webContents = panel->GetWebContents();
673c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (!webContents)
6743240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    return;
675010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  NSView* contentView = webContents->GetNativeView();
67658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (NSHeight([self contentRectForFrameRect:[[self window] frame]]) <= 0) {
677c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // No need to retain the view before it is removed from its superview
678c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // because WebContentsView keeps a reference to this view.
679c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    if ([contentView superview])
680c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      [contentView removeFromSuperview];
681c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else {
682424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (![contentView superview]) {
683c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      [[[self window] contentView] addSubview:contentView];
684424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
685424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // When the web contents view is put back, we need to tell its render
686424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // widget host view to accept focus.
687424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      content::RenderWidgetHostView* rwhv =
688424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          webContents->GetRenderWidgetHostView();
689424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      if (rwhv) {
690424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        [[self window] makeFirstResponder:rwhv->GetNativeView()];
691424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        rwhv->SetActive([[self window] isMainWindow]);
692424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
693424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
694868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
695868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
696868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)activate {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Activate the window. -|windowDidBecomeKey:| will be called when
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // window becomes active.
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoReset<BOOL> pin(&activationRequestedByPanel_, true);
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [BrowserWindowUtils activateWindowForController:self];
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)deactivate {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (![[self window] isMainWindow])
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [NSApp deactivate];
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Cocoa does not support deactivating a NSWindow explicitly. To work around
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // this, we call orderOut and orderFront to force the window to lose its key
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // window state.
713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Before doing this, we need to disable screen updates to prevent flickering.
715cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NSDisableScreenUpdates();
716cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // If a panel is in stacked mode, the window has a background parent window.
718cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // We need to detach it from its parent window before applying the ordering
719cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // change and then put it back because otherwise tha background parent window
720cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // might show up.
721cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NSWindow* parentWindow = [[self window] parentWindow];
722cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (parentWindow)
723cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    [parentWindow removeChildWindow:[self window]];
724cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
725cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  [[self window] orderOut:nil];
726cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  [[self window] orderFront:nil];
727cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
728cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (parentWindow)
729cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    [parentWindow addChildWindow:[self window] ordered:NSWindowAbove];
730cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
731cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  NSEnableScreenUpdates();
732cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
733cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Though the above workaround causes the window to lose its key window state,
734cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // it does not trigger the system to call windowDidResignKey.
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self onWindowDidResignKey];
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)onWindowDidResignKey {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to deactivate the controls (in the "WebView"). To do this, get the
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // selected WebContents's RenderWidgetHostView and tell it to deactivate.
741868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (WebContents* contents = windowShim_->panel()->GetWebContents()) {
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (content::RenderWidgetHostView* rwhv =
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        contents->GetRenderWidgetHostView())
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rwhv->SetActive(false);
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  windowShim_->panel()->OnActiveStateChanged(false);
748cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
749cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Make the window not user-resizable when it loses the focus. This is to
750cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // solve the problem that the bottom edge of the active panel does not
751cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // trigger the user-resizing if this panel stacks with another inactive
752cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // panel at the bottom.
753cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  [[self window] setStyleMask:
754cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      [[self window] styleMask] & ~NSResizableWindowMask];
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)preventBecomingKeyWindow:(BOOL)prevent {
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  canBecomeKeyWindow_ = !prevent;
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)fullScreenModeChanged:(bool)isFullScreen {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self updateWindowLevel];
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the panel is not always on top, its z-order should not be affected if
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // some other window enters fullscreen mode.
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!windowShim_->panel()->IsAlwaysOnTop())
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The full-screen window is in normal level and changing the panel window
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to same normal level will not move it below the full-screen window. Thus
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // we need to reorder the panel window.
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (isFullScreen)
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    [[self window] orderOut:nil];
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [[self window] orderFrontRegardless];
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)canBecomeKeyWindow {
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Panel can only gain focus if it is expanded. Minimized panels do not
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // participate in Cmd-~ rotation.
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(dimich): If it will be ever desired to expand/focus the Panel on
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // keyboard navigation or via main menu, the care should be taken to avoid
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cases when minimized Panel is getting keyboard input, invisibly.
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return canBecomeKeyWindow_;
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (int)numPanels {
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return windowShim_->panel()->manager()->num_panels();
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (BOOL)activationRequestedByPanel {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return activationRequestedByPanel_;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateWindowLevel {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [self updateWindowLevel:windowShim_->panel()->IsMinimized()];
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (void)updateWindowLevel:(BOOL)panelIsMinimized {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (![self isWindowLoaded])
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Panel* panel = windowShim_->panel();
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!panel->IsAlwaysOnTop()) {
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [[self window] setLevel:NSNormalWindowLevel];
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we simply use NSStatusWindowLevel (25) for all docked panel windows,
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IME composition windows for things like CJK languages appear behind panels.
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pre 10.7, IME composition windows have a window level of 19, which is
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lower than the dock at level 20. Since we want panels to appear on top of
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the dock, it is impossible to enforce an ordering where IME > panel > dock,
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // since IME < dock.
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On 10.7, IME composition windows and the dock both live at level 20, so we
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // use the same window level for panels. Since newly created windows appear at
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the top of their window level, panels are typically on top of the dock, and
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the IME composition window correctly draws over the panel.
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An autohide dock causes problems though: since it's constantly being
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // revealed, it ends up drawing on top of other windows at the same level.
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // While this is OK for expanded panels, it makes minimized panels impossible
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to activate. As a result, we still use NSStatusWindowLevel for minimized
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // panels, since it's impossible to compose IME text in them anyway.
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (panelIsMinimized) {
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    [[self window] setLevel:NSStatusWindowLevel];
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  [[self window] setLevel:NSDockWindowLevel];
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)- (void)updateWindowCollectionBehavior {
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (![self isWindowLoaded])
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NSWindowCollectionBehavior collectionBehavior =
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NSWindowCollectionBehaviorParticipatesInCycle;
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (windowShim_->panel()->IsAlwaysOnTop())
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    collectionBehavior |= NSWindowCollectionBehaviorCanJoinAllSpaces;
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  [[self window] setCollectionBehavior:collectionBehavior];
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
83958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (void)updateTrackingArea {
84058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  NSView* superview = [[[self window] contentView] superview];
84158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
84258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (trackingArea_.get())
84358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    [superview removeTrackingArea:trackingArea_.get()];
84458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
84558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  trackingArea_.reset(
84658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          [[CrTrackingArea alloc] initWithRect:[superview bounds]
84758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                       options:NSTrackingInVisibleRect |
84858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                               NSTrackingMouseMoved |
84958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                               NSTrackingActiveInKeyWindow
85058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                         owner:superview
85158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                      userInfo:nil]);
85258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  [superview addTrackingArea:trackingArea_.get()];
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)showShadow:(BOOL)show {
856c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (![self isWindowLoaded])
857c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
858c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  [[self window] setHasShadow:show];
859c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
861c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (void)miniaturize {
862c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  [[self window] miniaturize:nil];
863c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
864c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)- (BOOL)isMiniaturized {
866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return [[self window] isMiniaturized];
867c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
868c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)- (BOOL)canResizeByMouseAtCurrentLocation {
87058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  panel::Resizability resizability = windowShim_->panel()->CanResizeByMouse();
87158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  NSRect frame = [[self window] frame];
87258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  NSPoint point = [NSEvent mouseLocation];
87358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
87458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (point.y < NSMinY(frame) + kWidthOfMouseResizeArea) {
87558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea &&
87658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_BOTTOM_LEFT) == 0) {
87758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
87858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
87958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea &&
88058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_BOTTOM_RIGHT) == 0) {
88158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
88258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
88358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if ((resizability & panel::RESIZABLE_BOTTOM) == 0)
88458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
88558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else if (point.y > NSMaxY(frame) - kWidthOfMouseResizeArea) {
88658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea &&
88758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_TOP_LEFT) == 0) {
88858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
88958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
89058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea &&
89158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_TOP_RIGHT) == 0) {
89258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
89358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
89458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if ((resizability & panel::RESIZABLE_TOP) == 0)
89558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
89658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
89758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x < NSMinX(frame) + kWidthOfMouseResizeArea &&
89858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_LEFT) == 0) {
89958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
90058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
90158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (point.x > NSMaxX(frame) - kWidthOfMouseResizeArea &&
90258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        (resizability & panel::RESIZABLE_RIGHT) == 0) {
90358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return NO;
90458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
90558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
90658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return YES;
90758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
90858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We have custom implementation of these because our titlebar height is custom
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and does not match the standard one.
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (NSRect)frameRectForContentRect:(NSRect)contentRect {
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contentRect is in contentView coord system. We should add a titlebar on top
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and then convert to the windows coord system.
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contentRect.size.height += panel::kTitlebarHeight;
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect frameRect = [[[self window] contentView] convertRect:contentRect
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       toView:nil];
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return frameRect;
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)- (NSRect)contentRectForFrameRect:(NSRect)frameRect {
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NSRect contentRect = [[[self window] contentView] convertRect:frameRect
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       fromView:nil];
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contentRect.size.height -= panel::kTitlebarHeight;
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contentRect.size.height < 0)
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    contentRect.size.height = 0;
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contentRect;
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)@end
930