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 #ifndef EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_H_ 6 #define EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_H_ 7 8 #include <string> 9 #include <vector> 10 11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/weak_ptr.h" 13 #include "components/sessions/session_id.h" 14 #include "components/web_modal/popup_manager.h" 15 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" 16 #include "content/public/browser/notification_observer.h" 17 #include "content/public/browser/notification_registrar.h" 18 #include "content/public/browser/web_contents_delegate.h" 19 #include "content/public/browser/web_contents_observer.h" 20 #include "extensions/browser/extension_icon_image.h" 21 #include "ui/base/ui_base_types.h" // WindowShowState 22 #include "ui/gfx/image/image.h" 23 #include "ui/gfx/rect.h" 24 25 class GURL; 26 class SkRegion; 27 28 namespace base { 29 class DictionaryValue; 30 } 31 32 namespace content { 33 class BrowserContext; 34 class WebContents; 35 } 36 37 namespace ui { 38 class BaseWindow; 39 } 40 41 namespace extensions { 42 43 class AppDelegate; 44 class AppWebContentsHelper; 45 class Extension; 46 class NativeAppWindow; 47 class PlatformAppBrowserTest; 48 class WindowController; 49 50 struct DraggableRegion; 51 52 // Manages the web contents for app windows. The implementation for this 53 // class should create and maintain the WebContents for the window, and handle 54 // any message passing between the web contents and the extension system or 55 // native window. 56 class AppWindowContents { 57 public: 58 AppWindowContents() {} 59 virtual ~AppWindowContents() {} 60 61 // Called to initialize the WebContents, before the app window is created. 62 virtual void Initialize(content::BrowserContext* context, 63 const GURL& url) = 0; 64 65 // Called to load the contents, after the app window is created. 66 virtual void LoadContents(int32 creator_process_id) = 0; 67 68 // Called when the native window changes. 69 virtual void NativeWindowChanged(NativeAppWindow* native_app_window) = 0; 70 71 // Called when the native window closes. 72 virtual void NativeWindowClosed() = 0; 73 74 // Called in tests when the window is shown 75 virtual void DispatchWindowShownForTests() const = 0; 76 77 virtual content::WebContents* GetWebContents() const = 0; 78 79 private: 80 DISALLOW_COPY_AND_ASSIGN(AppWindowContents); 81 }; 82 83 // AppWindow is the type of window used by platform apps. App windows 84 // have a WebContents but none of the chrome of normal browser windows. 85 class AppWindow : public content::NotificationObserver, 86 public content::WebContentsDelegate, 87 public content::WebContentsObserver, 88 public web_modal::WebContentsModalDialogManagerDelegate, 89 public IconImage::Observer { 90 public: 91 enum WindowType { 92 WINDOW_TYPE_DEFAULT = 1 << 0, // Default app window. 93 WINDOW_TYPE_PANEL = 1 << 1, // OS controlled panel window (Ash only). 94 WINDOW_TYPE_V1_PANEL = 1 << 2, // For apps v1 support in Ash; deprecate 95 // with v1 apps. 96 }; 97 98 enum Frame { 99 FRAME_CHROME, // Chrome-style window frame. 100 FRAME_NONE, // Frameless window. 101 }; 102 103 enum FullscreenType { 104 // Not fullscreen. 105 FULLSCREEN_TYPE_NONE = 0, 106 107 // Fullscreen entered by the app.window api. 108 FULLSCREEN_TYPE_WINDOW_API = 1 << 0, 109 110 // Fullscreen entered by HTML requestFullscreen(). 111 FULLSCREEN_TYPE_HTML_API = 1 << 1, 112 113 // Fullscreen entered by the OS. ChromeOS uses this type of fullscreen to 114 // enter immersive fullscreen when the user hits the <F4> key. 115 FULLSCREEN_TYPE_OS = 1 << 2, 116 117 // Fullscreen mode that could not be exited by the user. ChromeOS uses 118 // this type of fullscreen to run an app in kiosk mode. 119 FULLSCREEN_TYPE_FORCED = 1 << 3, 120 }; 121 122 struct BoundsSpecification { 123 // INT_MIN represents an unspecified position component. 124 static const int kUnspecifiedPosition; 125 126 BoundsSpecification(); 127 ~BoundsSpecification(); 128 129 // INT_MIN designates 'unspecified' for the position components, and 0 130 // designates 'unspecified' for the size components. When unspecified, 131 // they should be replaced with a default value. 132 gfx::Rect bounds; 133 134 gfx::Size minimum_size; 135 gfx::Size maximum_size; 136 137 // Reset the bounds fields to their 'unspecified' values. The minimum and 138 // maximum size constraints remain unchanged. 139 void ResetBounds(); 140 }; 141 142 struct CreateParams { 143 CreateParams(); 144 ~CreateParams(); 145 146 WindowType window_type; 147 Frame frame; 148 149 bool has_frame_color; 150 SkColor active_frame_color; 151 SkColor inactive_frame_color; 152 bool alpha_enabled; 153 154 // The initial content/inner bounds specification (excluding any window 155 // decorations). 156 BoundsSpecification content_spec; 157 158 // The initial window/outer bounds specification (including window 159 // decorations). 160 BoundsSpecification window_spec; 161 162 std::string window_key; 163 164 // The process ID of the process that requested the create. 165 int32 creator_process_id; 166 167 // Initial state of the window. 168 ui::WindowShowState state; 169 170 // If true, don't show the window after creation. 171 bool hidden; 172 173 // If true, the window will be resizable by the user. Defaults to true. 174 bool resizable; 175 176 // If true, the window will be focused on creation. Defaults to true. 177 bool focused; 178 179 // If true, the window will stay on top of other windows that are not 180 // configured to be always on top. Defaults to false. 181 bool always_on_top; 182 183 // If true, the window will be visible on all workspaces. Defaults to false. 184 bool visible_on_all_workspaces; 185 186 // The API enables developers to specify content or window bounds. This 187 // function combines them into a single, constrained window size. 188 gfx::Rect GetInitialWindowBounds(const gfx::Insets& frame_insets) const; 189 190 // The API enables developers to specify content or window size constraints. 191 // These functions combine them so that we can work with one set of 192 // constraints. 193 gfx::Size GetContentMinimumSize(const gfx::Insets& frame_insets) const; 194 gfx::Size GetContentMaximumSize(const gfx::Insets& frame_insets) const; 195 gfx::Size GetWindowMinimumSize(const gfx::Insets& frame_insets) const; 196 gfx::Size GetWindowMaximumSize(const gfx::Insets& frame_insets) const; 197 }; 198 199 // Convert draggable regions in raw format to SkRegion format. Caller is 200 // responsible for deleting the returned SkRegion instance. 201 static SkRegion* RawDraggableRegionsToSkRegion( 202 const std::vector<DraggableRegion>& regions); 203 204 // The constructor and Init methods are public for constructing a AppWindow 205 // with a non-standard render interface (e.g. v1 apps using Ash Panels). 206 // Normally AppWindow::Create should be used. 207 // Takes ownership of |app_delegate| and |delegate|. 208 AppWindow(content::BrowserContext* context, 209 AppDelegate* app_delegate, 210 const Extension* extension); 211 212 // Initializes the render interface, web contents, and native window. 213 // |app_window_contents| will become owned by AppWindow. 214 void Init(const GURL& url, 215 AppWindowContents* app_window_contents, 216 const CreateParams& params); 217 218 const std::string& window_key() const { return window_key_; } 219 const SessionID& session_id() const { return session_id_; } 220 const std::string& extension_id() const { return extension_id_; } 221 content::WebContents* web_contents() const; 222 WindowType window_type() const { return window_type_; } 223 bool window_type_is_panel() const { 224 return (window_type_ == WINDOW_TYPE_PANEL || 225 window_type_ == WINDOW_TYPE_V1_PANEL); 226 } 227 content::BrowserContext* browser_context() const { return browser_context_; } 228 const gfx::Image& app_icon() const { return app_icon_; } 229 const GURL& app_icon_url() const { return app_icon_url_; } 230 const gfx::Image& badge_icon() const { return badge_icon_; } 231 const GURL& badge_icon_url() const { return badge_icon_url_; } 232 bool is_hidden() const { return is_hidden_; } 233 234 const Extension* GetExtension() const; 235 NativeAppWindow* GetBaseWindow(); 236 gfx::NativeWindow GetNativeWindow(); 237 238 // Returns the bounds that should be reported to the renderer. 239 gfx::Rect GetClientBounds() const; 240 241 // NativeAppWindows should call this to determine what the window's title 242 // is on startup and from within UpdateWindowTitle(). 243 base::string16 GetTitle() const; 244 245 // Call to notify ShellRegistry and delete the window. Subclasses should 246 // invoke this method instead of using "delete this". 247 void OnNativeClose(); 248 249 // Should be called by native implementations when the window size, position, 250 // or minimized/maximized state has changed. 251 void OnNativeWindowChanged(); 252 253 // Should be called by native implementations when the window is activated. 254 void OnNativeWindowActivated(); 255 256 // Specifies a url for the launcher icon. 257 void SetAppIconUrl(const GURL& icon_url); 258 259 // Specifies a url for the window badge. 260 void SetBadgeIconUrl(const GURL& icon_url); 261 262 // Clear the current badge. 263 void ClearBadge(); 264 265 // Set the window shape. Passing a NULL |region| sets the default shape. 266 void UpdateShape(scoped_ptr<SkRegion> region); 267 268 // Called from the render interface to modify the draggable regions. 269 void UpdateDraggableRegions(const std::vector<DraggableRegion>& regions); 270 271 // Updates the app image to |image|. Called internally from the image loader 272 // callback. Also called externally for v1 apps using Ash Panels. 273 void UpdateAppIcon(const gfx::Image& image); 274 275 // Enable or disable fullscreen mode. |type| specifies which type of 276 // fullscreen mode to change (note that disabling one type of fullscreen may 277 // not exit fullscreen mode because a window may have a different type of 278 // fullscreen enabled). If |type| is not FORCED, checks that the extension has 279 // the required permission. 280 void SetFullscreen(FullscreenType type, bool enable); 281 282 // Returns true if the app window is in a fullscreen state. 283 bool IsFullscreen() const; 284 285 // Returns true if the app window is in a forced fullscreen state (one that 286 // cannot be exited by the user). 287 bool IsForcedFullscreen() const; 288 289 // Returns true if the app window is in a fullscreen state entered from an 290 // HTML API request. 291 bool IsHtmlApiFullscreen() const; 292 293 // Transitions window into fullscreen, maximized, minimized or restores based 294 // on chrome.app.window API. 295 void Fullscreen(); 296 void Maximize(); 297 void Minimize(); 298 void Restore(); 299 300 // Transitions to OS fullscreen. See FULLSCREEN_TYPE_OS for more details. 301 void OSFullscreen(); 302 303 // Transitions to forced fullscreen. See FULLSCREEN_TYPE_FORCED for more 304 // details. 305 void ForcedFullscreen(); 306 307 // Set the minimum and maximum size of the content bounds. 308 void SetContentSizeConstraints(const gfx::Size& min_size, 309 const gfx::Size& max_size); 310 311 enum ShowType { SHOW_ACTIVE, SHOW_INACTIVE }; 312 313 // Shows the window if its contents have been painted; otherwise flags the 314 // window to be shown as soon as its contents are painted for the first time. 315 void Show(ShowType show_type); 316 317 // Hides the window. If the window was previously flagged to be shown on 318 // first paint, it will be unflagged. 319 void Hide(); 320 321 AppWindowContents* app_window_contents_for_test() { 322 return app_window_contents_.get(); 323 } 324 325 int fullscreen_types_for_test() { 326 return fullscreen_types_; 327 } 328 329 // Set whether the window should stay above other windows which are not 330 // configured to be always-on-top. 331 void SetAlwaysOnTop(bool always_on_top); 332 333 // Whether the always-on-top property has been set by the chrome.app.window 334 // API. Note that the actual value of this property in the native app window 335 // may be false if the bit is silently switched off for security reasons. 336 bool IsAlwaysOnTop() const; 337 338 // Retrieve the current state of the app window as a dictionary, to pass to 339 // the renderer. 340 void GetSerializedState(base::DictionaryValue* properties) const; 341 342 // Called by the window API when events can be sent to the window for this 343 // app. 344 void WindowEventsReady(); 345 346 // Whether the app window wants to be alpha enabled. 347 bool requested_alpha_enabled() const { return requested_alpha_enabled_; } 348 349 void SetAppWindowContentsForTesting(scoped_ptr<AppWindowContents> contents) { 350 app_window_contents_ = contents.Pass(); 351 } 352 353 protected: 354 virtual ~AppWindow(); 355 356 private: 357 // PlatformAppBrowserTest needs access to web_contents() 358 friend class PlatformAppBrowserTest; 359 360 // content::WebContentsDelegate implementation. 361 virtual void CloseContents(content::WebContents* contents) OVERRIDE; 362 virtual bool ShouldSuppressDialogs() OVERRIDE; 363 virtual content::ColorChooser* OpenColorChooser( 364 content::WebContents* web_contents, 365 SkColor color, 366 const std::vector<content::ColorSuggestion>& suggestions) OVERRIDE; 367 virtual void RunFileChooser(content::WebContents* tab, 368 const content::FileChooserParams& params) 369 OVERRIDE; 370 virtual bool IsPopupOrPanel(const content::WebContents* source) 371 const OVERRIDE; 372 virtual void MoveContents(content::WebContents* source, 373 const gfx::Rect& pos) OVERRIDE; 374 virtual void NavigationStateChanged( 375 const content::WebContents* source, 376 content::InvalidateTypes changed_flags) OVERRIDE; 377 virtual void ToggleFullscreenModeForTab(content::WebContents* source, 378 bool enter_fullscreen) OVERRIDE; 379 virtual bool IsFullscreenForTabOrPending(const content::WebContents* source) 380 const OVERRIDE; 381 virtual void RequestMediaAccessPermission( 382 content::WebContents* web_contents, 383 const content::MediaStreamRequest& request, 384 const content::MediaResponseCallback& callback) OVERRIDE; 385 virtual bool CheckMediaAccessPermission( 386 content::WebContents* web_contents, 387 const GURL& security_origin, 388 content::MediaStreamType type) OVERRIDE; 389 virtual content::WebContents* OpenURLFromTab( 390 content::WebContents* source, 391 const content::OpenURLParams& params) OVERRIDE; 392 virtual void AddNewContents(content::WebContents* source, 393 content::WebContents* new_contents, 394 WindowOpenDisposition disposition, 395 const gfx::Rect& initial_pos, 396 bool user_gesture, 397 bool* was_blocked) OVERRIDE; 398 virtual bool PreHandleKeyboardEvent( 399 content::WebContents* source, 400 const content::NativeWebKeyboardEvent& event, 401 bool* is_keyboard_shortcut) OVERRIDE; 402 virtual void HandleKeyboardEvent(content::WebContents* source, 403 const content::NativeWebKeyboardEvent& event) 404 OVERRIDE; 405 virtual void RequestToLockMouse(content::WebContents* web_contents, 406 bool user_gesture, 407 bool last_unlocked_by_target) OVERRIDE; 408 virtual bool PreHandleGestureEvent(content::WebContents* source, 409 const blink::WebGestureEvent& event) 410 OVERRIDE; 411 412 // content::WebContentsObserver implementation. 413 virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE; 414 415 // content::NotificationObserver implementation. 416 virtual void Observe(int type, 417 const content::NotificationSource& source, 418 const content::NotificationDetails& details) OVERRIDE; 419 420 // web_modal::WebContentsModalDialogManagerDelegate implementation. 421 virtual void SetWebContentsBlocked(content::WebContents* web_contents, 422 bool blocked) OVERRIDE; 423 virtual bool IsWebContentsVisible(content::WebContents* web_contents) 424 OVERRIDE; 425 426 // Saves the window geometry/position/screen bounds. 427 void SaveWindowPosition(); 428 429 // Helper method to adjust the cached bounds so that we can make sure it can 430 // be visible on the screen. See http://crbug.com/145752. 431 void AdjustBoundsToBeVisibleOnScreen(const gfx::Rect& cached_bounds, 432 const gfx::Rect& cached_screen_bounds, 433 const gfx::Rect& current_screen_bounds, 434 const gfx::Size& minimum_size, 435 gfx::Rect* bounds) const; 436 437 // Loads the appropriate default or cached window bounds. Returns a new 438 // CreateParams that should be used to create the window. 439 CreateParams LoadDefaults(CreateParams params) const; 440 441 // Load the app's image, firing a load state change when loaded. 442 void UpdateExtensionAppIcon(); 443 444 // Set the fullscreen state in the native app window. 445 void SetNativeWindowFullscreen(); 446 447 // Returns true if there is any overlap between the window and the taskbar 448 // (Windows only). 449 bool IntersectsWithTaskbar() const; 450 451 // Update the always-on-top bit in the native app window. 452 void UpdateNativeAlwaysOnTop(); 453 454 // Sends the onWindowShown event to the app if the window has been shown. Only 455 // has an effect in tests. 456 void SendOnWindowShownIfShown(); 457 458 // web_modal::WebContentsModalDialogManagerDelegate implementation. 459 virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() 460 OVERRIDE; 461 462 // Updates the badge to |image|. Called internally from the image loader 463 // callback. 464 void UpdateBadgeIcon(const gfx::Image& image); 465 466 // Callback from web_contents()->DownloadFavicon. 467 void DidDownloadFavicon(int id, 468 int http_status_code, 469 const GURL& image_url, 470 const std::vector<SkBitmap>& bitmaps, 471 const std::vector<gfx::Size>& original_bitmap_sizes); 472 473 // IconImage::Observer implementation. 474 virtual void OnExtensionIconImageChanged(IconImage* image) OVERRIDE; 475 476 // The browser context with which this window is associated. AppWindow does 477 // not own this object. 478 content::BrowserContext* browser_context_; 479 480 const std::string extension_id_; 481 482 // Identifier that is used when saving and restoring geometry for this 483 // window. 484 std::string window_key_; 485 486 const SessionID session_id_; 487 WindowType window_type_; 488 content::NotificationRegistrar registrar_; 489 490 // Icon shown in the task bar. 491 gfx::Image app_icon_; 492 493 // Icon URL to be used for setting the app icon. If not empty, app_icon_ will 494 // be fetched and set using this URL. 495 GURL app_icon_url_; 496 497 // An object to load the app's icon as an extension resource. 498 scoped_ptr<IconImage> app_icon_image_; 499 500 // Badge for icon shown in the task bar. 501 gfx::Image badge_icon_; 502 503 // URL to be used for setting the badge on the app icon. 504 GURL badge_icon_url_; 505 506 // An object to load the badge as an extension resource. 507 scoped_ptr<IconImage> badge_icon_image_; 508 509 scoped_ptr<NativeAppWindow> native_app_window_; 510 scoped_ptr<AppWindowContents> app_window_contents_; 511 scoped_ptr<AppDelegate> app_delegate_; 512 scoped_ptr<AppWebContentsHelper> helper_; 513 514 // Manages popup windows (bubbles, tab-modals) visible overlapping the 515 // app window. 516 scoped_ptr<web_modal::PopupManager> popup_manager_; 517 518 base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_; 519 520 // Bit field of FullscreenType. 521 int fullscreen_types_; 522 523 // Show has been called, so the window should be shown once the first visually 524 // non-empty paint occurs. 525 bool show_on_first_paint_; 526 527 // The first visually non-empty paint has completed. 528 bool first_paint_complete_; 529 530 // Whether the window has been shown or not. 531 bool has_been_shown_; 532 533 // Whether events can be sent to the window. 534 bool can_send_events_; 535 536 // Whether the window is hidden or not. Hidden in this context means actively 537 // by the chrome.app.window API, not in an operating system context. For 538 // example windows which are minimized are not hidden, and windows which are 539 // part of a hidden app on OS X are not hidden. Windows which were created 540 // with the |hidden| flag set to true, or which have been programmatically 541 // hidden, are considered hidden. 542 bool is_hidden_; 543 544 // Whether the delayed Show() call was for an active or inactive window. 545 ShowType delayed_show_type_; 546 547 // Cache the desired value of the always-on-top property. When windows enter 548 // fullscreen or overlap the Windows taskbar, this property will be 549 // automatically and silently switched off for security reasons. It is 550 // reinstated when the window exits fullscreen and moves away from the 551 // taskbar. 552 bool cached_always_on_top_; 553 554 // Whether |alpha_enabled| was set in the CreateParams. 555 bool requested_alpha_enabled_; 556 557 DISALLOW_COPY_AND_ASSIGN(AppWindow); 558 }; 559 560 } // namespace extensions 561 562 #endif // EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_H_ 563