OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Class handling user-facing aspects of the client session. | 7 * Class handling user-facing aspects of the client session. |
8 */ | 8 */ |
9 | 9 |
10 'use strict'; | 10 'use strict'; |
11 | 11 |
12 /** @suppress {duplicate} */ | 12 /** @suppress {duplicate} */ |
13 var remoting = remoting || {}; | 13 var remoting = remoting || {}; |
14 | 14 |
15 /** | 15 /** |
16 * True to enable mouse lock. | 16 * True to enable mouse lock. |
17 * This is currently disabled because the current client plugin does not | 17 * This is currently disabled because the current client plugin does not |
18 * properly handle mouse lock and delegated large cursors at the same time. | 18 * properly handle mouse lock and delegated large cursors at the same time. |
19 * This should be re-enabled (by removing this flag) once a version of | 19 * This should be re-enabled (by removing this flag) once a version of |
20 * the plugin that supports both has reached Chrome Stable channel. | 20 * the plugin that supports both has reached Chrome Stable channel. |
21 * (crbug.com/429322). | 21 * (crbug.com/429322). |
22 * | 22 * |
23 * @type {boolean} | 23 * @type {boolean} |
24 */ | 24 */ |
25 remoting.enableMouseLock = false; | 25 remoting.enableMouseLock = false; |
26 | 26 |
27 /** | 27 /** |
28 * @param {remoting.ClientSession} session | 28 * @param {remoting.ClientSession} session |
29 * @param {HTMLElement} container | 29 * @param {HTMLElement} container |
30 * @param {string} hostDisplayName A human-readable name for the host. | 30 * @param {remoting.Host} host |
31 * @param {string} hostId The host identifier for Me2Me, or empty for IT2Me. | |
32 * Mixed into authentication hashes for some authentication methods. | |
33 * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. | 31 * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection. |
34 * @param {string} defaultRemapKeys The default set of remap keys, to use | 32 * @param {string} defaultRemapKeys The default set of remap keys, to use |
35 * when the client doesn't define any. | 33 * when the client doesn't define any. |
36 * @param {function(remoting.Error, remoting.ClientPlugin): void} onInitialized | 34 * @param {function(remoting.Error, remoting.ClientPlugin): void} onInitialized |
37 * @constructor | 35 * @constructor |
38 * @extends {base.EventSourceImpl} | 36 * @extends {base.EventSourceImpl} |
39 */ | 37 */ |
40 remoting.DesktopConnectedView = function(session, container, hostDisplayName, | 38 remoting.DesktopConnectedView = function(session, container, host, mode, |
41 hostId, mode, defaultRemapKeys, | 39 defaultRemapKeys, onInitialized) { |
42 onInitialized) { | |
43 this.session_ = session; | 40 this.session_ = session; |
44 | 41 |
45 /** @type {HTMLElement} @private */ | 42 /** @type {HTMLElement} @private */ |
46 this.container_ = container; | 43 this.container_ = container; |
47 | 44 |
48 /** @type {remoting.ClientPlugin} @private */ | 45 /** @type {remoting.ClientPlugin} @private */ |
49 this.plugin_ = null; | 46 this.plugin_ = null; |
50 | 47 |
51 /** @private */ | 48 /** @private */ |
52 this.hostDisplayName_ = hostDisplayName; | 49 this.host_ = host; |
53 | |
54 /** @private */ | |
55 this.hostId_ = hostId; | |
56 | 50 |
57 /** @private */ | 51 /** @private */ |
58 this.mode_ = mode; | 52 this.mode_ = mode; |
59 | 53 |
60 /** @type {boolean} @private */ | |
61 this.shrinkToFit_ = true; | |
62 | |
63 /** @type {boolean} @private */ | |
64 this.resizeToClient_ = true; | |
65 | |
66 /** @type {number} @private */ | |
67 this.desktopScale_ = 1.0; | |
68 | |
69 /** @type {string} @private */ | 54 /** @type {string} @private */ |
70 this.defaultRemapKeys_ = defaultRemapKeys; | 55 this.defaultRemapKeys_ = defaultRemapKeys; |
71 | 56 |
72 /** @type {string} @private */ | 57 /** @type {string} @private */ |
73 this.remapKeys_ = ''; | 58 this.remapKeys_ = ''; |
74 | 59 |
75 /** | 60 /** |
76 * Called when the UI is finished initializing. | 61 * Called when the UI is finished initializing. |
77 * @type {function(remoting.Error, remoting.ClientPlugin):void} | 62 * @type {function(remoting.Error, remoting.ClientPlugin):void} |
78 */ | 63 */ |
79 this.onInitialized_ = onInitialized; | 64 this.onInitialized_ = onInitialized; |
80 | 65 |
81 /** @type {function(boolean=):void} @private */ | 66 /** @type {function(boolean=):void} @private */ |
82 this.callOnFullScreenChanged_ = this.onFullScreenChanged_.bind(this) | 67 this.callOnFullScreenChanged_ = this.onFullScreenChanged_.bind(this) |
83 | 68 |
84 /** @private */ | 69 /** @private */ |
85 this.callPluginLostFocus_ = this.pluginLostFocus_.bind(this); | 70 this.callPluginLostFocus_ = this.pluginLostFocus_.bind(this); |
86 /** @private */ | 71 /** @private */ |
87 this.callPluginGotFocus_ = this.pluginGotFocus_.bind(this); | 72 this.callPluginGotFocus_ = this.pluginGotFocus_.bind(this); |
88 | 73 |
89 /** @type {number?} @private */ | |
90 this.notifyClientResolutionTimer_ = null; | |
91 | |
92 /** @type {Element} @private */ | 74 /** @type {Element} @private */ |
93 this.mouseCursorOverlay_ = | 75 this.mouseCursorOverlay_ = |
94 this.container_.querySelector('.mouse-cursor-overlay'); | 76 this.container_.querySelector('.mouse-cursor-overlay'); |
95 | 77 |
| 78 /** @private {remoting.DesktopViewport} */ |
| 79 this.viewport_ = null; |
| 80 |
96 /** @type {Element} */ | 81 /** @type {Element} */ |
97 var img = this.mouseCursorOverlay_; | 82 var img = this.mouseCursorOverlay_; |
98 /** @param {Event} event @private */ | 83 /** @param {Event} event @private */ |
99 this.updateMouseCursorPosition_ = function(event) { | 84 this.updateMouseCursorPosition_ = function(event) { |
100 img.style.top = event.y + 'px'; | 85 img.style.top = event.y + 'px'; |
101 img.style.left = event.x + 'px'; | 86 img.style.left = event.x + 'px'; |
102 }; | 87 }; |
103 | 88 |
104 /** @type {number?} @private */ | |
105 this.bumpScrollTimer_ = null; | |
106 | |
107 // Bump-scroll test variables. Override to use a fake value for the width | |
108 // and height of the client plugin so that bump-scrolling can be tested | |
109 // without relying on the actual size of the host desktop. | |
110 /** @type {number} @private */ | |
111 this.pluginWidthForBumpScrollTesting = 0; | |
112 /** @type {number} @private */ | |
113 this.pluginHeightForBumpScrollTesting = 0; | |
114 | |
115 /** @type {remoting.VideoFrameRecorder} @private */ | 89 /** @type {remoting.VideoFrameRecorder} @private */ |
116 this.videoFrameRecorder_ = null; | 90 this.videoFrameRecorder_ = null; |
117 }; | 91 }; |
118 | 92 |
119 base.extend(remoting.DesktopConnectedView, base.EventSourceImpl); | 93 base.extend(remoting.DesktopConnectedView, base.EventSourceImpl); |
120 | 94 |
121 /** @enum {string} */ | |
122 remoting.DesktopConnectedView.Events = { | |
123 bumpScrollStarted: 'bumpScrollStarted', | |
124 bumpScrollStopped: 'bumpScrollStopped' | |
125 }; | |
126 | |
127 // The mode of this session. | 95 // The mode of this session. |
128 /** @enum {number} */ | 96 /** @enum {number} */ |
129 remoting.DesktopConnectedView.Mode = { | 97 remoting.DesktopConnectedView.Mode = { |
130 IT2ME: 0, | 98 IT2ME: 0, |
131 ME2ME: 1, | 99 ME2ME: 1, |
132 APP_REMOTING: 2 | 100 APP_REMOTING: 2 |
133 }; | 101 }; |
134 | 102 |
135 // Keys for per-host settings. | 103 // Keys for per-host settings. |
136 remoting.DesktopConnectedView.KEY_REMAP_KEYS = 'remapKeys'; | 104 remoting.DesktopConnectedView.KEY_REMAP_KEYS = 'remapKeys'; |
137 remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT = 'resizeToClient'; | 105 remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT = 'resizeToClient'; |
138 remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT = 'shrinkToFit'; | 106 remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT = 'shrinkToFit'; |
139 remoting.DesktopConnectedView.KEY_DESKTOP_SCALE = 'desktopScale'; | 107 remoting.DesktopConnectedView.KEY_DESKTOP_SCALE = 'desktopScale'; |
140 | 108 |
141 /** | 109 /** |
142 * Get host display name. | 110 * Get host display name. |
143 * | 111 * |
144 * @return {string} | 112 * @return {string} |
145 */ | 113 */ |
146 remoting.DesktopConnectedView.prototype.getHostDisplayName = function() { | 114 remoting.DesktopConnectedView.prototype.getHostDisplayName = function() { |
147 return this.hostDisplayName_; | 115 return this.host_.hostName; |
148 }; | 116 }; |
149 | 117 |
150 /** | 118 /** |
151 * @return {remoting.DesktopConnectedView.Mode} The current state. | 119 * @return {remoting.DesktopConnectedView.Mode} The current state. |
152 */ | 120 */ |
153 remoting.DesktopConnectedView.prototype.getMode = function() { | 121 remoting.DesktopConnectedView.prototype.getMode = function() { |
154 return this.mode_; | 122 return this.mode_; |
155 }; | 123 }; |
156 | 124 |
157 /** | 125 /** |
158 * @return {boolean} True if shrink-to-fit is enabled; false otherwise. | 126 * @return {boolean} True if shrink-to-fit is enabled; false otherwise. |
159 */ | 127 */ |
160 remoting.DesktopConnectedView.prototype.getShrinkToFit = function() { | 128 remoting.DesktopConnectedView.prototype.getShrinkToFit = function() { |
161 return this.shrinkToFit_; | 129 if (this.viewport_) { |
| 130 return this.viewport_.getShrinkToFit(); |
| 131 } |
162 }; | 132 }; |
163 | 133 |
164 /** | 134 /** |
165 * @return {boolean} True if resize-to-client is enabled; false otherwise. | 135 * @return {boolean} True if resize-to-client is enabled; false otherwise. |
166 */ | 136 */ |
167 remoting.DesktopConnectedView.prototype.getResizeToClient = function() { | 137 remoting.DesktopConnectedView.prototype.getResizeToClient = function() { |
168 return this.resizeToClient_; | 138 if (this.viewport_) { |
| 139 return this.viewport_.getResizeToClient(); |
| 140 } |
169 }; | 141 }; |
170 | 142 |
171 /** | 143 /** |
172 * @return {Element} The element that should host the plugin. | 144 * @return {Element} The element that should host the plugin. |
| 145 * @private |
173 */ | 146 */ |
174 remoting.DesktopConnectedView.prototype.getPluginContainer = function() { | 147 remoting.DesktopConnectedView.prototype.getPluginContainer_ = function() { |
175 return this.container_.querySelector('.client-plugin-container') | 148 return this.container_.querySelector('.client-plugin-container'); |
176 }; | 149 }; |
177 | 150 |
178 /** | 151 /** |
179 * @return {{width: number, height: number}} The height of the window's client | |
180 * area. This differs between apps v1 and apps v2 due to the custom window | |
181 * borders used by the latter. | |
182 * TODO: make private | |
183 */ | |
184 remoting.DesktopConnectedView.prototype.getClientArea_ = function() { | |
185 return remoting.windowFrame ? | |
186 remoting.windowFrame.getClientArea() : | |
187 { 'width': window.innerWidth, 'height': window.innerHeight }; | |
188 }; | |
189 | |
190 /** | |
191 * Notifies the host of the client's current dimensions and DPI. | 152 * Notifies the host of the client's current dimensions and DPI. |
192 * Also takes into account per-host scaling factor, if configured. | 153 * Also takes into account per-host scaling factor, if configured. |
193 * TODO: private | 154 * TODO: private |
194 */ | 155 */ |
195 remoting.DesktopConnectedView.prototype.notifyClientResolution_ = function() { | 156 remoting.DesktopConnectedView.prototype.notifyClientResolution_ = function() { |
196 var clientArea = this.getClientArea_(); | 157 if (this.viewport_) { |
197 this.plugin_.notifyClientResolution(clientArea.width * this.desktopScale_, | 158 this.viewport_.resizeHostDesktop(); |
198 clientArea.height * this.desktopScale_, | 159 } |
199 window.devicePixelRatio); | 160 }; |
| 161 |
| 162 /** @return {remoting.DesktopViewport} */ |
| 163 remoting.DesktopConnectedView.prototype.getViewportForTesting = function() { |
| 164 return this.viewport_; |
200 }; | 165 }; |
201 | 166 |
202 /** | 167 /** |
203 * Adds <embed> element to the UI container and readies the session object. | 168 * Adds <embed> element to the UI container and readies the session object. |
204 * | 169 * |
205 * @param {function(string, string):boolean} onExtensionMessage The handler for | 170 * @param {function(string, string):boolean} onExtensionMessage The handler for |
206 * protocol extension messages. Returns true if a message is recognized; | 171 * protocol extension messages. Returns true if a message is recognized; |
207 * false otherwise. | 172 * false otherwise. |
208 * @param {Array<string>} requiredCapabilities A list of capabilities | 173 * @param {Array.<string>} requiredCapabilities A list of capabilities |
209 * required by this application. | 174 * required by this application. |
210 */ | 175 */ |
211 remoting.DesktopConnectedView.prototype.createPluginAndConnect = | 176 remoting.DesktopConnectedView.prototype.createPluginAndConnect = |
212 function(onExtensionMessage, requiredCapabilities) { | 177 function(onExtensionMessage, requiredCapabilities) { |
213 this.plugin_ = remoting.ClientPlugin.factory.createPlugin( | 178 this.plugin_ = remoting.ClientPlugin.factory.createPlugin( |
214 this.getPluginContainer(), | 179 this.getPluginContainer_(), |
215 onExtensionMessage, requiredCapabilities); | 180 onExtensionMessage, requiredCapabilities); |
216 remoting.HostSettings.load(this.hostId_, | 181 var that = this; |
217 this.onHostSettingsLoaded_.bind(this)); | 182 this.host_.options().load().then(function(){ |
| 183 that.plugin_.initialize(that.onPluginInitialized_.bind(that)); |
| 184 }); |
218 }; | 185 }; |
219 | 186 |
220 /** | 187 /** |
221 * @param {Object<string|boolean|number>} options The current options for the | |
222 * host, or {} if this client has no saved settings for the host. | |
223 * @private | |
224 */ | |
225 remoting.DesktopConnectedView.prototype.onHostSettingsLoaded_ = function( | |
226 options) { | |
227 if (remoting.DesktopConnectedView.KEY_REMAP_KEYS in options && | |
228 typeof(options[remoting.DesktopConnectedView.KEY_REMAP_KEYS]) == | |
229 'string') { | |
230 this.remapKeys_ = /** @type {string} */ | |
231 (options[remoting.DesktopConnectedView.KEY_REMAP_KEYS]); | |
232 } | |
233 if (remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT in options && | |
234 typeof(options[remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT]) == | |
235 'boolean') { | |
236 this.resizeToClient_ = /** @type {boolean} */ | |
237 (options[remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT]); | |
238 } | |
239 if (remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT in options && | |
240 typeof(options[remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT]) == | |
241 'boolean') { | |
242 this.shrinkToFit_ = /** @type {boolean} */ | |
243 (options[remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT]); | |
244 } | |
245 if (remoting.DesktopConnectedView.KEY_DESKTOP_SCALE in options && | |
246 typeof(options[remoting.DesktopConnectedView.KEY_DESKTOP_SCALE]) == | |
247 'number') { | |
248 this.desktopScale_ = /** @type {number} */ | |
249 (options[remoting.DesktopConnectedView.KEY_DESKTOP_SCALE]); | |
250 } | |
251 | |
252 /** @param {boolean} result */ | |
253 this.plugin_.initialize(this.onPluginInitialized_.bind(this)); | |
254 }; | |
255 | |
256 /** | |
257 * @param {boolean} initialized | 188 * @param {boolean} initialized |
258 */ | 189 */ |
259 remoting.DesktopConnectedView.prototype.onPluginInitialized_ = function( | 190 remoting.DesktopConnectedView.prototype.onPluginInitialized_ = function( |
260 initialized) { | 191 initialized) { |
261 if (!initialized) { | 192 if (!initialized) { |
262 console.error('ERROR: remoting plugin not loaded'); | 193 console.error('ERROR: remoting plugin not loaded'); |
263 this.onInitialized_(remoting.Error.MISSING_PLUGIN, this.plugin_); | 194 this.onInitialized_(remoting.Error.MISSING_PLUGIN, this.plugin_); |
264 return; | 195 return; |
265 } | 196 } |
266 | 197 |
(...skipping 19 matching lines...) Expand all Loading... |
286 this.applyRemapKeys_(true); | 217 this.applyRemapKeys_(true); |
287 } | 218 } |
288 | 219 |
289 // TODO(wez): Only allow mouse lock if the app has the pointerLock permission. | 220 // TODO(wez): Only allow mouse lock if the app has the pointerLock permission. |
290 // Enable automatic mouse-lock. | 221 // Enable automatic mouse-lock. |
291 if (remoting.enableMouseLock && | 222 if (remoting.enableMouseLock && |
292 this.plugin_.hasFeature(remoting.ClientPlugin.Feature.ALLOW_MOUSE_LOCK)) { | 223 this.plugin_.hasFeature(remoting.ClientPlugin.Feature.ALLOW_MOUSE_LOCK)) { |
293 this.plugin_.allowMouseLock(); | 224 this.plugin_.allowMouseLock(); |
294 } | 225 } |
295 | 226 |
296 this.plugin_.setDesktopShapeUpdateHandler( | |
297 this.onDesktopShapeChanged_.bind(this)); | |
298 this.plugin_.setDesktopSizeUpdateHandler( | |
299 this.onDesktopSizeChanged_.bind(this)); | |
300 this.plugin_.setMouseCursorHandler(this.updateMouseCursorImage_.bind(this)); | 227 this.plugin_.setMouseCursorHandler(this.updateMouseCursorImage_.bind(this)); |
301 | 228 |
302 this.onInitialized_(remoting.Error.NONE, this.plugin_); | 229 this.onInitialized_(remoting.Error.NONE, this.plugin_); |
303 }; | 230 }; |
304 | 231 |
305 /** | 232 /** |
306 * This is a callback that gets called when the plugin notifies us of a change | |
307 * in the size of the remote desktop. | |
308 * | |
309 * @return {void} Nothing. | |
310 * @private | |
311 */ | |
312 remoting.DesktopConnectedView.prototype.onDesktopSizeChanged_ = function() { | |
313 console.log('desktop size changed: ' + | |
314 this.plugin_.getDesktopWidth() + 'x' + | |
315 this.plugin_.getDesktopHeight() +' @ ' + | |
316 this.plugin_.getDesktopXDpi() + 'x' + | |
317 this.plugin_.getDesktopYDpi() + ' DPI'); | |
318 this.updateDimensions(); | |
319 this.updateScrollbarVisibility(); | |
320 }; | |
321 | |
322 /** | |
323 * Sets the non-click-through area of the client in response to notifications | |
324 * from the plugin of desktop shape changes. | |
325 * | |
326 * @param {Array<Array<number>>} rects List of rectangles comprising the | |
327 * desktop shape. | |
328 * @return {void} Nothing. | |
329 * @private | |
330 */ | |
331 remoting.DesktopConnectedView.prototype.onDesktopShapeChanged_ = function( | |
332 rects) { | |
333 // Build the list of rects for the input region. | |
334 var inputRegion = []; | |
335 for (var i = 0; i < rects.length; ++i) { | |
336 var rect = {}; | |
337 rect.left = rects[i][0]; | |
338 rect.top = rects[i][1]; | |
339 rect.width = rects[i][2]; | |
340 rect.height = rects[i][3]; | |
341 inputRegion.push(rect); | |
342 } | |
343 | |
344 remoting.windowShape.setDesktopRects(inputRegion); | |
345 }; | |
346 | |
347 /** | |
348 * This is a callback that gets called when the window is resized. | 233 * This is a callback that gets called when the window is resized. |
349 * | 234 * |
350 * @return {void} Nothing. | 235 * @return {void} Nothing. |
351 */ | 236 */ |
352 remoting.DesktopConnectedView.prototype.onResize = function() { | 237 remoting.DesktopConnectedView.prototype.onResize = function() { |
353 this.updateDimensions(); | 238 if (this.viewport_) { |
354 | 239 this.viewport_.onResize(); |
355 if (this.notifyClientResolutionTimer_) { | |
356 window.clearTimeout(this.notifyClientResolutionTimer_); | |
357 this.notifyClientResolutionTimer_ = null; | |
358 } | 240 } |
359 | |
360 // Defer notifying the host of the change until the window stops resizing, to | |
361 // avoid overloading the control channel with notifications. | |
362 if (this.resizeToClient_) { | |
363 var kResizeRateLimitMs = 1000; | |
364 if (this.session_.hasCapability( | |
365 remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS)) { | |
366 kResizeRateLimitMs = 250; | |
367 } | |
368 var clientArea = this.getClientArea_(); | |
369 this.notifyClientResolutionTimer_ = window.setTimeout( | |
370 this.notifyClientResolution_.bind(this), | |
371 kResizeRateLimitMs); | |
372 } | |
373 | |
374 // If bump-scrolling is enabled, adjust the plugin margins to fully utilize | |
375 // the new window area. | |
376 this.resetScroll_(); | |
377 | |
378 this.updateScrollbarVisibility(); | |
379 }; | 241 }; |
380 | 242 |
381 /** | 243 /** |
382 * Callback that the plugin invokes to indicate when the connection is | 244 * Callback that the plugin invokes to indicate when the connection is |
383 * ready. | 245 * ready. |
384 * | 246 * |
385 * @param {boolean} ready True if the connection is ready. | 247 * @param {boolean} ready True if the connection is ready. |
386 */ | 248 */ |
387 remoting.DesktopConnectedView.prototype.onConnectionReady = function(ready) { | 249 remoting.DesktopConnectedView.prototype.onConnectionReady = function(ready) { |
388 if (!ready) { | 250 if (!ready) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 if (remoting.optionsMenu) { | 290 if (remoting.optionsMenu) { |
429 remoting.optionsMenu.setDesktopConnectedView(null); | 291 remoting.optionsMenu.setDesktopConnectedView(null); |
430 } | 292 } |
431 | 293 |
432 document.body.classList.remove('connected'); | 294 document.body.classList.remove('connected'); |
433 this.container_.removeEventListener( | 295 this.container_.removeEventListener( |
434 'mousemove', this.updateMouseCursorPosition_, true); | 296 'mousemove', this.updateMouseCursorPosition_, true); |
435 // Stop listening for full-screen events. | 297 // Stop listening for full-screen events. |
436 remoting.fullscreen.removeListener(this.callOnFullScreenChanged_); | 298 remoting.fullscreen.removeListener(this.callOnFullScreenChanged_); |
437 | 299 |
| 300 base.dispose(this.viewport_); |
| 301 this.viewport_ = null; |
438 } else { | 302 } else { |
| 303 this.viewport_ = new remoting.DesktopViewport( |
| 304 document.getElementById('scroller'), |
| 305 this.plugin_.hostDesktop(), |
| 306 this.host_.options()); |
439 if (remoting.windowFrame) { | 307 if (remoting.windowFrame) { |
440 remoting.windowFrame.setDesktopConnectedView(this); | 308 remoting.windowFrame.setDesktopConnectedView(this); |
441 } | 309 } |
442 if (remoting.toolbar) { | 310 if (remoting.toolbar) { |
443 remoting.toolbar.setDesktopConnectedView(this); | 311 remoting.toolbar.setDesktopConnectedView(this); |
444 } | 312 } |
445 if (remoting.optionsMenu) { | 313 if (remoting.optionsMenu) { |
446 remoting.optionsMenu.setDesktopConnectedView(this); | 314 remoting.optionsMenu.setDesktopConnectedView(this); |
447 } | 315 } |
448 | 316 |
449 if (this.resizeToClient_) { | |
450 this.notifyClientResolution_(); | |
451 } | |
452 | |
453 document.body.classList.add('connected'); | 317 document.body.classList.add('connected'); |
454 this.container_.addEventListener( | 318 this.container_.addEventListener( |
455 'mousemove', this.updateMouseCursorPosition_, true); | 319 'mousemove', this.updateMouseCursorPosition_, true); |
456 // Activate full-screen related UX. | 320 // Activate full-screen related UX. |
457 remoting.fullscreen.addListener(this.callOnFullScreenChanged_); | 321 remoting.fullscreen.addListener(this.callOnFullScreenChanged_); |
458 this.onDesktopSizeChanged_(); | |
459 this.setFocusHandlers_(); | 322 this.setFocusHandlers_(); |
460 } | 323 } |
461 }; | 324 }; |
462 | 325 |
463 /** | 326 /** |
464 * @return {{top: number, left:number}} The top-left corner of the plugin. | |
465 */ | |
466 remoting.DesktopConnectedView.prototype.getPluginPositionForTesting = function( | |
467 ) { | |
468 var style = this.container_.style; | |
469 return { | |
470 top: parseFloat(style.marginTop), | |
471 left: parseFloat(style.marginLeft) | |
472 }; | |
473 }; | |
474 | |
475 /** | |
476 * Constrains the focus to the plugin element. | 327 * Constrains the focus to the plugin element. |
477 * @private | 328 * @private |
478 */ | 329 */ |
479 remoting.DesktopConnectedView.prototype.setFocusHandlers_ = function() { | 330 remoting.DesktopConnectedView.prototype.setFocusHandlers_ = function() { |
480 this.plugin_.element().addEventListener( | 331 this.plugin_.element().addEventListener( |
481 'focus', this.callPluginGotFocus_, false); | 332 'focus', this.callPluginGotFocus_, false); |
482 this.plugin_.element().addEventListener( | 333 this.plugin_.element().addEventListener( |
483 'blur', this.callPluginLostFocus_, false); | 334 'blur', this.callPluginLostFocus_, false); |
484 this.plugin_.element().focus(); | 335 this.plugin_.element().focus(); |
485 }; | 336 }; |
486 | 337 |
487 /** | 338 /** |
488 * Set the shrink-to-fit and resize-to-client flags and save them if this is | 339 * Set the shrink-to-fit and resize-to-client flags and save them if this is |
489 * a Me2Me connection. | 340 * a Me2Me connection. |
490 * | 341 * |
491 * @param {boolean} shrinkToFit True if the remote desktop should be scaled | 342 * @param {boolean} shrinkToFit True if the remote desktop should be scaled |
492 * down if it is larger than the client window; false if scroll-bars | 343 * down if it is larger than the client window; false if scroll-bars |
493 * should be added in this case. | 344 * should be added in this case. |
494 * @param {boolean} resizeToClient True if window resizes should cause the | 345 * @param {boolean} resizeToClient True if window resizes should cause the |
495 * host to attempt to resize its desktop to match the client window size; | 346 * host to attempt to resize its desktop to match the client window size; |
496 * false to disable this behaviour for subsequent window resizes--the | 347 * false to disable this behaviour for subsequent window resizes--the |
497 * current host desktop size is not restored in this case. | 348 * current host desktop size is not restored in this case. |
498 * @return {void} Nothing. | 349 * @return {void} Nothing. |
499 */ | 350 */ |
500 remoting.DesktopConnectedView.prototype.setScreenMode = | 351 remoting.DesktopConnectedView.prototype.setScreenMode = |
501 function(shrinkToFit, resizeToClient) { | 352 function(shrinkToFit, resizeToClient) { |
502 if (resizeToClient && !this.resizeToClient_) { | 353 this.viewport_.setScreenMode(shrinkToFit, resizeToClient); |
503 this.notifyClientResolution_(); | |
504 } | |
505 | |
506 // If enabling shrink, reset bump-scroll offsets. | |
507 var needsScrollReset = shrinkToFit && !this.shrinkToFit_; | |
508 | |
509 this.shrinkToFit_ = shrinkToFit; | |
510 this.resizeToClient_ = resizeToClient; | |
511 this.updateScrollbarVisibility(); | |
512 | |
513 if (this.hostId_ != '') { | |
514 var options = {}; | |
515 options[remoting.DesktopConnectedView.KEY_SHRINK_TO_FIT] = | |
516 this.shrinkToFit_; | |
517 options[remoting.DesktopConnectedView.KEY_RESIZE_TO_CLIENT] = | |
518 this.resizeToClient_; | |
519 remoting.HostSettings.save(this.hostId_, options); | |
520 } | |
521 | |
522 this.updateDimensions(); | |
523 if (needsScrollReset) { | |
524 this.resetScroll_(); | |
525 } | |
526 }; | 354 }; |
527 | 355 |
528 /** | 356 /** |
529 * Sets and stores the scale factor to apply to host sizing requests. | |
530 * The desktopScale applies to the dimensions reported to the host, not | |
531 * to the client DPI reported to it. | |
532 * | |
533 * @param {number} desktopScale Scale factor to apply. | |
534 */ | |
535 remoting.DesktopConnectedView.prototype.setDesktopScale = function( | |
536 desktopScale) { | |
537 this.desktopScale_ = desktopScale; | |
538 | |
539 // onResize() will update the plugin size and scrollbars for the new | |
540 // scaled plugin dimensions, and send a client resolution notification. | |
541 this.onResize(); | |
542 | |
543 // Save the new desktop scale setting. | |
544 var options = {}; | |
545 options[remoting.DesktopConnectedView.KEY_DESKTOP_SCALE] = this.desktopScale_; | |
546 remoting.HostSettings.save(this.hostId_, options); | |
547 }; | |
548 | |
549 /** | |
550 * Called when the full-screen status has changed, either via the | 357 * Called when the full-screen status has changed, either via the |
551 * remoting.Fullscreen class, or via a system event such as the Escape key | 358 * remoting.Fullscreen class, or via a system event such as the Escape key |
552 * | 359 * |
553 * @param {boolean=} fullscreen True if the app is entering full-screen mode; | 360 * @param {boolean=} fullscreen True if the app is entering full-screen mode; |
554 * false if it is leaving it. | 361 * false if it is leaving it. |
555 * @private | 362 * @private |
556 */ | 363 */ |
557 remoting.DesktopConnectedView.prototype.onFullScreenChanged_ = function ( | 364 remoting.DesktopConnectedView.prototype.onFullScreenChanged_ = function ( |
558 fullscreen) { | 365 fullscreen) { |
559 this.enableBumpScroll_(fullscreen); | 366 if (this.viewport_) { |
| 367 this.viewport_.enableBumpScroll(fullscreen); |
| 368 } |
560 }; | 369 }; |
561 | 370 |
562 /** | 371 /** |
563 * Callback function called when the plugin element gets focus. | 372 * Callback function called when the plugin element gets focus. |
564 */ | 373 */ |
565 remoting.DesktopConnectedView.prototype.pluginGotFocus_ = function() { | 374 remoting.DesktopConnectedView.prototype.pluginGotFocus_ = function() { |
566 remoting.clipboard.initiateToHost(); | 375 remoting.clipboard.initiateToHost(); |
567 }; | 376 }; |
568 | 377 |
569 /** | 378 /** |
(...skipping 22 matching lines...) Expand all Loading... |
592 function(url, hotspotX, hotspotY) { | 401 function(url, hotspotX, hotspotY) { |
593 this.mouseCursorOverlay_.hidden = !url; | 402 this.mouseCursorOverlay_.hidden = !url; |
594 if (url) { | 403 if (url) { |
595 this.mouseCursorOverlay_.style.marginLeft = '-' + hotspotX + 'px'; | 404 this.mouseCursorOverlay_.style.marginLeft = '-' + hotspotX + 'px'; |
596 this.mouseCursorOverlay_.style.marginTop = '-' + hotspotY + 'px'; | 405 this.mouseCursorOverlay_.style.marginTop = '-' + hotspotY + 'px'; |
597 this.mouseCursorOverlay_.src = url; | 406 this.mouseCursorOverlay_.src = url; |
598 } | 407 } |
599 }; | 408 }; |
600 | 409 |
601 /** | 410 /** |
602 * Enable or disable bump-scrolling. When disabling bump scrolling, also reset | |
603 * the scroll offsets to (0, 0). | |
604 * @param {boolean=} enable True to enable bump-scrolling, false to disable it. | |
605 * @private | |
606 */ | |
607 remoting.DesktopConnectedView.prototype.enableBumpScroll_ = function(enable) { | |
608 var element = /** @type{HTMLElement} */ (document.documentElement); | |
609 if (enable) { | |
610 /** @type {null|function(Event):void} */ | |
611 this.onMouseMoveRef_ = this.onMouseMove_.bind(this); | |
612 element.addEventListener('mousemove', this.onMouseMoveRef_, false); | |
613 } else { | |
614 element.removeEventListener('mousemove', this.onMouseMoveRef_, false); | |
615 this.onMouseMoveRef_ = null; | |
616 this.resetScroll_(); | |
617 } | |
618 }; | |
619 | |
620 remoting.DesktopConnectedView.prototype.resetScroll_ = function() { | |
621 this.container_.style.marginTop = '0px'; | |
622 this.container_.style.marginLeft = '0px'; | |
623 }; | |
624 | |
625 /** | |
626 * @param {Event} event The mouse event. | |
627 * @private | |
628 */ | |
629 remoting.DesktopConnectedView.prototype.onMouseMove_ = function(event) { | |
630 if (this.bumpScrollTimer_) { | |
631 window.clearTimeout(this.bumpScrollTimer_); | |
632 this.bumpScrollTimer_ = null; | |
633 } | |
634 | |
635 /** | |
636 * Compute the scroll speed based on how close the mouse is to the edge. | |
637 * @param {number} mousePos The mouse x- or y-coordinate | |
638 * @param {number} size The width or height of the content area. | |
639 * @return {number} The scroll delta, in pixels. | |
640 */ | |
641 var computeDelta = function(mousePos, size) { | |
642 var threshold = 10; | |
643 if (mousePos >= size - threshold) { | |
644 return 1 + 5 * (mousePos - (size - threshold)) / threshold; | |
645 } else if (mousePos <= threshold) { | |
646 return -1 - 5 * (threshold - mousePos) / threshold; | |
647 } | |
648 return 0; | |
649 }; | |
650 | |
651 var clientArea = this.getClientArea_(); | |
652 var dx = computeDelta(event.x, clientArea.width); | |
653 var dy = computeDelta(event.y, clientArea.height); | |
654 | |
655 if (dx != 0 || dy != 0) { | |
656 this.raiseEvent(remoting.DesktopConnectedView.Events.bumpScrollStarted); | |
657 /** @type {remoting.DesktopConnectedView} */ | |
658 var that = this; | |
659 /** | |
660 * Scroll the view, and schedule a timer to do so again unless we've hit | |
661 * the edges of the screen. This timer is cancelled when the mouse moves. | |
662 * @param {number} expected The time at which we expect to be called. | |
663 */ | |
664 var repeatScroll = function(expected) { | |
665 /** @type {number} */ | |
666 var now = new Date().getTime(); | |
667 /** @type {number} */ | |
668 var timeout = 10; | |
669 var lateAdjustment = 1 + (now - expected) / timeout; | |
670 if (that.scroll_(lateAdjustment * dx, lateAdjustment * dy)) { | |
671 that.raiseEvent(remoting.DesktopConnectedView.Events.bumpScrollStopped); | |
672 } else { | |
673 that.bumpScrollTimer_ = window.setTimeout( | |
674 function() { repeatScroll(now + timeout); }, | |
675 timeout); | |
676 } | |
677 }; | |
678 repeatScroll(new Date().getTime()); | |
679 } | |
680 }; | |
681 | |
682 /** | |
683 * Scroll the client plugin by the specified amount, keeping it visible. | |
684 * Note that this is only used in content full-screen mode (not windowed or | |
685 * browser full-screen modes), where window.scrollBy and the scrollTop and | |
686 * scrollLeft properties don't work. | |
687 * @param {number} dx The amount by which to scroll horizontally. Positive to | |
688 * scroll right; negative to scroll left. | |
689 * @param {number} dy The amount by which to scroll vertically. Positive to | |
690 * scroll down; negative to scroll up. | |
691 * @return {boolean} True if the requested scroll had no effect because both | |
692 * vertical and horizontal edges of the screen have been reached. | |
693 * @private | |
694 */ | |
695 remoting.DesktopConnectedView.prototype.scroll_ = function(dx, dy) { | |
696 /** | |
697 * Helper function for x- and y-scrolling | |
698 * @param {number|string} curr The current margin, eg. "10px". | |
699 * @param {number} delta The requested scroll amount. | |
700 * @param {number} windowBound The size of the window, in pixels. | |
701 * @param {number} pluginBound The size of the plugin, in pixels. | |
702 * @param {{stop: boolean}} stop Reference parameter used to indicate when | |
703 * the scroll has reached one of the edges and can be stopped in that | |
704 * direction. | |
705 * @return {string} The new margin value. | |
706 */ | |
707 var adjustMargin = function(curr, delta, windowBound, pluginBound, stop) { | |
708 var minMargin = Math.min(0, windowBound - pluginBound); | |
709 var result = (curr ? parseFloat(curr) : 0) - delta; | |
710 result = Math.min(0, Math.max(minMargin, result)); | |
711 stop.stop = (result == 0 || result == minMargin); | |
712 return result + 'px'; | |
713 }; | |
714 | |
715 var plugin = this.plugin_.element(); | |
716 var style = this.container_.style; | |
717 | |
718 var stopX = { stop: false }; | |
719 var clientArea = this.getClientArea_(); | |
720 style.marginLeft = adjustMargin(style.marginLeft, dx, clientArea.width, | |
721 this.pluginWidthForBumpScrollTesting || plugin.clientWidth, stopX); | |
722 | |
723 var stopY = { stop: false }; | |
724 style.marginTop = adjustMargin( | |
725 style.marginTop, dy, clientArea.height, | |
726 this.pluginHeightForBumpScrollTesting || plugin.clientHeight, stopY); | |
727 return stopX.stop && stopY.stop; | |
728 }; | |
729 | |
730 /** | |
731 * Refreshes the plugin's dimensions, taking into account the sizes of the | |
732 * remote desktop and client window, and the current scale-to-fit setting. | |
733 * | |
734 * @return {void} Nothing. | |
735 */ | |
736 remoting.DesktopConnectedView.prototype.updateDimensions = function() { | |
737 if (this.plugin_.getDesktopWidth() == 0 || | |
738 this.plugin_.getDesktopHeight() == 0) { | |
739 return; | |
740 } | |
741 | |
742 var desktopSize = { width: this.plugin_.getDesktopWidth(), | |
743 height: this.plugin_.getDesktopHeight() }; | |
744 var desktopDpi = { x: this.plugin_.getDesktopXDpi(), | |
745 y: this.plugin_.getDesktopYDpi() }; | |
746 var newSize = remoting.DesktopConnectedView.choosePluginSize( | |
747 this.getClientArea_(), window.devicePixelRatio, | |
748 desktopSize, desktopDpi, this.desktopScale_, | |
749 remoting.fullscreen.isActive(), this.shrinkToFit_); | |
750 | |
751 // Resize the plugin if necessary. | |
752 console.log('plugin dimensions:' + newSize.width + 'x' + newSize.height); | |
753 this.plugin_.element().style.width = newSize.width + 'px'; | |
754 this.plugin_.element().style.height = newSize.height + 'px'; | |
755 | |
756 // When we receive the first plugin dimensions from the host, we know that | |
757 // remote host has started. | |
758 remoting.app.onVideoStreamingStarted(); | |
759 } | |
760 | |
761 /** | |
762 * Helper function accepting client and host dimensions, and returning a chosen | |
763 * size for the plugin element, in DIPs. | |
764 * | |
765 * @param {{width: number, height: number}} clientSizeDips Available client | |
766 * dimensions, in DIPs. | |
767 * @param {number} clientPixelRatio Number of physical pixels per client DIP. | |
768 * @param {{width: number, height: number}} desktopSize Size of the host desktop | |
769 * in physical pixels. | |
770 * @param {{x: number, y: number}} desktopDpi DPI of the host desktop in both | |
771 * dimensions. | |
772 * @param {number} desktopScale The scale factor configured for the host. | |
773 * @param {boolean} isFullscreen True if full-screen mode is active. | |
774 * @param {boolean} shrinkToFit True if shrink-to-fit should be applied. | |
775 * @return {{width: number, height: number}} Chosen plugin dimensions, in DIPs. | |
776 */ | |
777 remoting.DesktopConnectedView.choosePluginSize = function( | |
778 clientSizeDips, clientPixelRatio, desktopSize, desktopDpi, desktopScale, | |
779 isFullscreen, shrinkToFit) { | |
780 base.debug.assert(clientSizeDips.width > 0); | |
781 base.debug.assert(clientSizeDips.height > 0); | |
782 base.debug.assert(clientPixelRatio >= 1.0); | |
783 base.debug.assert(desktopSize.width > 0); | |
784 base.debug.assert(desktopSize.height > 0); | |
785 base.debug.assert(desktopDpi.x > 0); | |
786 base.debug.assert(desktopDpi.y > 0); | |
787 base.debug.assert(desktopScale > 0); | |
788 | |
789 // We have the following goals in sizing the desktop display at the client: | |
790 // 1. Avoid losing detail by down-scaling beyond 1:1 host:device pixels. | |
791 // 2. Avoid up-scaling if that will cause the client to need scrollbars. | |
792 // 3. Avoid introducing blurriness with non-integer up-scaling factors. | |
793 // 4. Avoid having huge "letterboxes" around the desktop, if it's really | |
794 // small. | |
795 // 5. Compensate for mismatched DPIs, so that the behaviour of features like | |
796 // shrink-to-fit matches their "natural" rather than their pixel size. | |
797 // e.g. with shrink-to-fit active a 1024x768 low-DPI host on a 640x480 | |
798 // high-DPI client will be up-scaled to 1280x960, rather than displayed | |
799 // at 1:1 host:physical client pixels. | |
800 // | |
801 // To determine the ideal size we follow a four-stage process: | |
802 // 1. Determine the "natural" size at which to display the desktop. | |
803 // a. Initially assume 1:1 mapping of desktop to client device pixels. | |
804 // b. If host DPI is less than the client's then up-scale accordingly. | |
805 // c. If desktopScale is configured for the host then allow that to | |
806 // reduce the amount of up-scaling from (b). e.g. if the client:host | |
807 // DPIs are 2:1 then a desktopScale of 1.5 would reduce the up-scale | |
808 // to 4:3, while a desktopScale of 3.0 would result in no up-scaling. | |
809 // 2. If the natural size of the desktop is smaller than the client device | |
810 // then apply up-scaling by an integer scale factor to avoid excessive | |
811 // letterboxing. | |
812 // 3. If shrink-to-fit is configured then: | |
813 // a. If the natural size exceeds the client size then apply down-scaling | |
814 // by an arbitrary scale factor. | |
815 // b. If we're in full-screen mode and the client & host aspect-ratios | |
816 // are radically different (e.g. the host is actually multi-monitor) | |
817 // then shrink-to-fit to the shorter dimension, rather than leaving | |
818 // huge letterboxes; the user can then bump-scroll around the desktop. | |
819 // 4. If the overall scale factor is fractionally over an integer factor | |
820 // then reduce it to that integer factor, to avoid blurring. | |
821 | |
822 // All calculations are performed in device pixels. | |
823 var clientWidth = clientSizeDips.width * clientPixelRatio; | |
824 var clientHeight = clientSizeDips.height * clientPixelRatio; | |
825 | |
826 // 1. Determine a "natural" size at which to display the desktop. | |
827 var scale = 1.0; | |
828 | |
829 // Determine the effective host device pixel ratio. | |
830 // Note that we round up or down to the closest integer pixel ratio. | |
831 var hostPixelRatioX = Math.round(desktopDpi.x / 96); | |
832 var hostPixelRatioY = Math.round(desktopDpi.y / 96); | |
833 var hostPixelRatio = Math.min(hostPixelRatioX, hostPixelRatioY); | |
834 | |
835 // Allow up-scaling to account for DPI. | |
836 scale = Math.max(scale, clientPixelRatio / hostPixelRatio); | |
837 | |
838 // Allow some or all of the up-scaling to be cancelled by the desktopScale. | |
839 if (desktopScale > 1.0) { | |
840 scale = Math.max(1.0, scale / desktopScale); | |
841 } | |
842 | |
843 // 2. If the host is still much smaller than the client, then up-scale to | |
844 // avoid wasting space, but only by an integer factor, to avoid blurring. | |
845 if (desktopSize.width * scale <= clientWidth && | |
846 desktopSize.height * scale <= clientHeight) { | |
847 var scaleX = Math.floor(clientWidth / desktopSize.width); | |
848 var scaleY = Math.floor(clientHeight / desktopSize.height); | |
849 scale = Math.min(scaleX, scaleY); | |
850 base.debug.assert(scale >= 1.0); | |
851 } | |
852 | |
853 // 3. Apply shrink-to-fit, if configured. | |
854 if (shrinkToFit) { | |
855 var scaleFitWidth = Math.min(scale, clientWidth / desktopSize.width); | |
856 var scaleFitHeight = Math.min(scale, clientHeight / desktopSize.height); | |
857 scale = Math.min(scaleFitHeight, scaleFitWidth); | |
858 | |
859 // If we're running full-screen then try to handle common side-by-side | |
860 // multi-monitor combinations more intelligently. | |
861 if (isFullscreen) { | |
862 // If the host has two monitors each the same size as the client then | |
863 // scale-to-fit will have the desktop occupy only 50% of the client area, | |
864 // in which case it would be preferable to down-scale less and let the | |
865 // user bump-scroll around ("scale-and-pan"). | |
866 // Triggering scale-and-pan if less than 65% of the client area would be | |
867 // used adds enough fuzz to cope with e.g. 1280x800 client connecting to | |
868 // a (2x1280)x1024 host nicely. | |
869 // Note that we don't need to account for scrollbars while fullscreen. | |
870 if (scale <= scaleFitHeight * 0.65) { | |
871 scale = scaleFitHeight; | |
872 } | |
873 if (scale <= scaleFitWidth * 0.65) { | |
874 scale = scaleFitWidth; | |
875 } | |
876 } | |
877 } | |
878 | |
879 // 4. Avoid blurring for close-to-integer up-scaling factors. | |
880 if (scale > 1.0) { | |
881 var scaleBlurriness = scale / Math.floor(scale); | |
882 if (scaleBlurriness < 1.1) { | |
883 scale = Math.floor(scale); | |
884 } | |
885 } | |
886 | |
887 // Return the necessary plugin dimensions in DIPs. | |
888 scale = scale / clientPixelRatio; | |
889 var pluginWidth = Math.round(desktopSize.width * scale); | |
890 var pluginHeight = Math.round(desktopSize.height * scale); | |
891 return { width: pluginWidth, height: pluginHeight }; | |
892 } | |
893 | |
894 /** | |
895 * Called when the window or desktop size or the scaling settings change, | |
896 * to set the scroll-bar visibility. | |
897 * | |
898 * TODO(jamiewalch): crbug.com/252796: Remove this once crbug.com/240772 is | |
899 * fixed. | |
900 */ | |
901 remoting.DesktopConnectedView.prototype.updateScrollbarVisibility = function() { | |
902 var scroller = document.getElementById('scroller'); | |
903 if (!scroller) { | |
904 return; | |
905 } | |
906 | |
907 var needsVerticalScroll = false; | |
908 var needsHorizontalScroll = false; | |
909 if (!this.shrinkToFit_) { | |
910 // Determine whether or not horizontal or vertical scrollbars are | |
911 // required, taking into account their width. | |
912 var clientArea = this.getClientArea_(); | |
913 needsVerticalScroll = clientArea.height < this.plugin_.getDesktopHeight(); | |
914 needsHorizontalScroll = clientArea.width < this.plugin_.getDesktopWidth(); | |
915 var kScrollBarWidth = 16; | |
916 if (needsHorizontalScroll && !needsVerticalScroll) { | |
917 needsVerticalScroll = | |
918 clientArea.height - kScrollBarWidth < this.plugin_.getDesktopHeight(); | |
919 } else if (!needsHorizontalScroll && needsVerticalScroll) { | |
920 needsHorizontalScroll = | |
921 clientArea.width - kScrollBarWidth < this.plugin_.getDesktopWidth(); | |
922 } | |
923 } | |
924 | |
925 if (needsHorizontalScroll) { | |
926 scroller.classList.remove('no-horizontal-scroll'); | |
927 } else { | |
928 scroller.classList.add('no-horizontal-scroll'); | |
929 } | |
930 if (needsVerticalScroll) { | |
931 scroller.classList.remove('no-vertical-scroll'); | |
932 } else { | |
933 scroller.classList.add('no-vertical-scroll'); | |
934 } | |
935 }; | |
936 | |
937 /** | |
938 * Sets and stores the key remapping setting for the current host. | 411 * Sets and stores the key remapping setting for the current host. |
939 * | 412 * |
940 * @param {string} remappings Comma separated list of key remappings. | 413 * @param {string} remappings Comma separated list of key remappings. |
941 */ | 414 */ |
942 remoting.DesktopConnectedView.prototype.setRemapKeys = function(remappings) { | 415 remoting.DesktopConnectedView.prototype.setRemapKeys = function(remappings) { |
943 // Cancel any existing remappings and apply the new ones. | 416 // Cancel any existing remappings and apply the new ones. |
944 this.applyRemapKeys_(false); | 417 this.applyRemapKeys_(false); |
945 this.remapKeys_ = remappings; | 418 this.remapKeys_ = remappings; |
946 this.applyRemapKeys_(true); | 419 this.applyRemapKeys_(true); |
947 | 420 |
948 // Save the new remapping setting. | 421 // Save the new remapping setting. |
949 var options = {}; | 422 this.host_.options().remapKeys = this.remapKeys_; |
950 options[remoting.DesktopConnectedView.KEY_REMAP_KEYS] = this.remapKeys_; | 423 this.host_.options().save(); |
951 remoting.HostSettings.save(this.hostId_, options); | |
952 }; | 424 }; |
953 | 425 |
954 /** | 426 /** |
955 * Applies the configured key remappings to the session, or resets them. | 427 * Applies the configured key remappings to the session, or resets them. |
956 * | 428 * |
957 * @param {boolean} apply True to apply remappings, false to cancel them. | 429 * @param {boolean} apply True to apply remappings, false to cancel them. |
958 */ | 430 */ |
959 remoting.DesktopConnectedView.prototype.applyRemapKeys_ = function(apply) { | 431 remoting.DesktopConnectedView.prototype.applyRemapKeys_ = function(apply) { |
960 var remapKeys = this.remapKeys_; | 432 var remapKeys = this.remapKeys_; |
961 if (remapKeys == '') { | 433 if (remapKeys == '') { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1088 * @param {Object} message The parsed extension message data. | 560 * @param {Object} message The parsed extension message data. |
1089 * @return {boolean} True if the message was recognized, false otherwise. | 561 * @return {boolean} True if the message was recognized, false otherwise. |
1090 */ | 562 */ |
1091 remoting.DesktopConnectedView.prototype.handleExtensionMessage = | 563 remoting.DesktopConnectedView.prototype.handleExtensionMessage = |
1092 function(type, message) { | 564 function(type, message) { |
1093 if (this.videoFrameRecorder_) { | 565 if (this.videoFrameRecorder_) { |
1094 return this.videoFrameRecorder_.handleMessage(type, message); | 566 return this.videoFrameRecorder_.handleMessage(type, message); |
1095 } | 567 } |
1096 return false; | 568 return false; |
1097 }; | 569 }; |
OLD | NEW |