diff options
author | jamiewalch@chromium.org <jamiewalch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 21:07:27 +0000 |
---|---|---|
committer | jamiewalch@chromium.org <jamiewalch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-30 21:07:27 +0000 |
commit | 3febebe90d62a419d49ccc80eaf7228ac632c2fa (patch) | |
tree | 8120e36bd5e8743791f786afedbe5195ce4b036b /remoting/webapp | |
parent | 2547c91ed6fd014a7eac9a5a764f87f54b9bc714 (diff) | |
download | chromium_src-3febebe90d62a419d49ccc80eaf7228ac632c2fa.zip chromium_src-3febebe90d62a419d49ccc80eaf7228ac632c2fa.tar.gz chromium_src-3febebe90d62a419d49ccc80eaf7228ac632c2fa.tar.bz2 |
Use chrome.app.window full-screen API for apps v2.
This allows us to hook onMaximized to enter full-screen which is a cleaner UX.
In the future, we will also have on-screen auto-hide close/minimize/restore
controls in full-screen mode, which will eliminate the need for the tool-bar
menu entry completely.
See https://developer.chrome.com/apps/app_window#type-AppWindow for details
of the API, and http://code.google.com/p/chromium/issues/detail?id=364942 for a discussion of why
this behaviour is not going to be supported by requestFullscreen.
BUG=134213,252927
NOTRY=true
Review URL: https://codereview.chromium.org/252783003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267329 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/webapp')
-rw-r--r-- | remoting/webapp/client_session.js | 47 | ||||
-rw-r--r-- | remoting/webapp/fullscreen.js | 65 | ||||
-rw-r--r-- | remoting/webapp/fullscreen_v1.js | 86 | ||||
-rw-r--r-- | remoting/webapp/fullscreen_v2.js | 121 | ||||
-rw-r--r-- | remoting/webapp/js_proto/chrome_proto.js | 10 | ||||
-rw-r--r-- | remoting/webapp/remoting.js | 2 |
6 files changed, 309 insertions, 22 deletions
diff --git a/remoting/webapp/client_session.js b/remoting/webapp/client_session.js index 22f67b9..92ded18 100644 --- a/remoting/webapp/client_session.js +++ b/remoting/webapp/client_session.js @@ -113,7 +113,10 @@ remoting.ClientSession = function(accessCode, fetchPin, fetchThirdPartyToken, /** @private */ this.callSetScreenMode_ = this.onSetScreenMode_.bind(this); /** @private */ - this.callToggleFullScreen_ = this.toggleFullScreen_.bind(this); + this.callToggleFullScreen_ = remoting.fullscreen.toggle.bind( + remoting.fullscreen); + /** @private */ + this.callOnFullScreenChanged_ = this.onFullScreenChanged_.bind(this); /** @private */ this.screenOptionsMenu_ = new remoting.MenuButton( @@ -151,8 +154,6 @@ remoting.ClientSession = function(accessCode, fetchPin, fetchThirdPartyToken, 'click', this.callSetScreenMode_, false); this.fullScreenButton_.addEventListener( 'click', this.callToggleFullScreen_, false); - document.addEventListener( - 'webkitfullscreenchange', this.onFullScreenChanged_.bind(this), false); }; /** @@ -544,8 +545,14 @@ remoting.ClientSession.prototype.removePlugin = function() { this.fullScreenButton_.removeEventListener( 'click', this.callToggleFullScreen_, false); - // In case the user had selected full-screen mode, cancel it now. - document.webkitCancelFullScreen(); + // Leave full-screen mode, and stop listening for related events. + var listener = this.callOnFullScreenChanged_; + remoting.fullscreen.syncWithMaximize(false); + remoting.fullscreen.activate( + false, + function() { + remoting.fullscreen.removeListener(listener); + }); // Remove mediasource-rendering class from video-contained - this will also // hide the <video> element. @@ -922,6 +929,9 @@ remoting.ClientSession.prototype.onConnectionStatusUpdate_ = window.innerHeight, window.devicePixelRatio); } + // Start listening for full-screen related events. + remoting.fullscreen.addListener(this.callOnFullScreenChanged_); + remoting.fullscreen.syncWithMaximize(true); } else if (status == remoting.ClientSession.State.FAILED) { switch (error) { case remoting.ClientSession.ConnectionError.HOST_IS_OFFLINE: @@ -1138,7 +1148,7 @@ remoting.ClientSession.prototype.updateDimensions = function() { // If we're running full-screen then try to handle common side-by-side // multi-monitor combinations more intelligently. - if (document.webkitIsFullScreen) { + if (remoting.fullscreen.isActive()) { // If the host has two monitors each the same size as the client then // scale-to-fit will have the desktop occupy only 50% of the client area, // in which case it would be preferable to down-scale less and let the @@ -1225,30 +1235,23 @@ remoting.ClientSession.prototype.requestPairing = function(clientName, onDone) { }; /** - * Toggles between full-screen and windowed mode. - * @return {void} Nothing. + * Called when the full-screen status has changed, either via the + * remoting.Fullscreen class, or via a system event such as the Escape key + * + * @param {boolean} fullscreen True if the app is entering full-screen mode; + * false if it is leaving it. * @private */ -remoting.ClientSession.prototype.toggleFullScreen_ = function() { - if (document.webkitIsFullScreen) { - document.webkitCancelFullScreen(); - } else { - document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } -}; - -remoting.ClientSession.prototype.onFullScreenChanged_ = function () { +remoting.ClientSession.prototype.onFullScreenChanged_ = function (fullscreen) { var htmlNode = /** @type {HTMLElement} */ (document.documentElement); - var isFullScreen = document.webkitIsFullScreen; - this.enableBumpScroll_(isFullScreen); - if (isFullScreen) { + this.enableBumpScroll_(fullscreen); + if (fullscreen) { htmlNode.classList.add('full-screen'); } else { htmlNode.classList.remove('full-screen'); } }; - /** * Updates the options menu to reflect the current scale-to-fit and full-screen * settings. @@ -1259,7 +1262,7 @@ remoting.ClientSession.prototype.onShowOptionsMenu_ = function() { remoting.MenuButton.select(this.resizeToClientButton_, this.resizeToClient_); remoting.MenuButton.select(this.shrinkToFitButton_, this.shrinkToFit_); remoting.MenuButton.select(this.fullScreenButton_, - document.webkitIsFullScreen); + remoting.fullscreen.isActive()); }; /** diff --git a/remoting/webapp/fullscreen.js b/remoting/webapp/fullscreen.js new file mode 100644 index 0000000..d510828 --- /dev/null +++ b/remoting/webapp/fullscreen.js @@ -0,0 +1,65 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Controller interface for full-screen mode. + */ + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** @interface */ +remoting.Fullscreen = function() { }; + +/** + * Enter or leave full-screen mode. + * + * @param {boolean} fullscreen True to enter full-screen mode; false to leave. + * @param {function():void=} opt_onDone Optional completion callback. + */ +remoting.Fullscreen.prototype.activate = function(fullscreen, opt_onDone) { }; + +/** + * @return {boolean} True if full-screen mode is active. + */ +remoting.Fullscreen.prototype.isActive = function() { }; + +/** + * Toggle full-screen mode. + */ +remoting.Fullscreen.prototype.toggle = function() { }; + +/** + * Add a listener for the full-screen-changed event. + * + * @param {function(boolean):void} callback + */ +remoting.Fullscreen.prototype.addListener = function(callback) { }; + +/** + * Remove a listener for the full-screen-changed event. + * + * @param {function(boolean):void} callback + */ +remoting.Fullscreen.prototype.removeListener = function(callback) { }; + +/** + * Enable or disable automatic synchronization of full-screen and maximized + * states. This allows the application to enter full-screen mode whenever its + * window is maximized, regardless of how the user initiates this (clicking + * the maximize control, double-clicking the title bar or using the tray menu, + * for example). If the window is already maximized when this synchronization + * is enabled, it is full-screened. + * + * This method is a no-op for apps v1. + * + * @param {boolean} sync True to enable synchronization; false to disable. + */ +remoting.Fullscreen.prototype.syncWithMaximize = function(sync) { }; + +/** @type {remoting.Fullscreen} */ +remoting.fullscreen = null; diff --git a/remoting/webapp/fullscreen_v1.js b/remoting/webapp/fullscreen_v1.js new file mode 100644 index 0000000..052732d --- /dev/null +++ b/remoting/webapp/fullscreen_v1.js @@ -0,0 +1,86 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Full-screen implementation for apps v1, using webkitRequestFullscreen. + */ + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** + * @constructor + * @implements {remoting.Fullscreen} + */ +remoting.FullscreenAppsV1 = function() { + /** + * @type {string} Internal 'full-screen changed' event name + * @private + */ + this.kEventName_ = '_fullscreenchanged'; + + /** + * @type {base.EventSource} + * @private + */ + this.eventSource_ = new base.EventSource(); + this.eventSource_.defineEvents([this.kEventName_]); + + document.addEventListener( + 'webkitfullscreenchange', + this.onFullscreenChanged_.bind(this), + false); +}; + +remoting.FullscreenAppsV1.prototype.activate = function( + fullscreen, opt_onDone) { + if (opt_onDone) { + if (this.isActive() == fullscreen) { + opt_onDone(); + } else { + /** @type {remoting.Fullscreen} */ + var that = this; + var callbackAndRemoveListener = function() { + that.removeListener(callbackAndRemoveListener); + opt_onDone(); + }; + this.addListener(callbackAndRemoveListener); + } + } + + if (fullscreen) { + document.body.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + document.webkitCancelFullScreen(); + } +}; + +remoting.FullscreenAppsV1.prototype.toggle = function() { + this.activate(!this.isActive()); +}; + +remoting.FullscreenAppsV1.prototype.isActive = function() { + return document.webkitIsFullScreen; +}; + +remoting.FullscreenAppsV1.prototype.addListener = function(callback) { + this.eventSource_.addEventListener(this.kEventName_, callback); +}; + +remoting.FullscreenAppsV1.prototype.removeListener = function(callback) { + this.eventSource_.removeEventListener(this.kEventName_, callback); +}; + +remoting.FullscreenAppsV1.prototype.syncWithMaximize = function(sync) { +}; + +/** + * @private + */ +remoting.FullscreenAppsV1.prototype.onFullscreenChanged_ = function() { + this.eventSource_.raiseEvent(this.kEventName_, this.isActive()); +}; diff --git a/remoting/webapp/fullscreen_v2.js b/remoting/webapp/fullscreen_v2.js new file mode 100644 index 0000000..4e19f34 --- /dev/null +++ b/remoting/webapp/fullscreen_v2.js @@ -0,0 +1,121 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * Full-screen implementation for apps v2, using chrome.AppWindow. + */ + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** + * @constructor + * @implements {remoting.Fullscreen} + */ +remoting.FullscreenAppsV2 = function() { + /** + * @type {boolean} True if maximize/restore events are being hooked. + * @private + */ + this.hookingWindowEvents_ = false; + + /** + * @type {boolean} True if the next onRestored event should cause callbacks + * to be notified of a full-screen changed event. onRestored fires when + * full-screen mode is exited and also when the window is restored from + * being minimized; callbacks should not be notified of the latter. + * @private + */ + this.notifyCallbacksOnRestore_ = this.isActive(); + + /** + * @type {string} Internal 'full-screen changed' event name + * @private + */ + this.kEventName_ = '_fullscreenchanged'; + + /** + * @type {base.EventSource} + * @private + */ + this.eventSource_ = new base.EventSource(); + this.eventSource_.defineEvents([this.kEventName_]); + + chrome.app.window.current().onFullscreened.addListener( + this.onFullscreened_.bind(this)); + chrome.app.window.current().onMaximized.addListener( + this.onMaximized_.bind(this)); + chrome.app.window.current().onRestored.addListener( + this.onRestored_.bind(this)); +}; + +remoting.FullscreenAppsV2.prototype.activate = function( + fullscreen, opt_onDone) { + if (opt_onDone) { + if (this.isActive() == fullscreen) { + opt_onDone(); + } else { + /** @type {remoting.Fullscreen} */ + var that = this; + var callbackAndRemoveListener = function() { + that.removeListener(callbackAndRemoveListener); + opt_onDone(); + }; + this.addListener(callbackAndRemoveListener); + } + } + + if (fullscreen) { + chrome.app.window.current().fullscreen(); + } else if (this.isActive()) { + chrome.app.window.current().restore(); + } +}; + +remoting.FullscreenAppsV2.prototype.toggle = function() { + this.activate(!this.isActive()); +}; + +remoting.FullscreenAppsV2.prototype.isActive = function() { + return chrome.app.window.current().isFullscreen(); +}; + +remoting.FullscreenAppsV2.prototype.addListener = function(callback) { + this.eventSource_.addEventListener(this.kEventName_, callback); +}; + +remoting.FullscreenAppsV2.prototype.removeListener = function(callback) { + this.eventSource_.removeEventListener(this.kEventName_, callback); +}; + +remoting.FullscreenAppsV2.prototype.syncWithMaximize = function(sync) { + if (sync && chrome.app.window.current().isMaximized()) { + this.activate(true); + } + this.hookingWindowEvents_ = sync; +}; + +remoting.FullscreenAppsV2.prototype.onFullscreened_ = function() { + this.notifyCallbacksOnRestore_ = true; + this.eventSource_.raiseEvent(this.kEventName_, true); +}; + +remoting.FullscreenAppsV2.prototype.onMaximized_ = function() { + if (this.hookingWindowEvents_) { + this.activate(true); + } +}; + +remoting.FullscreenAppsV2.prototype.onRestored_ = function() { + if (this.hookingWindowEvents_) { + this.activate(false); + } + if (this.notifyCallbacksOnRestore_) { + this.notifyCallbacksOnRestore_ = false; + this.eventSource_.raiseEvent(this.kEventName_, false); + } +}; diff --git a/remoting/webapp/js_proto/chrome_proto.js b/remoting/webapp/js_proto/chrome_proto.js index 0e41606..273910e 100644 --- a/remoting/webapp/js_proto/chrome_proto.js +++ b/remoting/webapp/js_proto/chrome_proto.js @@ -279,11 +279,21 @@ var AppWindow = function() { this.contentWindow = null; /** @type {chrome.Event} */ this.onRestored = null; + /** @type {chrome.Event} */ + this.onMaximized = null; + /** @type {chrome.Event} */ + this.onFullscreened = null; }; AppWindow.prototype.close = function() {}; AppWindow.prototype.drawAttention = function() {}; AppWindow.prototype.minimize = function() {}; +AppWindow.prototype.restore = function() {}; +AppWindow.prototype.fullscreen = function() {}; +/** @return {boolean} */ +AppWindow.prototype.isFullscreen = function() {}; +/** @return {boolean} */ +AppWindow.prototype.isMaximized = function() {}; /** * @param {{rects: Array.<ClientRect>}} rects diff --git a/remoting/webapp/remoting.js b/remoting/webapp/remoting.js index d015832..07bd828 100644 --- a/remoting/webapp/remoting.js +++ b/remoting/webapp/remoting.js @@ -60,12 +60,14 @@ remoting.init = function() { remoting.settings = new remoting.Settings(); if (remoting.isAppsV2) { remoting.identity = new remoting.Identity(consentRequired_); + remoting.fullscreen = new remoting.FullscreenAppsV2(); } else { remoting.oauth2 = new remoting.OAuth2(); if (!remoting.oauth2.isAuthenticated()) { document.getElementById('auth-dialog').hidden = false; } remoting.identity = remoting.oauth2; + remoting.fullscreen = new remoting.FullscreenAppsV1(); } remoting.stats = new remoting.ConnectionStats( document.getElementById('statistics')); |