Home | History | Annotate | Download | only in apps
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/apps/native_app_window_views.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/file_util.h"
      9 #include "base/path_service.h"
     10 #include "base/threading/sequenced_worker_pool.h"
     11 #include "chrome/app/chrome_command_ids.h"
     12 #include "chrome/browser/extensions/extension_host.h"
     13 #include "chrome/browser/favicon/favicon_tab_helper.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
     16 #include "chrome/browser/ui/views/extensions/shell_window_frame_view.h"
     17 #include "chrome/common/chrome_switches.h"
     18 #include "chrome/common/extensions/extension.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "content/public/browser/render_view_host.h"
     21 #include "content/public/browser/render_widget_host_view.h"
     22 #include "content/public/browser/web_contents.h"
     23 #include "content/public/browser/web_contents_view.h"
     24 #include "extensions/common/draggable_region.h"
     25 #include "ui/views/controls/webview/webview.h"
     26 #include "ui/views/widget/widget.h"
     27 #include "ui/views/window/non_client_view.h"
     28 
     29 #if defined(OS_WIN)
     30 #include "base/strings/utf_string_conversions.h"
     31 #include "chrome/browser/ui/web_applications/web_app_ui.h"
     32 #include "chrome/browser/web_applications/web_app.h"
     33 #include "chrome/browser/web_applications/web_app_win.h"
     34 #include "ui/base/win/shell.h"
     35 #include "ui/views/win/hwnd_util.h"
     36 #endif
     37 
     38 #if defined(USE_ASH)
     39 #include "ash/screen_ash.h"
     40 #include "ash/shell.h"
     41 #include "ash/wm/custom_frame_view_ash.h"
     42 #include "ash/wm/panels/panel_frame_view.h"
     43 #include "ash/wm/window_properties.h"
     44 #include "chrome/browser/ui/ash/ash_util.h"
     45 #include "ui/aura/client/aura_constants.h"
     46 #include "ui/aura/root_window.h"
     47 #include "ui/aura/window.h"
     48 #endif
     49 
     50 using apps::ShellWindow;
     51 
     52 namespace {
     53 
     54 const int kMinPanelWidth = 100;
     55 const int kMinPanelHeight = 100;
     56 const int kDefaultPanelWidth = 200;
     57 const int kDefaultPanelHeight = 300;
     58 const int kResizeInsideBoundsSize = 5;
     59 
     60 struct AcceleratorMapping {
     61   ui::KeyboardCode keycode;
     62   int modifiers;
     63   int command_id;
     64 };
     65 const AcceleratorMapping kAppWindowAcceleratorMap[] = {
     66   { ui::VKEY_W, ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
     67   { ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
     68   { ui::VKEY_F4, ui::EF_ALT_DOWN, IDC_CLOSE_WINDOW },
     69 };
     70 
     71 const std::map<ui::Accelerator, int>& GetAcceleratorTable() {
     72   typedef std::map<ui::Accelerator, int> AcceleratorMap;
     73   CR_DEFINE_STATIC_LOCAL(AcceleratorMap, accelerators, ());
     74   if (accelerators.empty()) {
     75     for (size_t i = 0; i < arraysize(kAppWindowAcceleratorMap); ++i) {
     76       ui::Accelerator accelerator(kAppWindowAcceleratorMap[i].keycode,
     77                                   kAppWindowAcceleratorMap[i].modifiers);
     78       accelerators[accelerator] = kAppWindowAcceleratorMap[i].command_id;
     79     }
     80   }
     81   return accelerators;
     82 }
     83 
     84 #if defined(OS_WIN)
     85 void CreateIconAndSetRelaunchDetails(
     86     const base::FilePath web_app_path,
     87     const base::FilePath icon_file,
     88     const ShellIntegration::ShortcutInfo& shortcut_info,
     89     const HWND hwnd) {
     90   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
     91 
     92   // Set the relaunch data so "Pin this program to taskbar" has the app's
     93   // information.
     94   CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher(
     95       shortcut_info.url,
     96       shortcut_info.extension_id,
     97       shortcut_info.profile_path);
     98 
     99   // TODO(benwells): Change this to use app_host.exe.
    100   base::FilePath chrome_exe;
    101   if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
    102      NOTREACHED();
    103      return;
    104   }
    105   command_line.SetProgram(chrome_exe);
    106   ui::win::SetRelaunchDetailsForWindow(command_line.GetCommandLineString(),
    107       shortcut_info.title, hwnd);
    108 
    109   if (!base::PathExists(web_app_path) &&
    110       !file_util::CreateDirectory(web_app_path)) {
    111     return;
    112   }
    113   ui::win::SetAppIconForWindow(icon_file.value(), hwnd);
    114   web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon);
    115 }
    116 #endif
    117 
    118 }  // namespace
    119 
    120 NativeAppWindowViews::NativeAppWindowViews(
    121     ShellWindow* shell_window,
    122     const ShellWindow::CreateParams& create_params)
    123     : shell_window_(shell_window),
    124       web_view_(NULL),
    125       window_(NULL),
    126       is_fullscreen_(false),
    127       frameless_(create_params.frame == ShellWindow::FRAME_NONE),
    128       transparent_background_(create_params.transparent_background),
    129       minimum_size_(create_params.minimum_size),
    130       maximum_size_(create_params.maximum_size),
    131       resizable_(create_params.resizable),
    132       weak_ptr_factory_(this) {
    133   Observe(web_contents());
    134 
    135   window_ = new views::Widget;
    136   if (create_params.window_type == ShellWindow::WINDOW_TYPE_PANEL ||
    137       create_params.window_type == ShellWindow::WINDOW_TYPE_V1_PANEL) {
    138     InitializePanelWindow(create_params);
    139   } else {
    140     InitializeDefaultWindow(create_params);
    141   }
    142   extension_keybinding_registry_.reset(
    143       new ExtensionKeybindingRegistryViews(
    144           profile(),
    145           window_->GetFocusManager(),
    146           extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
    147           shell_window_));
    148 
    149   OnViewWasResized();
    150   window_->AddObserver(this);
    151 }
    152 
    153 NativeAppWindowViews::~NativeAppWindowViews() {
    154   web_view_->SetWebContents(NULL);
    155 }
    156 
    157 void NativeAppWindowViews::InitializeDefaultWindow(
    158     const ShellWindow::CreateParams& create_params) {
    159   views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
    160   init_params.delegate = this;
    161   init_params.remove_standard_frame = ShouldUseChromeStyleFrame();
    162   init_params.use_system_default_icon = true;
    163   // TODO(erg): Conceptually, these are toplevel windows, but we theoretically
    164   // could plumb context through to here in some cases.
    165   init_params.top_level = true;
    166   gfx::Rect window_bounds = create_params.bounds;
    167   bool position_specified =
    168       window_bounds.x() != INT_MIN && window_bounds.y() != INT_MIN;
    169   if (position_specified && !window_bounds.IsEmpty())
    170     init_params.bounds = window_bounds;
    171   window_->Init(init_params);
    172 
    173   gfx::Rect adjusted_bounds = window_bounds;
    174   adjusted_bounds.Inset(-GetFrameInsets());
    175   // Center window if no position was specified.
    176   if (!position_specified)
    177     window_->CenterWindow(adjusted_bounds.size());
    178   else if (!adjusted_bounds.IsEmpty() && adjusted_bounds != window_bounds)
    179     window_->SetBounds(adjusted_bounds);
    180 
    181   // Register accelarators supported by app windows.
    182   // TODO(jeremya/stevenjb): should these be registered for panels too?
    183   views::FocusManager* focus_manager = GetFocusManager();
    184   const std::map<ui::Accelerator, int>& accelerator_table =
    185       GetAcceleratorTable();
    186   for (std::map<ui::Accelerator, int>::const_iterator iter =
    187            accelerator_table.begin();
    188        iter != accelerator_table.end(); ++iter) {
    189     focus_manager->RegisterAccelerator(
    190         iter->first, ui::AcceleratorManager::kNormalPriority, this);
    191   }
    192 
    193 #if defined(OS_WIN)
    194   string16 app_name = UTF8ToWide(
    195       web_app::GenerateApplicationNameFromExtensionId(extension()->id()));
    196   HWND hwnd = GetNativeAppWindowHWND();
    197   ui::win::SetAppIdForWindow(ShellIntegration::GetAppModelIdForProfile(
    198       app_name, profile()->GetPath()), hwnd);
    199 
    200   web_app::UpdateShortcutInfoAndIconForApp(
    201       *extension(), profile(),
    202       base::Bind(&NativeAppWindowViews::OnShortcutInfoLoaded,
    203                  weak_ptr_factory_.GetWeakPtr()));
    204 #endif
    205 }
    206 
    207 #if defined(OS_WIN)
    208 void NativeAppWindowViews::OnShortcutInfoLoaded(
    209     const ShellIntegration::ShortcutInfo& shortcut_info) {
    210   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    211 
    212   HWND hwnd = GetNativeAppWindowHWND();
    213 
    214   // Set window's icon to the one we're about to create/update in the web app
    215   // path. The icon cache will refresh on icon creation.
    216   base::FilePath web_app_path = web_app::GetWebAppDataDirectory(
    217       shortcut_info.profile_path, shortcut_info.extension_id,
    218       shortcut_info.url);
    219   base::FilePath icon_file = web_app_path
    220       .Append(web_app::internals::GetSanitizedFileName(shortcut_info.title))
    221       .ReplaceExtension(FILE_PATH_LITERAL(".ico"));
    222 
    223   content::BrowserThread::PostBlockingPoolTask(
    224       FROM_HERE,
    225       base::Bind(&CreateIconAndSetRelaunchDetails,
    226                  web_app_path, icon_file, shortcut_info, hwnd));
    227 }
    228 
    229 HWND NativeAppWindowViews::GetNativeAppWindowHWND() const {
    230   return views::HWNDForWidget(GetWidget()->GetTopLevelWidget());
    231 }
    232 #endif
    233 
    234 void NativeAppWindowViews::InitializePanelWindow(
    235     const ShellWindow::CreateParams& create_params) {
    236   views::Widget::InitParams params(views::Widget::InitParams::TYPE_PANEL);
    237   params.delegate = this;
    238 
    239   preferred_size_ = gfx::Size(create_params.bounds.width(),
    240                               create_params.bounds.height());
    241   if (preferred_size_.width() == 0)
    242     preferred_size_.set_width(kDefaultPanelWidth);
    243   else if (preferred_size_.width() < kMinPanelWidth)
    244     preferred_size_.set_width(kMinPanelWidth);
    245 
    246   if (preferred_size_.height() == 0)
    247     preferred_size_.set_height(kDefaultPanelHeight);
    248   else if (preferred_size_.height() < kMinPanelHeight)
    249     preferred_size_.set_height(kMinPanelHeight);
    250 #if defined(USE_ASH)
    251   if (ash::Shell::HasInstance()) {
    252     // Open a new panel on the active root window where
    253     // a current active/focused window is on.
    254     aura::RootWindow* active = ash::Shell::GetActiveRootWindow();
    255     params.bounds = ash::ScreenAsh::ConvertRectToScreen(
    256         active, gfx::Rect(preferred_size_));
    257   } else {
    258     params.bounds = gfx::Rect(preferred_size_);
    259   }
    260 #else
    261   params.bounds = gfx::Rect(preferred_size_);
    262 #endif
    263   // TODO(erg): Conceptually, these are toplevel windows, but we theoretically
    264   // could plumb context through to here in some cases.
    265   params.top_level = true;
    266   window_->Init(params);
    267   window_->set_focus_on_creation(create_params.focused);
    268 
    269 #if defined(USE_ASH)
    270   if (create_params.state == ui::SHOW_STATE_DETACHED) {
    271     gfx::Rect window_bounds(create_params.bounds.x(),
    272                             create_params.bounds.y(),
    273                             preferred_size_.width(),
    274                             preferred_size_.height());
    275     aura::Window* native_window = GetNativeWindow();
    276     native_window->SetProperty(ash::internal::kPanelAttachedKey, false);
    277     native_window->SetDefaultParentByRootWindow(
    278         native_window->GetRootWindow(), native_window->GetBoundsInScreen());
    279     window_->SetBounds(window_bounds);
    280   }
    281 #else
    282   // TODO(stevenjb): NativeAppWindow panels need to be implemented for other
    283   // platforms.
    284 #endif
    285 }
    286 
    287 // ui::BaseWindow implementation.
    288 
    289 bool NativeAppWindowViews::IsActive() const {
    290   return window_->IsActive();
    291 }
    292 
    293 bool NativeAppWindowViews::IsMaximized() const {
    294   return window_->IsMaximized();
    295 }
    296 
    297 bool NativeAppWindowViews::IsMinimized() const {
    298   return window_->IsMinimized();
    299 }
    300 
    301 bool NativeAppWindowViews::IsFullscreen() const {
    302   return window_->IsFullscreen();
    303 }
    304 
    305 gfx::NativeWindow NativeAppWindowViews::GetNativeWindow() {
    306   return window_->GetNativeWindow();
    307 }
    308 
    309 gfx::Rect NativeAppWindowViews::GetRestoredBounds() const {
    310   return window_->GetRestoredBounds();
    311 }
    312 
    313 ui::WindowShowState NativeAppWindowViews::GetRestoredState() const {
    314   if (IsMaximized())
    315     return ui::SHOW_STATE_MAXIMIZED;
    316 #if defined(USE_ASH)
    317   // On Ash, restore fullscreen.
    318   if (IsFullscreen())
    319     return ui::SHOW_STATE_FULLSCREEN;
    320 
    321   // Use kRestoreShowStateKey in case a window is minimized/hidden.
    322   ui::WindowShowState restore_state =
    323       window_->GetNativeWindow()->GetProperty(
    324           aura::client::kRestoreShowStateKey);
    325   // Whitelist states to return so that invalid and transient states
    326   // are not saved and used to restore windows when they are recreated.
    327   switch (restore_state) {
    328     case ui::SHOW_STATE_NORMAL:
    329     case ui::SHOW_STATE_MAXIMIZED:
    330     case ui::SHOW_STATE_FULLSCREEN:
    331     case ui::SHOW_STATE_DETACHED:
    332       return restore_state;
    333 
    334     case ui::SHOW_STATE_DEFAULT:
    335     case ui::SHOW_STATE_MINIMIZED:
    336     case ui::SHOW_STATE_INACTIVE:
    337     case ui::SHOW_STATE_END:
    338       return ui::SHOW_STATE_NORMAL;
    339   }
    340 #endif
    341   return ui::SHOW_STATE_NORMAL;
    342 }
    343 
    344 gfx::Rect NativeAppWindowViews::GetBounds() const {
    345   return window_->GetWindowBoundsInScreen();
    346 }
    347 
    348 void NativeAppWindowViews::Show() {
    349   if (window_->IsVisible()) {
    350     window_->Activate();
    351     return;
    352   }
    353 
    354   window_->Show();
    355 }
    356 
    357 void NativeAppWindowViews::ShowInactive() {
    358   if (window_->IsVisible())
    359     return;
    360   window_->ShowInactive();
    361 }
    362 
    363 void NativeAppWindowViews::Hide() {
    364   window_->Hide();
    365 }
    366 
    367 void NativeAppWindowViews::Close() {
    368   window_->Close();
    369 }
    370 
    371 void NativeAppWindowViews::Activate() {
    372   window_->Activate();
    373 }
    374 
    375 void NativeAppWindowViews::Deactivate() {
    376   window_->Deactivate();
    377 }
    378 
    379 void NativeAppWindowViews::Maximize() {
    380   window_->Maximize();
    381 }
    382 
    383 void NativeAppWindowViews::Minimize() {
    384   window_->Minimize();
    385 }
    386 
    387 void NativeAppWindowViews::Restore() {
    388   window_->Restore();
    389 }
    390 
    391 void NativeAppWindowViews::SetBounds(const gfx::Rect& bounds) {
    392   GetWidget()->SetBounds(bounds);
    393 }
    394 
    395 void NativeAppWindowViews::FlashFrame(bool flash) {
    396   window_->FlashFrame(flash);
    397 }
    398 
    399 bool NativeAppWindowViews::IsAlwaysOnTop() const {
    400   if (!shell_window_->window_type_is_panel())
    401     return false;
    402 #if defined(USE_ASH)
    403   return window_->GetNativeWindow()->GetProperty(
    404       ash::internal::kPanelAttachedKey);
    405 #else
    406   return true;
    407 #endif
    408 }
    409 
    410 gfx::Insets NativeAppWindowViews::GetFrameInsets() const {
    411   if (frameless())
    412     return gfx::Insets();
    413 
    414   // The pretend client_bounds passed in need to be large enough to ensure that
    415   // GetWindowBoundsForClientBounds() doesn't decide that it needs more than
    416   // the specified amount of space to fit the window controls in, and return a
    417   // number larger than the real frame insets. Most window controls are smaller
    418   // than 1000x1000px, so this should be big enough.
    419   gfx::Rect client_bounds = gfx::Rect(1000, 1000);
    420   gfx::Rect window_bounds =
    421       window_->non_client_view()->GetWindowBoundsForClientBounds(
    422           client_bounds);
    423   return window_bounds.InsetsFrom(client_bounds);
    424 }
    425 
    426 gfx::NativeView NativeAppWindowViews::GetHostView() const {
    427   return window_->GetNativeView();
    428 }
    429 
    430 gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
    431   gfx::Size shell_window_size = window_->GetWindowBoundsInScreen().size();
    432   return gfx::Point(shell_window_size.width() / 2 - size.width() / 2,
    433                     shell_window_size.height() / 2 - size.height() / 2);
    434 }
    435 
    436 void NativeAppWindowViews::AddObserver(
    437     web_modal::WebContentsModalDialogHostObserver* observer) {
    438   observer_list_.AddObserver(observer);
    439 }
    440 void NativeAppWindowViews::RemoveObserver(
    441     web_modal::WebContentsModalDialogHostObserver* observer) {
    442   observer_list_.RemoveObserver(observer);
    443 }
    444 
    445 // Private method. TODO(stevenjb): Move this below InitializePanelWindow()
    446 // to match declaration order.
    447 void NativeAppWindowViews::OnViewWasResized() {
    448   // TODO(jeremya): this doesn't seem like a terribly elegant way to keep the
    449   // window shape in sync.
    450 #if defined(OS_WIN) && !defined(USE_AURA)
    451   DCHECK(window_);
    452   DCHECK(web_view_);
    453   gfx::Size sz = web_view_->size();
    454   int height = sz.height(), width = sz.width();
    455   if (ShouldUseChromeStyleFrame()) {
    456     // Set the window shape of the RWHV.
    457     const int kCornerRadius = 1;
    458     gfx::Path path;
    459     if (window_->IsMaximized() || window_->IsFullscreen()) {
    460       // Don't round the corners when the window is maximized or fullscreen.
    461       path.addRect(0, 0, width, height);
    462     } else {
    463       if (frameless_) {
    464         path.moveTo(0, kCornerRadius);
    465         path.lineTo(kCornerRadius, 0);
    466         path.lineTo(width - kCornerRadius, 0);
    467         path.lineTo(width, kCornerRadius);
    468       } else {
    469         // Don't round the top corners in chrome-style frame mode.
    470         path.moveTo(0, 0);
    471         path.lineTo(width, 0);
    472       }
    473       path.lineTo(width, height - kCornerRadius - 1);
    474       path.lineTo(width - kCornerRadius - 1, height);
    475       path.lineTo(kCornerRadius + 1, height);
    476       path.lineTo(0, height - kCornerRadius - 1);
    477       path.close();
    478     }
    479     SetWindowRgn(web_contents()->GetView()->GetNativeView(),
    480                  path.CreateNativeRegion(), 1);
    481   }
    482 
    483   SkRegion* rgn = new SkRegion;
    484   if (!window_->IsFullscreen()) {
    485     if (draggable_region())
    486       rgn->op(*draggable_region(), SkRegion::kUnion_Op);
    487     if (!window_->IsMaximized()) {
    488       if (frameless_)
    489         rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
    490       rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
    491       rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
    492           SkRegion::kUnion_Op);
    493       rgn->op(0, height - kResizeInsideBoundsSize, width, height,
    494           SkRegion::kUnion_Op);
    495     }
    496   }
    497   if (web_contents()->GetRenderViewHost()->GetView())
    498     web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
    499 #endif
    500 
    501   FOR_EACH_OBSERVER(web_modal::WebContentsModalDialogHostObserver,
    502                     observer_list_,
    503                     OnPositionRequiresUpdate());
    504 }
    505 
    506 bool NativeAppWindowViews::ShouldUseChromeStyleFrame() const {
    507   return !CommandLine::ForCurrentProcess()->HasSwitch(
    508       switches::kAppsUseNativeFrame) || frameless_;
    509 }
    510 
    511 // WidgetDelegate implementation.
    512 
    513 void NativeAppWindowViews::OnWidgetMove() {
    514   shell_window_->OnNativeWindowChanged();
    515 }
    516 
    517 views::View* NativeAppWindowViews::GetInitiallyFocusedView() {
    518   return web_view_;
    519 }
    520 
    521 bool NativeAppWindowViews::CanResize() const {
    522   return resizable_ &&
    523       (maximum_size_.IsEmpty() || minimum_size_ != maximum_size_);
    524 }
    525 
    526 bool NativeAppWindowViews::CanMaximize() const {
    527   return resizable_ && maximum_size_.IsEmpty();
    528 }
    529 
    530 string16 NativeAppWindowViews::GetWindowTitle() const {
    531   return shell_window_->GetTitle();
    532 }
    533 
    534 bool NativeAppWindowViews::ShouldShowWindowTitle() const {
    535   return shell_window_->window_type() == ShellWindow::WINDOW_TYPE_V1_PANEL;
    536 }
    537 
    538 gfx::ImageSkia NativeAppWindowViews::GetWindowAppIcon() {
    539   gfx::Image app_icon = shell_window_->app_icon();
    540   if (app_icon.IsEmpty())
    541     return GetWindowIcon();
    542   else
    543     return *app_icon.ToImageSkia();
    544 }
    545 
    546 gfx::ImageSkia NativeAppWindowViews::GetWindowIcon() {
    547   content::WebContents* web_contents = shell_window_->web_contents();
    548   if (web_contents) {
    549     FaviconTabHelper* favicon_tab_helper =
    550         FaviconTabHelper::FromWebContents(web_contents);
    551     gfx::Image app_icon = favicon_tab_helper->GetFavicon();
    552     if (!app_icon.IsEmpty())
    553       return *app_icon.ToImageSkia();
    554   }
    555   return gfx::ImageSkia();
    556 }
    557 
    558 bool NativeAppWindowViews::ShouldShowWindowIcon() const {
    559   return shell_window_->window_type() == ShellWindow::WINDOW_TYPE_V1_PANEL;
    560 }
    561 
    562 void NativeAppWindowViews::SaveWindowPlacement(const gfx::Rect& bounds,
    563                                                ui::WindowShowState show_state) {
    564   views::WidgetDelegate::SaveWindowPlacement(bounds, show_state);
    565   shell_window_->OnNativeWindowChanged();
    566 }
    567 
    568 void NativeAppWindowViews::DeleteDelegate() {
    569   window_->RemoveObserver(this);
    570   shell_window_->OnNativeClose();
    571 }
    572 
    573 views::Widget* NativeAppWindowViews::GetWidget() {
    574   return window_;
    575 }
    576 
    577 const views::Widget* NativeAppWindowViews::GetWidget() const {
    578   return window_;
    579 }
    580 
    581 views::NonClientFrameView* NativeAppWindowViews::CreateNonClientFrameView(
    582     views::Widget* widget) {
    583 #if defined(USE_ASH)
    584   if (chrome::IsNativeViewInAsh(widget->GetNativeView())) {
    585     if (shell_window_->window_type_is_panel()) {
    586       ash::PanelFrameView::FrameType frame_type = frameless_ ?
    587           ash::PanelFrameView::FRAME_NONE : ash::PanelFrameView::FRAME_ASH;
    588       return new ash::PanelFrameView(widget, frame_type);
    589     }
    590     if (!frameless_) {
    591       ash::CustomFrameViewAsh* frame = new ash::CustomFrameViewAsh();
    592       frame->Init(widget);
    593       return frame;
    594     }
    595   }
    596 #endif
    597   if (ShouldUseChromeStyleFrame()) {
    598     ShellWindowFrameView* frame_view = new ShellWindowFrameView(this);
    599     frame_view->Init(window_);
    600     return frame_view;
    601   }
    602   return views::WidgetDelegateView::CreateNonClientFrameView(widget);
    603 }
    604 
    605 bool NativeAppWindowViews::ShouldDescendIntoChildForEventHandling(
    606     gfx::NativeView child,
    607     const gfx::Point& location) {
    608 #if defined(USE_AURA)
    609   if (child == web_view_->web_contents()->GetView()->GetNativeView()) {
    610     // Shell window should claim mouse events that fall within the draggable
    611     // region.
    612     return !draggable_region_.get() ||
    613            !draggable_region_->contains(location.x(), location.y());
    614   }
    615 #endif
    616 
    617   return true;
    618 }
    619 
    620 // WidgetObserver implementation.
    621 
    622 void NativeAppWindowViews::OnWidgetVisibilityChanged(views::Widget* widget,
    623                                                      bool visible) {
    624   shell_window_->OnNativeWindowChanged();
    625 }
    626 
    627 void NativeAppWindowViews::OnWidgetActivationChanged(views::Widget* widget,
    628                                                      bool active) {
    629   shell_window_->OnNativeWindowChanged();
    630   if (active)
    631     shell_window_->OnNativeWindowActivated();
    632 }
    633 
    634 // WebContentsObserver implementation.
    635 
    636 void NativeAppWindowViews::RenderViewCreated(
    637     content::RenderViewHost* render_view_host) {
    638   if (transparent_background_) {
    639     // Use a background with transparency to trigger transparency in Webkit.
    640     SkBitmap background;
    641     background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
    642     background.allocPixels();
    643     background.eraseARGB(0x00, 0x00, 0x00, 0x00);
    644 
    645     content::RenderWidgetHostView* view = render_view_host->GetView();
    646     DCHECK(view);
    647     view->SetBackground(background);
    648   }
    649 }
    650 
    651 // views::View implementation.
    652 
    653 void NativeAppWindowViews::Layout() {
    654   DCHECK(web_view_);
    655   web_view_->SetBounds(0, 0, width(), height());
    656   OnViewWasResized();
    657 }
    658 
    659 void NativeAppWindowViews::ViewHierarchyChanged(
    660     const ViewHierarchyChangedDetails& details) {
    661   if (details.is_add && details.child == this) {
    662     web_view_ = new views::WebView(NULL);
    663     AddChildView(web_view_);
    664     web_view_->SetWebContents(web_contents());
    665   }
    666 }
    667 
    668 gfx::Size NativeAppWindowViews::GetPreferredSize() {
    669   if (!preferred_size_.IsEmpty())
    670     return preferred_size_;
    671   return views::View::GetPreferredSize();
    672 }
    673 
    674 gfx::Size NativeAppWindowViews::GetMinimumSize() {
    675   return minimum_size_;
    676 }
    677 
    678 gfx::Size NativeAppWindowViews::GetMaximumSize() {
    679   return maximum_size_;
    680 }
    681 
    682 void NativeAppWindowViews::OnFocus() {
    683   web_view_->RequestFocus();
    684 }
    685 
    686 bool NativeAppWindowViews::AcceleratorPressed(
    687     const ui::Accelerator& accelerator) {
    688   const std::map<ui::Accelerator, int>& accelerator_table =
    689       GetAcceleratorTable();
    690   std::map<ui::Accelerator, int>::const_iterator iter =
    691       accelerator_table.find(accelerator);
    692   DCHECK(iter != accelerator_table.end());
    693   int command_id = iter->second;
    694   switch (command_id) {
    695     case IDC_CLOSE_WINDOW:
    696       Close();
    697       return true;
    698     default:
    699       NOTREACHED() << "Unknown accelerator sent to app window.";
    700   }
    701   return false;
    702 }
    703 
    704 // NativeAppWindow implementation.
    705 
    706 void NativeAppWindowViews::SetFullscreen(bool fullscreen) {
    707   // Fullscreen not supported by panels.
    708   if (shell_window_->window_type_is_panel())
    709     return;
    710   is_fullscreen_ = fullscreen;
    711   window_->SetFullscreen(fullscreen);
    712   // TODO(jeremya) we need to call RenderViewHost::ExitFullscreen() if we
    713   // ever drop the window out of fullscreen in response to something that
    714   // wasn't the app calling webkitCancelFullScreen().
    715 }
    716 
    717 bool NativeAppWindowViews::IsFullscreenOrPending() const {
    718   return is_fullscreen_;
    719 }
    720 
    721 bool NativeAppWindowViews::IsDetached() const {
    722   if (!shell_window_->window_type_is_panel())
    723     return false;
    724 #if defined(USE_ASH)
    725   return !window_->GetNativeWindow()->GetProperty(
    726       ash::internal::kPanelAttachedKey);
    727 #else
    728   return false;
    729 #endif
    730 }
    731 
    732 views::View* NativeAppWindowViews::GetContentsView() {
    733   return this;
    734 }
    735 
    736 void NativeAppWindowViews::UpdateWindowIcon() {
    737   window_->UpdateWindowIcon();
    738 }
    739 
    740 void NativeAppWindowViews::UpdateWindowTitle() {
    741   window_->UpdateWindowTitle();
    742 }
    743 
    744 void NativeAppWindowViews::UpdateDraggableRegions(
    745     const std::vector<extensions::DraggableRegion>& regions) {
    746   // Draggable region is not supported for non-frameless window.
    747   if (!frameless_)
    748     return;
    749 
    750   draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
    751   OnViewWasResized();
    752 }
    753 
    754 void NativeAppWindowViews::HandleKeyboardEvent(
    755     const content::NativeWebKeyboardEvent& event) {
    756   unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
    757                                                         GetFocusManager());
    758 }
    759 
    760 void NativeAppWindowViews::RenderViewHostChanged() {
    761   OnViewWasResized();
    762 }
    763