1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/apps/native_app_window_views.h"
7 #include "apps/shell_window.h"
8 #include "apps/ui/views/shell_window_frame_view.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/path_service.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/app/chrome_command_ids.h"
14 #include "chrome/browser/extensions/extension_host.h"
15 #include "chrome/browser/favicon/favicon_tab_helper.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/host_desktop.h"
18 #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h"
19 #include "chrome/browser/web_applications/web_app.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/extension.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/browser/web_contents_view.h"
27 #include "extensions/common/draggable_region.h"
28 #include "ui/views/controls/webview/webview.h"
29 #include "ui/views/widget/widget.h"
30 #include "ui/views/window/non_client_view.h"
33 #include "base/strings/utf_string_conversions.h"
34 #include "chrome/browser/ui/web_applications/web_app_ui.h"
35 #include "chrome/browser/web_applications/web_app_win.h"
36 #include "ui/base/win/shell.h"
37 #include "ui/views/win/hwnd_util.h"
41 #include "chrome/browser/shell_integration_linux.h"
45 #include "ash/ash_constants.h"
46 #include "ash/screen_ash.h"
47 #include "ash/shell.h"
48 #include "ash/wm/custom_frame_view_ash.h"
49 #include "ash/wm/panels/panel_frame_view.h"
50 #include "ash/wm/window_state.h"
51 #include "ash/wm/window_state_delegate.h"
52 #include "chrome/browser/ui/ash/ash_util.h"
53 #include "ui/aura/client/aura_constants.h"
54 #include "ui/aura/client/window_tree_client.h"
55 #include "ui/aura/window.h"
59 #include "ui/aura/window.h"
62 using apps::ShellWindow;
66 const int kMinPanelWidth = 100;
67 const int kMinPanelHeight = 100;
68 const int kDefaultPanelWidth = 200;
69 const int kDefaultPanelHeight = 300;
70 const int kResizeInsideBoundsSize = 5;
71 const int kResizeAreaCornerSize = 16;
73 struct AcceleratorMapping {
74 ui::KeyboardCode keycode;
78 const AcceleratorMapping kAppWindowAcceleratorMap[] = {
79 { ui::VKEY_W, ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
80 { ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_CLOSE_WINDOW },
81 { ui::VKEY_F4, ui::EF_ALT_DOWN, IDC_CLOSE_WINDOW },
84 const std::map<ui::Accelerator, int>& GetAcceleratorTable() {
85 typedef std::map<ui::Accelerator, int> AcceleratorMap;
86 CR_DEFINE_STATIC_LOCAL(AcceleratorMap, accelerators, ());
87 if (accelerators.empty()) {
88 for (size_t i = 0; i < arraysize(kAppWindowAcceleratorMap); ++i) {
89 ui::Accelerator accelerator(kAppWindowAcceleratorMap[i].keycode,
90 kAppWindowAcceleratorMap[i].modifiers);
91 accelerators[accelerator] = kAppWindowAcceleratorMap[i].command_id;
98 void CreateIconAndSetRelaunchDetails(
99 const base::FilePath web_app_path,
100 const base::FilePath icon_file,
101 const ShellIntegration::ShortcutInfo& shortcut_info,
103 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
105 // Set the relaunch data so "Pin this program to taskbar" has the app's
107 CommandLine command_line = ShellIntegration::CommandLineArgsForLauncher(
109 shortcut_info.extension_id,
110 shortcut_info.profile_path);
112 base::FilePath chrome_exe;
113 if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
117 command_line.SetProgram(chrome_exe);
118 ui::win::SetRelaunchDetailsForWindow(command_line.GetCommandLineString(),
119 shortcut_info.title, hwnd);
121 if (!base::PathExists(web_app_path) &&
122 !file_util::CreateDirectory(web_app_path)) {
125 ui::win::SetAppIconForWindow(icon_file.value(), hwnd);
126 web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info.favicon);
131 // This class handles a user's fullscreen request (Shift+F4/F4).
132 class NativeAppWindowStateDelegate : public ash::wm::WindowStateDelegate {
134 explicit NativeAppWindowStateDelegate(ShellWindow* shell_window)
135 : shell_window_(shell_window) {
136 DCHECK(shell_window_);
138 virtual ~NativeAppWindowStateDelegate(){}
140 // Overridden from ash::wm::WindowStateDelegate.
141 virtual bool ToggleFullscreen(ash::wm::WindowState* window_state) OVERRIDE {
142 // Windows which cannot be maximized should not be fullscreened.
143 DCHECK(window_state->IsFullscreen() || window_state->CanMaximize());
144 if (window_state->IsFullscreen())
145 shell_window_->Restore();
146 else if (window_state->CanMaximize())
147 shell_window_->Fullscreen();
152 ShellWindow* shell_window_; // not owned.
154 DISALLOW_COPY_AND_ASSIGN(NativeAppWindowStateDelegate);
160 NativeAppWindowViews::NativeAppWindowViews(
161 ShellWindow* shell_window,
162 const ShellWindow::CreateParams& create_params)
163 : shell_window_(shell_window),
166 is_fullscreen_(false),
167 frameless_(create_params.frame == ShellWindow::FRAME_NONE),
168 transparent_background_(create_params.transparent_background),
169 resizable_(create_params.resizable),
170 weak_ptr_factory_(this) {
171 Observe(web_contents());
173 window_ = new views::Widget;
174 if (create_params.window_type == ShellWindow::WINDOW_TYPE_PANEL ||
175 create_params.window_type == ShellWindow::WINDOW_TYPE_V1_PANEL) {
176 InitializePanelWindow(create_params);
178 InitializeDefaultWindow(create_params);
180 extension_keybinding_registry_.reset(
181 new ExtensionKeybindingRegistryViews(
183 window_->GetFocusManager(),
184 extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY,
188 window_->AddObserver(this);
190 if (chrome::GetHostDesktopTypeForNativeView(GetNativeWindow()) ==
191 chrome::HOST_DESKTOP_TYPE_ASH) {
192 ash::wm::GetWindowState(GetNativeWindow())->SetDelegate(
193 scoped_ptr<ash::wm::WindowStateDelegate>(
194 new NativeAppWindowStateDelegate(shell_window)).Pass());
199 NativeAppWindowViews::~NativeAppWindowViews() {
200 web_view_->SetWebContents(NULL);
203 void NativeAppWindowViews::InitializeDefaultWindow(
204 const ShellWindow::CreateParams& create_params) {
205 std::string app_name =
206 web_app::GenerateApplicationNameFromExtensionId(extension()->id());
208 views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
209 init_params.delegate = this;
210 init_params.remove_standard_frame = ShouldUseChromeStyleFrame();
211 init_params.use_system_default_icon = true;
212 // TODO(erg): Conceptually, these are toplevel windows, but we theoretically
213 // could plumb context through to here in some cases.
214 init_params.top_level = true;
215 init_params.opacity = create_params.transparent_background
216 ? views::Widget::InitParams::TRANSLUCENT_WINDOW
217 : views::Widget::InitParams::INFER_OPACITY;
218 init_params.keep_on_top = create_params.always_on_top;
219 gfx::Rect window_bounds = create_params.bounds;
220 bool position_specified =
221 window_bounds.x() != INT_MIN && window_bounds.y() != INT_MIN;
222 if (position_specified && !window_bounds.IsEmpty())
223 init_params.bounds = window_bounds;
225 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
226 // Set up a custom WM_CLASS for app windows. This allows task switchers in
227 // X11 environments to distinguish them from main browser windows.
228 init_params.wm_class_name = web_app::GetWMClassFromAppName(app_name);
229 init_params.wm_class_class = ShellIntegrationLinux::GetProgramClassName();
232 window_->Init(init_params);
234 gfx::Rect adjusted_bounds = window_bounds;
235 adjusted_bounds.Inset(-GetFrameInsets());
236 // Center window if no position was specified.
237 if (!position_specified)
238 window_->CenterWindow(adjusted_bounds.size());
239 else if (!adjusted_bounds.IsEmpty() && adjusted_bounds != window_bounds)
240 window_->SetBounds(adjusted_bounds);
242 // Register accelarators supported by app windows.
243 // TODO(jeremya/stevenjb): should these be registered for panels too?
244 views::FocusManager* focus_manager = GetFocusManager();
245 const std::map<ui::Accelerator, int>& accelerator_table =
246 GetAcceleratorTable();
247 for (std::map<ui::Accelerator, int>::const_iterator iter =
248 accelerator_table.begin();
249 iter != accelerator_table.end(); ++iter) {
250 focus_manager->RegisterAccelerator(
251 iter->first, ui::AcceleratorManager::kNormalPriority, this);
255 string16 app_name_wide = UTF8ToWide(app_name);
256 HWND hwnd = GetNativeAppWindowHWND();
257 ui::win::SetAppIdForWindow(ShellIntegration::GetAppModelIdForProfile(
258 app_name_wide, profile()->GetPath()), hwnd);
260 web_app::UpdateShortcutInfoAndIconForApp(
261 *extension(), profile(),
262 base::Bind(&NativeAppWindowViews::OnShortcutInfoLoaded,
263 weak_ptr_factory_.GetWeakPtr()));
268 void NativeAppWindowViews::OnShortcutInfoLoaded(
269 const ShellIntegration::ShortcutInfo& shortcut_info) {
270 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
272 HWND hwnd = GetNativeAppWindowHWND();
274 // Set window's icon to the one we're about to create/update in the web app
275 // path. The icon cache will refresh on icon creation.
276 base::FilePath web_app_path = web_app::GetWebAppDataDirectory(
277 shortcut_info.profile_path, shortcut_info.extension_id,
279 base::FilePath icon_file = web_app_path
280 .Append(web_app::internals::GetSanitizedFileName(shortcut_info.title))
281 .ReplaceExtension(FILE_PATH_LITERAL(".ico"));
283 content::BrowserThread::PostBlockingPoolTask(
285 base::Bind(&CreateIconAndSetRelaunchDetails,
286 web_app_path, icon_file, shortcut_info, hwnd));
289 HWND NativeAppWindowViews::GetNativeAppWindowHWND() const {
290 return views::HWNDForWidget(GetWidget()->GetTopLevelWidget());
294 void NativeAppWindowViews::InitializePanelWindow(
295 const ShellWindow::CreateParams& create_params) {
296 views::Widget::InitParams params(views::Widget::InitParams::TYPE_PANEL);
297 params.delegate = this;
299 preferred_size_ = gfx::Size(create_params.bounds.width(),
300 create_params.bounds.height());
301 if (preferred_size_.width() == 0)
302 preferred_size_.set_width(kDefaultPanelWidth);
303 else if (preferred_size_.width() < kMinPanelWidth)
304 preferred_size_.set_width(kMinPanelWidth);
306 if (preferred_size_.height() == 0)
307 preferred_size_.set_height(kDefaultPanelHeight);
308 else if (preferred_size_.height() < kMinPanelHeight)
309 preferred_size_.set_height(kMinPanelHeight);
311 if (ash::Shell::HasInstance()) {
312 // Open a new panel on the target root.
313 aura::Window* target = ash::Shell::GetTargetRootWindow();
314 params.bounds = ash::ScreenAsh::ConvertRectToScreen(
315 target, gfx::Rect(preferred_size_));
317 params.bounds = gfx::Rect(preferred_size_);
320 params.bounds = gfx::Rect(preferred_size_);
322 // TODO(erg): Conceptually, these are toplevel windows, but we theoretically
323 // could plumb context through to here in some cases.
324 params.top_level = true;
325 window_->Init(params);
326 window_->set_focus_on_creation(create_params.focused);
329 if (create_params.state == ui::SHOW_STATE_DETACHED) {
330 gfx::Rect window_bounds(create_params.bounds.x(),
331 create_params.bounds.y(),
332 preferred_size_.width(),
333 preferred_size_.height());
334 aura::Window* native_window = GetNativeWindow();
335 ash::wm::GetWindowState(native_window)->set_panel_attached(false);
336 aura::client::ParentWindowWithContext(native_window,
337 native_window->GetRootWindow(),
338 native_window->GetBoundsInScreen());
339 window_->SetBounds(window_bounds);
342 // TODO(stevenjb): NativeAppWindow panels need to be implemented for other
347 bool NativeAppWindowViews::ShouldUseChromeStyleFrame() const {
348 return !CommandLine::ForCurrentProcess()->HasSwitch(
349 switches::kAppsUseNativeFrame) || frameless_;
352 apps::ShellWindowFrameView* NativeAppWindowViews::CreateShellWindowFrameView() {
353 // By default the user can resize the window from slightly inside the bounds.
354 int resize_inside_bounds_size = kResizeInsideBoundsSize;
355 int resize_outside_bounds_size = 0;
356 int resize_outside_scale_for_touch = 1;
357 int resize_area_corner_size = kResizeAreaCornerSize;
359 // For Aura windows on the Ash desktop the sizes are different and the user
360 // can resize the window from slightly outside the bounds as well.
361 if (chrome::IsNativeWindowInAsh(window_->GetNativeWindow())) {
362 resize_inside_bounds_size = ash::kResizeInsideBoundsSize;
363 resize_outside_bounds_size = ash::kResizeOutsideBoundsSize;
364 resize_outside_scale_for_touch = ash::kResizeOutsideBoundsScaleForTouch;
365 resize_area_corner_size = ash::kResizeAreaCornerSize;
368 apps::ShellWindowFrameView* frame_view = new apps::ShellWindowFrameView(this);
369 frame_view->Init(window_,
370 resize_inside_bounds_size,
371 resize_outside_bounds_size,
372 resize_outside_scale_for_touch,
373 resize_area_corner_size);
377 // ui::BaseWindow implementation.
379 bool NativeAppWindowViews::IsActive() const {
380 return window_->IsActive();
383 bool NativeAppWindowViews::IsMaximized() const {
384 return window_->IsMaximized();
387 bool NativeAppWindowViews::IsMinimized() const {
388 return window_->IsMinimized();
391 bool NativeAppWindowViews::IsFullscreen() const {
392 return window_->IsFullscreen();
395 gfx::NativeWindow NativeAppWindowViews::GetNativeWindow() {
396 return window_->GetNativeWindow();
399 gfx::Rect NativeAppWindowViews::GetRestoredBounds() const {
400 return window_->GetRestoredBounds();
403 ui::WindowShowState NativeAppWindowViews::GetRestoredState() const {
405 return ui::SHOW_STATE_MAXIMIZED;
407 return ui::SHOW_STATE_FULLSCREEN;
409 // Use kRestoreShowStateKey in case a window is minimized/hidden.
410 ui::WindowShowState restore_state =
411 window_->GetNativeWindow()->GetProperty(
412 aura::client::kRestoreShowStateKey);
413 // Whitelist states to return so that invalid and transient states
414 // are not saved and used to restore windows when they are recreated.
415 switch (restore_state) {
416 case ui::SHOW_STATE_NORMAL:
417 case ui::SHOW_STATE_MAXIMIZED:
418 case ui::SHOW_STATE_FULLSCREEN:
419 case ui::SHOW_STATE_DETACHED:
420 return restore_state;
422 case ui::SHOW_STATE_DEFAULT:
423 case ui::SHOW_STATE_MINIMIZED:
424 case ui::SHOW_STATE_INACTIVE:
425 case ui::SHOW_STATE_END:
426 return ui::SHOW_STATE_NORMAL;
429 return ui::SHOW_STATE_NORMAL;
432 gfx::Rect NativeAppWindowViews::GetBounds() const {
433 return window_->GetWindowBoundsInScreen();
436 void NativeAppWindowViews::Show() {
437 if (window_->IsVisible()) {
445 void NativeAppWindowViews::ShowInactive() {
446 if (window_->IsVisible())
448 window_->ShowInactive();
451 void NativeAppWindowViews::Hide() {
455 void NativeAppWindowViews::Close() {
459 void NativeAppWindowViews::Activate() {
463 void NativeAppWindowViews::Deactivate() {
464 window_->Deactivate();
467 void NativeAppWindowViews::Maximize() {
471 void NativeAppWindowViews::Minimize() {
475 void NativeAppWindowViews::Restore() {
479 void NativeAppWindowViews::SetBounds(const gfx::Rect& bounds) {
480 GetWidget()->SetBounds(bounds);
483 void NativeAppWindowViews::FlashFrame(bool flash) {
484 window_->FlashFrame(flash);
487 bool NativeAppWindowViews::IsAlwaysOnTop() const {
488 if (shell_window_->window_type_is_panel()) {
490 return ash::wm::GetWindowState(window_->GetNativeWindow())->
496 return window_->IsAlwaysOnTop();
500 void NativeAppWindowViews::SetAlwaysOnTop(bool always_on_top) {
501 window_->SetAlwaysOnTop(always_on_top);
502 shell_window_->OnNativeWindowChanged();
505 gfx::NativeView NativeAppWindowViews::GetHostView() const {
506 return window_->GetNativeView();
509 gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
510 gfx::Size shell_window_size = window_->GetWindowBoundsInScreen().size();
511 return gfx::Point(shell_window_size.width() / 2 - size.width() / 2,
512 shell_window_size.height() / 2 - size.height() / 2);
515 gfx::Size NativeAppWindowViews::GetMaximumDialogSize() {
516 return window_->GetWindowBoundsInScreen().size();
519 void NativeAppWindowViews::AddObserver(
520 web_modal::ModalDialogHostObserver* observer) {
521 observer_list_.AddObserver(observer);
523 void NativeAppWindowViews::RemoveObserver(
524 web_modal::ModalDialogHostObserver* observer) {
525 observer_list_.RemoveObserver(observer);
528 // Private method. TODO(stevenjb): Move this below InitializePanelWindow()
529 // to match declaration order.
530 void NativeAppWindowViews::OnViewWasResized() {
531 // TODO(jeremya): this doesn't seem like a terribly elegant way to keep the
532 // window shape in sync.
533 #if defined(OS_WIN) && !defined(USE_AURA)
536 gfx::Size sz = web_view_->size();
537 int height = sz.height(), width = sz.width();
538 if (ShouldUseChromeStyleFrame()) {
539 // Set the window shape of the RWHV.
540 const int kCornerRadius = 1;
542 if (window_->IsMaximized() || window_->IsFullscreen()) {
543 // Don't round the corners when the window is maximized or fullscreen.
544 path.addRect(0, 0, width, height);
547 path.moveTo(0, kCornerRadius);
548 path.lineTo(kCornerRadius, 0);
549 path.lineTo(width - kCornerRadius, 0);
550 path.lineTo(width, kCornerRadius);
552 // Don't round the top corners in chrome-style frame mode.
554 path.lineTo(width, 0);
556 path.lineTo(width, height - kCornerRadius - 1);
557 path.lineTo(width - kCornerRadius - 1, height);
558 path.lineTo(kCornerRadius + 1, height);
559 path.lineTo(0, height - kCornerRadius - 1);
562 SetWindowRgn(web_contents()->GetView()->GetNativeView(),
563 path.CreateNativeRegion(), 1);
566 SkRegion* rgn = new SkRegion;
567 if (!window_->IsFullscreen()) {
568 if (draggable_region_)
569 rgn->op(*draggable_region_, SkRegion::kUnion_Op);
570 if (!window_->IsMaximized()) {
572 rgn->op(0, 0, width, kResizeInsideBoundsSize, SkRegion::kUnion_Op);
573 rgn->op(0, 0, kResizeInsideBoundsSize, height, SkRegion::kUnion_Op);
574 rgn->op(width - kResizeInsideBoundsSize, 0, width, height,
575 SkRegion::kUnion_Op);
576 rgn->op(0, height - kResizeInsideBoundsSize, width, height,
577 SkRegion::kUnion_Op);
580 if (web_contents()->GetRenderViewHost()->GetView())
581 web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn);
584 FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver,
586 OnPositionRequiresUpdate());
589 // WidgetDelegate implementation.
591 void NativeAppWindowViews::OnWidgetMove() {
592 shell_window_->OnNativeWindowChanged();
595 views::View* NativeAppWindowViews::GetInitiallyFocusedView() {
599 bool NativeAppWindowViews::CanResize() const {
600 return resizable_ && !shell_window_->size_constraints().HasFixedSize();
603 bool NativeAppWindowViews::CanMaximize() const {
604 return resizable_ && !shell_window_->size_constraints().HasMaximumSize() &&
605 !shell_window_->window_type_is_panel();
608 string16 NativeAppWindowViews::GetWindowTitle() const {
609 return shell_window_->GetTitle();
612 bool NativeAppWindowViews::ShouldShowWindowTitle() const {
613 return shell_window_->window_type() == ShellWindow::WINDOW_TYPE_V1_PANEL;
616 gfx::ImageSkia NativeAppWindowViews::GetWindowAppIcon() {
617 gfx::Image app_icon = shell_window_->app_icon();
618 if (app_icon.IsEmpty())
619 return GetWindowIcon();
621 return *app_icon.ToImageSkia();
624 gfx::ImageSkia NativeAppWindowViews::GetWindowIcon() {
625 content::WebContents* web_contents = shell_window_->web_contents();
627 FaviconTabHelper* favicon_tab_helper =
628 FaviconTabHelper::FromWebContents(web_contents);
629 gfx::Image app_icon = favicon_tab_helper->GetFavicon();
630 if (!app_icon.IsEmpty())
631 return *app_icon.ToImageSkia();
633 return gfx::ImageSkia();
636 bool NativeAppWindowViews::ShouldShowWindowIcon() const {
637 return shell_window_->window_type() == ShellWindow::WINDOW_TYPE_V1_PANEL;
640 void NativeAppWindowViews::SaveWindowPlacement(const gfx::Rect& bounds,
641 ui::WindowShowState show_state) {
642 views::WidgetDelegate::SaveWindowPlacement(bounds, show_state);
643 shell_window_->OnNativeWindowChanged();
646 void NativeAppWindowViews::DeleteDelegate() {
647 window_->RemoveObserver(this);
648 shell_window_->OnNativeClose();
651 views::Widget* NativeAppWindowViews::GetWidget() {
655 const views::Widget* NativeAppWindowViews::GetWidget() const {
659 views::View* NativeAppWindowViews::GetContentsView() {
663 views::NonClientFrameView* NativeAppWindowViews::CreateNonClientFrameView(
664 views::Widget* widget) {
666 if (chrome::IsNativeViewInAsh(widget->GetNativeView())) {
667 if (shell_window_->window_type_is_panel()) {
668 ash::PanelFrameView::FrameType frame_type = frameless_ ?
669 ash::PanelFrameView::FRAME_NONE : ash::PanelFrameView::FRAME_ASH;
670 return new ash::PanelFrameView(widget, frame_type);
673 return new ash::CustomFrameViewAsh(widget);
677 if (ShouldUseChromeStyleFrame())
678 return CreateShellWindowFrameView();
679 return views::WidgetDelegateView::CreateNonClientFrameView(widget);
682 bool NativeAppWindowViews::WidgetHasHitTestMask() const {
683 return input_region_ != NULL;
686 void NativeAppWindowViews::GetWidgetHitTestMask(gfx::Path* mask) const {
687 input_region_->getBoundaryPath(mask);
690 bool NativeAppWindowViews::ShouldDescendIntoChildForEventHandling(
691 gfx::NativeView child,
692 const gfx::Point& location) {
693 #if defined(USE_AURA)
694 if (child->Contains(web_view_->web_contents()->GetView()->GetNativeView())) {
695 // Shell window should claim mouse events that fall within the draggable
697 return !draggable_region_.get() ||
698 !draggable_region_->contains(location.x(), location.y());
705 // WidgetObserver implementation.
707 void NativeAppWindowViews::OnWidgetVisibilityChanged(views::Widget* widget,
709 shell_window_->OnNativeWindowChanged();
712 void NativeAppWindowViews::OnWidgetActivationChanged(views::Widget* widget,
714 shell_window_->OnNativeWindowChanged();
716 shell_window_->OnNativeWindowActivated();
719 // WebContentsObserver implementation.
721 void NativeAppWindowViews::RenderViewCreated(
722 content::RenderViewHost* render_view_host) {
723 if (transparent_background_) {
724 // Use a background with transparency to trigger transparency in Webkit.
726 background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
727 background.allocPixels();
728 background.eraseARGB(0x00, 0x00, 0x00, 0x00);
730 content::RenderWidgetHostView* view = render_view_host->GetView();
732 view->SetBackground(background);
736 void NativeAppWindowViews::RenderViewHostChanged(
737 content::RenderViewHost* old_host,
738 content::RenderViewHost* new_host) {
742 // views::View implementation.
744 void NativeAppWindowViews::Layout() {
746 web_view_->SetBounds(0, 0, width(), height());
750 void NativeAppWindowViews::ViewHierarchyChanged(
751 const ViewHierarchyChangedDetails& details) {
752 if (details.is_add && details.child == this) {
753 web_view_ = new views::WebView(NULL);
754 AddChildView(web_view_);
755 web_view_->SetWebContents(web_contents());
759 gfx::Size NativeAppWindowViews::GetPreferredSize() {
760 if (!preferred_size_.IsEmpty())
761 return preferred_size_;
762 return views::View::GetPreferredSize();
765 gfx::Size NativeAppWindowViews::GetMinimumSize() {
766 return shell_window_->size_constraints().GetMinimumSize();
769 gfx::Size NativeAppWindowViews::GetMaximumSize() {
770 return shell_window_->size_constraints().GetMaximumSize();
773 void NativeAppWindowViews::OnFocus() {
774 web_view_->RequestFocus();
777 bool NativeAppWindowViews::AcceleratorPressed(
778 const ui::Accelerator& accelerator) {
779 const std::map<ui::Accelerator, int>& accelerator_table =
780 GetAcceleratorTable();
781 std::map<ui::Accelerator, int>::const_iterator iter =
782 accelerator_table.find(accelerator);
783 DCHECK(iter != accelerator_table.end());
784 int command_id = iter->second;
785 switch (command_id) {
786 case IDC_CLOSE_WINDOW:
790 NOTREACHED() << "Unknown accelerator sent to app window.";
795 // NativeAppWindow implementation.
797 void NativeAppWindowViews::SetFullscreen(bool fullscreen) {
798 // Fullscreen not supported by panels.
799 if (shell_window_->window_type_is_panel())
801 is_fullscreen_ = fullscreen;
802 window_->SetFullscreen(fullscreen);
803 // TODO(jeremya) we need to call RenderViewHost::ExitFullscreen() if we
804 // ever drop the window out of fullscreen in response to something that
805 // wasn't the app calling webkitCancelFullScreen().
808 bool NativeAppWindowViews::IsFullscreenOrPending() const {
809 return is_fullscreen_;
812 bool NativeAppWindowViews::IsDetached() const {
813 if (!shell_window_->window_type_is_panel())
816 return !ash::wm::GetWindowState(window_->GetNativeWindow())->panel_attached();
822 void NativeAppWindowViews::UpdateWindowIcon() {
823 window_->UpdateWindowIcon();
826 void NativeAppWindowViews::UpdateWindowTitle() {
827 window_->UpdateWindowTitle();
830 void NativeAppWindowViews::UpdateDraggableRegions(
831 const std::vector<extensions::DraggableRegion>& regions) {
832 // Draggable region is not supported for non-frameless window.
836 draggable_region_.reset(ShellWindow::RawDraggableRegionsToSkRegion(regions));
840 SkRegion* NativeAppWindowViews::GetDraggableRegion() {
841 return draggable_region_.get();
844 void NativeAppWindowViews::UpdateInputRegion(scoped_ptr<SkRegion> region) {
845 input_region_ = region.Pass();
847 #if defined(USE_AURA)
849 window_->SetShape(new SkRegion(*input_region_));
851 window_->SetShape(NULL);
852 #endif // defined(USE_AURA)
855 void NativeAppWindowViews::HandleKeyboardEvent(
856 const content::NativeWebKeyboardEvent& event) {
857 unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
861 bool NativeAppWindowViews::IsFrameless() const {
865 gfx::Insets NativeAppWindowViews::GetFrameInsets() const {
867 return gfx::Insets();
869 // The pretend client_bounds passed in need to be large enough to ensure that
870 // GetWindowBoundsForClientBounds() doesn't decide that it needs more than
871 // the specified amount of space to fit the window controls in, and return a
872 // number larger than the real frame insets. Most window controls are smaller
873 // than 1000x1000px, so this should be big enough.
874 gfx::Rect client_bounds = gfx::Rect(1000, 1000);
875 gfx::Rect window_bounds =
876 window_->non_client_view()->GetWindowBoundsForClientBounds(
878 return window_bounds.InsetsFrom(client_bounds);
881 void NativeAppWindowViews::HideWithApp() {}
882 void NativeAppWindowViews::ShowWithApp() {}
883 void NativeAppWindowViews::UpdateWindowMinMaxSize() {}