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