native_app_window_views.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 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 "components/native_app_window/native_app_window_views.h"
6
7#include "base/threading/sequenced_worker_pool.h"
8#include "content/public/browser/render_view_host.h"
9#include "content/public/browser/render_widget_host_view.h"
10#include "content/public/browser/web_contents.h"
11#include "extensions/browser/app_window/app_window.h"
12#include "extensions/common/draggable_region.h"
13#include "third_party/skia/include/core/SkRegion.h"
14#include "ui/gfx/path.h"
15#include "ui/views/controls/webview/webview.h"
16#include "ui/views/widget/widget.h"
17#include "ui/views/window/non_client_view.h"
18
19#if defined(USE_AURA)
20#include "ui/aura/window.h"
21#endif
22
23using extensions::AppWindow;
24
25namespace native_app_window {
26
27NativeAppWindowViews::NativeAppWindowViews()
28    : app_window_(NULL),
29      web_view_(NULL),
30      widget_(NULL),
31      frameless_(false),
32      resizable_(false) {
33}
34
35void NativeAppWindowViews::Init(AppWindow* app_window,
36                                const AppWindow::CreateParams& create_params) {
37  app_window_ = app_window;
38  frameless_ = create_params.frame == AppWindow::FRAME_NONE;
39  resizable_ = create_params.resizable;
40  size_constraints_.set_minimum_size(
41      create_params.GetContentMinimumSize(gfx::Insets()));
42  size_constraints_.set_maximum_size(
43      create_params.GetContentMaximumSize(gfx::Insets()));
44  Observe(app_window_->web_contents());
45
46  widget_ = new views::Widget;
47  InitializeWindow(app_window, create_params);
48
49  OnViewWasResized();
50  widget_->AddObserver(this);
51}
52
53NativeAppWindowViews::~NativeAppWindowViews() {
54  web_view_->SetWebContents(NULL);
55}
56
57void NativeAppWindowViews::OnCanHaveAlphaEnabledChanged() {
58  app_window_->OnNativeWindowChanged();
59}
60
61void NativeAppWindowViews::InitializeWindow(
62    AppWindow* app_window,
63    const AppWindow::CreateParams& create_params) {
64  // Stub implementation. See also ChromeNativeAppWindowViews.
65  views::Widget::InitParams init_params(views::Widget::InitParams::TYPE_WINDOW);
66  init_params.delegate = this;
67  init_params.keep_on_top = create_params.always_on_top;
68  widget_->Init(init_params);
69  widget_->CenterWindow(
70      create_params.GetInitialWindowBounds(gfx::Insets()).size());
71}
72
73// ui::BaseWindow implementation.
74
75bool NativeAppWindowViews::IsActive() const {
76  return widget_->IsActive();
77}
78
79bool NativeAppWindowViews::IsMaximized() const {
80  return widget_->IsMaximized();
81}
82
83bool NativeAppWindowViews::IsMinimized() const {
84  return widget_->IsMinimized();
85}
86
87bool NativeAppWindowViews::IsFullscreen() const {
88  return widget_->IsFullscreen();
89}
90
91gfx::NativeWindow NativeAppWindowViews::GetNativeWindow() {
92  return widget_->GetNativeWindow();
93}
94
95gfx::Rect NativeAppWindowViews::GetRestoredBounds() const {
96  return widget_->GetRestoredBounds();
97}
98
99ui::WindowShowState NativeAppWindowViews::GetRestoredState() const {
100  // Stub implementation. See also ChromeNativeAppWindowViews.
101  if (IsMaximized())
102    return ui::SHOW_STATE_MAXIMIZED;
103  if (IsFullscreen())
104    return ui::SHOW_STATE_FULLSCREEN;
105  return ui::SHOW_STATE_NORMAL;
106}
107
108gfx::Rect NativeAppWindowViews::GetBounds() const {
109  return widget_->GetWindowBoundsInScreen();
110}
111
112void NativeAppWindowViews::Show() {
113  if (widget_->IsVisible()) {
114    widget_->Activate();
115    return;
116  }
117  widget_->Show();
118}
119
120void NativeAppWindowViews::ShowInactive() {
121  if (widget_->IsVisible())
122    return;
123
124  widget_->ShowInactive();
125}
126
127void NativeAppWindowViews::Hide() {
128  widget_->Hide();
129}
130
131void NativeAppWindowViews::Close() {
132  widget_->Close();
133}
134
135void NativeAppWindowViews::Activate() {
136  widget_->Activate();
137}
138
139void NativeAppWindowViews::Deactivate() {
140  widget_->Deactivate();
141}
142
143void NativeAppWindowViews::Maximize() {
144  widget_->Maximize();
145}
146
147void NativeAppWindowViews::Minimize() {
148  widget_->Minimize();
149}
150
151void NativeAppWindowViews::Restore() {
152  widget_->Restore();
153}
154
155void NativeAppWindowViews::SetBounds(const gfx::Rect& bounds) {
156  widget_->SetBounds(bounds);
157}
158
159void NativeAppWindowViews::FlashFrame(bool flash) {
160  widget_->FlashFrame(flash);
161}
162
163bool NativeAppWindowViews::IsAlwaysOnTop() const {
164  // Stub implementation. See also ChromeNativeAppWindowViews.
165  return widget_->IsAlwaysOnTop();
166}
167
168void NativeAppWindowViews::SetAlwaysOnTop(bool always_on_top) {
169  widget_->SetAlwaysOnTop(always_on_top);
170}
171
172gfx::NativeView NativeAppWindowViews::GetHostView() const {
173  return widget_->GetNativeView();
174}
175
176gfx::Point NativeAppWindowViews::GetDialogPosition(const gfx::Size& size) {
177  gfx::Size app_window_size = widget_->GetWindowBoundsInScreen().size();
178  return gfx::Point(app_window_size.width() / 2 - size.width() / 2,
179                    app_window_size.height() / 2 - size.height() / 2);
180}
181
182gfx::Size NativeAppWindowViews::GetMaximumDialogSize() {
183  return widget_->GetWindowBoundsInScreen().size();
184}
185
186void NativeAppWindowViews::AddObserver(
187    web_modal::ModalDialogHostObserver* observer) {
188  observer_list_.AddObserver(observer);
189}
190void NativeAppWindowViews::RemoveObserver(
191    web_modal::ModalDialogHostObserver* observer) {
192  observer_list_.RemoveObserver(observer);
193}
194
195void NativeAppWindowViews::OnViewWasResized() {
196  FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver,
197                    observer_list_,
198                    OnPositionRequiresUpdate());
199}
200
201// WidgetDelegate implementation.
202
203void NativeAppWindowViews::OnWidgetMove() {
204  app_window_->OnNativeWindowChanged();
205}
206
207views::View* NativeAppWindowViews::GetInitiallyFocusedView() {
208  return web_view_;
209}
210
211bool NativeAppWindowViews::CanResize() const {
212  return resizable_ && !size_constraints_.HasFixedSize() &&
213         !WidgetHasHitTestMask();
214}
215
216bool NativeAppWindowViews::CanMaximize() const {
217  return resizable_ && !size_constraints_.HasMaximumSize() &&
218         !app_window_->window_type_is_panel() && !WidgetHasHitTestMask();
219}
220
221bool NativeAppWindowViews::CanMinimize() const {
222  return true;
223}
224
225base::string16 NativeAppWindowViews::GetWindowTitle() const {
226  return app_window_->GetTitle();
227}
228
229bool NativeAppWindowViews::ShouldShowWindowTitle() const {
230  return app_window_->window_type() == AppWindow::WINDOW_TYPE_V1_PANEL;
231}
232
233bool NativeAppWindowViews::ShouldShowWindowIcon() const {
234  return app_window_->window_type() == AppWindow::WINDOW_TYPE_V1_PANEL;
235}
236
237void NativeAppWindowViews::SaveWindowPlacement(const gfx::Rect& bounds,
238                                               ui::WindowShowState show_state) {
239  views::WidgetDelegate::SaveWindowPlacement(bounds, show_state);
240  app_window_->OnNativeWindowChanged();
241}
242
243void NativeAppWindowViews::DeleteDelegate() {
244  widget_->RemoveObserver(this);
245  app_window_->OnNativeClose();
246}
247
248views::Widget* NativeAppWindowViews::GetWidget() {
249  return widget_;
250}
251
252const views::Widget* NativeAppWindowViews::GetWidget() const {
253  return widget_;
254}
255
256views::View* NativeAppWindowViews::GetContentsView() {
257  return this;
258}
259
260bool NativeAppWindowViews::ShouldDescendIntoChildForEventHandling(
261    gfx::NativeView child,
262    const gfx::Point& location) {
263#if defined(USE_AURA)
264  if (child->Contains(web_view_->web_contents()->GetNativeView())) {
265    // App window should claim mouse events that fall within the draggable
266    // region.
267    return !draggable_region_.get() ||
268           !draggable_region_->contains(location.x(), location.y());
269  }
270#endif
271
272  return true;
273}
274
275// WidgetObserver implementation.
276
277void NativeAppWindowViews::OnWidgetVisibilityChanged(views::Widget* widget,
278                                                     bool visible) {
279  app_window_->OnNativeWindowChanged();
280}
281
282void NativeAppWindowViews::OnWidgetActivationChanged(views::Widget* widget,
283                                                     bool active) {
284  app_window_->OnNativeWindowChanged();
285  if (active)
286    app_window_->OnNativeWindowActivated();
287}
288
289// WebContentsObserver implementation.
290
291void NativeAppWindowViews::RenderViewCreated(
292    content::RenderViewHost* render_view_host) {
293  if (app_window_->requested_alpha_enabled() && CanHaveAlphaEnabled()) {
294    content::RenderWidgetHostView* view = render_view_host->GetView();
295    DCHECK(view);
296    view->SetBackgroundOpaque(false);
297  }
298}
299
300void NativeAppWindowViews::RenderViewHostChanged(
301    content::RenderViewHost* old_host,
302    content::RenderViewHost* new_host) {
303  OnViewWasResized();
304}
305
306// views::View implementation.
307
308void NativeAppWindowViews::Layout() {
309  DCHECK(web_view_);
310  web_view_->SetBounds(0, 0, width(), height());
311  OnViewWasResized();
312}
313
314void NativeAppWindowViews::ViewHierarchyChanged(
315    const ViewHierarchyChangedDetails& details) {
316  if (details.is_add && details.child == this) {
317    web_view_ = new views::WebView(NULL);
318    AddChildView(web_view_);
319    web_view_->SetWebContents(app_window_->web_contents());
320  }
321}
322
323gfx::Size NativeAppWindowViews::GetMinimumSize() const {
324  return size_constraints_.GetMinimumSize();
325}
326
327gfx::Size NativeAppWindowViews::GetMaximumSize() const {
328  return size_constraints_.GetMaximumSize();
329}
330
331void NativeAppWindowViews::OnFocus() {
332  web_view_->RequestFocus();
333}
334
335// NativeAppWindow implementation.
336
337void NativeAppWindowViews::SetFullscreen(int fullscreen_types) {
338  // Stub implementation. See also ChromeNativeAppWindowViews.
339  widget_->SetFullscreen(fullscreen_types != AppWindow::FULLSCREEN_TYPE_NONE);
340}
341
342bool NativeAppWindowViews::IsFullscreenOrPending() const {
343  // Stub implementation. See also ChromeNativeAppWindowViews.
344  return widget_->IsFullscreen();
345}
346
347void NativeAppWindowViews::UpdateWindowIcon() {
348  widget_->UpdateWindowIcon();
349}
350
351void NativeAppWindowViews::UpdateWindowTitle() {
352  widget_->UpdateWindowTitle();
353}
354
355void NativeAppWindowViews::UpdateBadgeIcon() {
356  // Stub implementation. See also ChromeNativeAppWindowViews.
357}
358
359void NativeAppWindowViews::UpdateDraggableRegions(
360    const std::vector<extensions::DraggableRegion>& regions) {
361  // Draggable region is not supported for non-frameless window.
362  if (!frameless_)
363    return;
364
365  draggable_region_.reset(AppWindow::RawDraggableRegionsToSkRegion(regions));
366  OnViewWasResized();
367}
368
369SkRegion* NativeAppWindowViews::GetDraggableRegion() {
370  return draggable_region_.get();
371}
372
373void NativeAppWindowViews::UpdateShape(scoped_ptr<SkRegion> region) {
374  // Stub implementation. See also ChromeNativeAppWindowViews.
375}
376
377void NativeAppWindowViews::HandleKeyboardEvent(
378    const content::NativeWebKeyboardEvent& event) {
379  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
380                                                        GetFocusManager());
381}
382
383bool NativeAppWindowViews::IsFrameless() const {
384  return frameless_;
385}
386
387bool NativeAppWindowViews::HasFrameColor() const {
388  return false;
389}
390
391SkColor NativeAppWindowViews::ActiveFrameColor() const {
392  return SK_ColorBLACK;
393}
394
395SkColor NativeAppWindowViews::InactiveFrameColor() const {
396  return SK_ColorBLACK;
397}
398
399gfx::Insets NativeAppWindowViews::GetFrameInsets() const {
400  if (frameless_)
401    return gfx::Insets();
402
403  // The pretend client_bounds passed in need to be large enough to ensure that
404  // GetWindowBoundsForClientBounds() doesn't decide that it needs more than
405  // the specified amount of space to fit the window controls in, and return a
406  // number larger than the real frame insets. Most window controls are smaller
407  // than 1000x1000px, so this should be big enough.
408  gfx::Rect client_bounds = gfx::Rect(1000, 1000);
409  gfx::Rect window_bounds =
410      widget_->non_client_view()->GetWindowBoundsForClientBounds(client_bounds);
411  return window_bounds.InsetsFrom(client_bounds);
412}
413
414void NativeAppWindowViews::HideWithApp() {
415}
416
417void NativeAppWindowViews::ShowWithApp() {
418}
419
420void NativeAppWindowViews::UpdateShelfMenu() {
421}
422
423gfx::Size NativeAppWindowViews::GetContentMinimumSize() const {
424  return size_constraints_.GetMinimumSize();
425}
426
427gfx::Size NativeAppWindowViews::GetContentMaximumSize() const {
428  return size_constraints_.GetMaximumSize();
429}
430
431void NativeAppWindowViews::SetContentSizeConstraints(
432    const gfx::Size& min_size,
433    const gfx::Size& max_size) {
434  size_constraints_.set_minimum_size(min_size);
435  size_constraints_.set_maximum_size(max_size);
436  widget_->OnSizeConstraintsChanged();
437}
438
439bool NativeAppWindowViews::CanHaveAlphaEnabled() const {
440  return widget_->IsTranslucentWindowOpacitySupported();
441}
442
443void NativeAppWindowViews::SetVisibleOnAllWorkspaces(bool always_visible) {
444  widget_->SetVisibleOnAllWorkspaces(always_visible);
445}
446
447}  // namespace native_app_window
448