OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * @fileoverview | |
7 * Implements a basic UX control for a connected remoting session. | |
8 */ | |
9 | |
10 /** @suppress {duplicate} */ | |
11 var remoting = remoting || {}; | |
12 | |
13 (function() { | |
14 | |
15 'use strict'; | |
16 | |
17 /** | |
18 * @param {remoting.ClientPlugin} plugin | |
19 * @param {HTMLElement} viewportElement | |
20 * @param {HTMLElement} cursorElement | |
21 * | |
22 * @constructor | |
23 * @implements {base.Disposable} | |
24 */ | |
25 remoting.ConnectedView = function(plugin, viewportElement, cursorElement) { | |
26 /** @private */ | |
27 this.viewportElement_ = viewportElement; | |
28 | |
29 /** @private */ | |
30 this.plugin_ = plugin; | |
31 | |
32 /** private */ | |
33 this.cursor_ = new remoting.ConnectedView.Cursor( | |
34 plugin, viewportElement, cursorElement); | |
35 | |
36 /** @private {Element} */ | |
37 this.debugRegionContainer_ = | |
38 viewportElement.querySelector('.debug-region-container'); | |
39 | |
40 var pluginElement = plugin.element(); | |
41 | |
42 /** private */ | |
43 this.disposables_ = new base.Disposables( | |
44 this.cursor_, | |
45 new base.DomEventHook(pluginElement, 'blur', | |
46 this.onPluginLostFocus_.bind(this), false), | |
47 new base.DomEventHook(document, 'visibilitychange', | |
48 this.onVisibilityChanged_.bind(this), false), | |
49 new remoting.Clipboard(plugin) | |
50 ); | |
51 | |
52 // TODO(wez): Only allow mouse lock if the app has the pointerLock permission. | |
53 // Enable automatic mouse-lock. | |
54 if (this.plugin_.hasFeature(remoting.ClientPlugin.Feature.ALLOW_MOUSE_LOCK)) { | |
55 this.plugin_.allowMouseLock(); | |
56 } | |
57 | |
58 pluginElement.focus(); | |
59 }; | |
60 | |
61 /** | |
62 * @return {void} Nothing. | |
63 */ | |
64 remoting.ConnectedView.prototype.dispose = function() { | |
65 base.dispose(this.disposables_); | |
66 this.disposables_ = null; | |
67 this.cursorRender_ = null; | |
68 this.plugin_ = null; | |
69 }; | |
70 | |
71 /** | |
72 * Called when the app window is hidden. | |
73 * @return {void} Nothing. | |
74 * @private | |
75 */ | |
76 remoting.ConnectedView.prototype.onVisibilityChanged_ = function() { | |
77 var pause = document.hidden; | |
78 this.plugin_.pauseVideo(pause); | |
79 this.plugin_.pauseAudio(pause); | |
80 }; | |
81 | |
82 /** | |
83 * Callback that the plugin invokes to indicate when the connection is | |
84 * ready. | |
85 * | |
86 * @param {boolean} ready True if the connection is ready. | |
87 */ | |
88 remoting.ConnectedView.prototype.onConnectionReady = function(ready) { | |
89 this.viewportElement_.classList.toggle('session-client-inactive', !ready); | |
90 }; | |
91 | |
92 /** | |
93 * Callback function called when the plugin element loses focus. | |
94 * @private | |
95 */ | |
96 remoting.ConnectedView.prototype.onPluginLostFocus_ = function() { | |
97 // Release all keys to prevent them becoming 'stuck down' on the host. | |
98 this.plugin_.releaseAllKeys(); | |
99 | |
100 // Focus should stay on the element, not (for example) the toolbar. | |
101 // Due to crbug.com/246335, we can't restore the focus immediately, | |
102 // otherwise the plugin gets confused about whether or not it has focus. | |
103 window.setTimeout( | |
104 this.plugin_.element().focus.bind(this.plugin_.element()), 0); | |
105 }; | |
106 | |
107 /** | |
108 * Handles dirty region debug messages. | |
109 * | |
110 * @param {{rects:Array<Array<number>>}} region Dirty region of the latest | |
111 * frame. | |
112 */ | |
113 remoting.ConnectedView.prototype.handleDebugRegion = function(region) { | |
114 while (this.debugRegionContainer_.firstChild) { | |
115 this.debugRegionContainer_.removeChild( | |
116 this.debugRegionContainer_.firstChild); | |
117 } | |
118 if (region.rects) { | |
119 var rects = region.rects; | |
120 for (var i = 0; i < rects.length; ++i) { | |
121 var rect = document.createElement('div'); | |
122 rect.classList.add('debug-region-rect'); | |
123 rect.style.left = rects[i][0] + 'px'; | |
124 rect.style.top = rects[i][1] +'px'; | |
125 rect.style.width = rects[i][2] +'px'; | |
126 rect.style.height = rects[i][3] + 'px'; | |
127 this.debugRegionContainer_.appendChild(rect); | |
128 } | |
129 } | |
130 }; | |
131 | |
132 /** | |
133 * Enables or disables rendering of dirty regions for debugging. | |
134 * @param {boolean} enable True to enable rendering. | |
135 */ | |
136 remoting.ConnectedView.prototype.enableDebugRegion = function(enable) { | |
137 if (enable) { | |
138 this.plugin_.setDebugDirtyRegionHandler(this.handleDebugRegion.bind(this)); | |
139 } else { | |
140 this.plugin_.setDebugDirtyRegionHandler(null); | |
141 } | |
142 }; | |
143 | |
144 /** | |
145 * @param {remoting.ClientPlugin} plugin | |
146 * @param {HTMLElement} viewportElement | |
147 * @param {HTMLElement} cursorElement | |
148 * | |
149 * @constructor | |
150 * @implements {base.Disposable} | |
151 */ | |
152 remoting.ConnectedView.Cursor = function( | |
153 plugin, viewportElement, cursorElement) { | |
154 /** @private */ | |
155 this.plugin_ = plugin; | |
156 /** @private */ | |
157 this.cursorElement_ = cursorElement; | |
158 /** @private */ | |
159 this.eventHook_ = new base.DomEventHook( | |
160 viewportElement, 'mousemove', this.onMouseMoved_.bind(this), true); | |
161 | |
162 this.plugin_.setMouseCursorHandler(this.onCursorChanged_.bind(this)); | |
163 }; | |
164 | |
165 remoting.ConnectedView.Cursor.prototype.dispose = function() { | |
166 base.dispose(this.eventHook_); | |
167 this.eventHook_ = null; | |
168 this.plugin_.setMouseCursorHandler( | |
169 /** function(string, string, number) */ base.doNothing); | |
170 this.plugin_ = null; | |
171 }; | |
172 | |
173 /** | |
174 * @param {string} url | |
175 * @param {number} hotspotX | |
176 * @param {number} hotspotY | |
177 * @private | |
178 */ | |
179 remoting.ConnectedView.Cursor.prototype.onCursorChanged_ = function( | |
180 url, hotspotX, hotspotY) { | |
181 this.cursorElement_.hidden = !url; | |
182 if (url) { | |
183 this.cursorElement_.style.marginLeft = '-' + hotspotX + 'px'; | |
184 this.cursorElement_.style.marginTop = '-' + hotspotY + 'px'; | |
185 this.cursorElement_.src = url; | |
186 } | |
187 }; | |
188 | |
189 /** | |
190 * @param {Event} event | |
191 * @private | |
192 */ | |
193 remoting.ConnectedView.Cursor.prototype.onMouseMoved_ = function(event) { | |
194 this.cursorElement_.style.top = event.offsetY + 'px'; | |
195 this.cursorElement_.style.left = event.offsetX + 'px'; | |
196 }; | |
197 | |
198 })(); | |
OLD | NEW |