Make power API generic

Decouple it from XVP and make it a generic API.
This commit is contained in:
Pierre Ossman 2017-10-13 14:25:26 +02:00
parent 85b35fc0cc
commit cd523e8f28
7 changed files with 101 additions and 101 deletions

View File

@ -591,17 +591,17 @@ select:active {
padding: 0 10px; padding: 0 10px;
} }
/* XVP Shutdown/Reboot */ /* Shutdown/Reboot */
:root:not(.noVNC_connected) #noVNC_xvp_button { :root:not(.noVNC_connected) #noVNC_power_button {
display: none; display: none;
} }
#noVNC_xvp { #noVNC_power {
} }
#noVNC_xvp_buttons { #noVNC_power_buttons {
display: none; display: none;
} }
#noVNC_xvp input[type=button] { #noVNC_power input[type=button] {
width: 100%; width: 100%;
} }

View File

@ -91,7 +91,7 @@ var UI = {
UI.addControlbarHandlers(); UI.addControlbarHandlers();
UI.addTouchSpecificHandlers(); UI.addTouchSpecificHandlers();
UI.addExtraKeysHandlers(); UI.addExtraKeysHandlers();
UI.addXvpHandlers(); UI.addMachineHandlers();
UI.addConnectionControlHandlers(); UI.addConnectionControlHandlers();
UI.addClipboardHandlers(); UI.addClipboardHandlers();
UI.addSettingsHandlers(); UI.addSettingsHandlers();
@ -207,7 +207,7 @@ var UI = {
'onUpdateState': UI.updateState, 'onUpdateState': UI.updateState,
'onDisconnected': UI.disconnectFinished, 'onDisconnected': UI.disconnectFinished,
'onCredentialsRequired': UI.credentials, 'onCredentialsRequired': UI.credentials,
'onXvpInit': UI.updateXvpButton, 'onCapabilities': UI.updatePowerButton,
'onClipboard': UI.clipboardReceive, 'onClipboard': UI.clipboardReceive,
'onBell': UI.bell, 'onBell': UI.bell,
'onFBUComplete': UI.initialResize, 'onFBUComplete': UI.initialResize,
@ -332,15 +332,15 @@ var UI = {
.addEventListener('click', UI.sendCtrlAltDel); .addEventListener('click', UI.sendCtrlAltDel);
}, },
addXvpHandlers: function() { addMachineHandlers: function() {
document.getElementById("noVNC_xvp_shutdown_button") document.getElementById("noVNC_shutdown_button")
.addEventListener('click', function() { UI.rfb.xvpShutdown(); }); .addEventListener('click', function() { UI.rfb.machineShutdown(); });
document.getElementById("noVNC_xvp_reboot_button") document.getElementById("noVNC_reboot_button")
.addEventListener('click', function() { UI.rfb.xvpReboot(); }); .addEventListener('click', function() { UI.rfb.machineReboot(); });
document.getElementById("noVNC_xvp_reset_button") document.getElementById("noVNC_reset_button")
.addEventListener('click', function() { UI.rfb.xvpReset(); }); .addEventListener('click', function() { UI.rfb.machineReset(); });
document.getElementById("noVNC_xvp_button") document.getElementById("noVNC_power_button")
.addEventListener('click', UI.toggleXvpPanel); .addEventListener('click', UI.togglePowerPanel);
}, },
addConnectionControlHandlers: function() { addConnectionControlHandlers: function() {
@ -489,7 +489,7 @@ var UI = {
UI.enableSetting('port'); UI.enableSetting('port');
UI.enableSetting('path'); UI.enableSetting('path');
UI.enableSetting('repeaterID'); UI.enableSetting('repeaterID');
UI.updateXvpButton(0); UI.updatePowerButton();
UI.keepControlbar(); UI.keepControlbar();
} }
@ -868,7 +868,7 @@ var UI = {
closeAllPanels: function() { closeAllPanels: function() {
UI.closeSettingsPanel(); UI.closeSettingsPanel();
UI.closeXvpPanel(); UI.closePowerPanel();
UI.closeClipboardPanel(); UI.closeClipboardPanel();
UI.closeExtraKeys(); UI.closeExtraKeys();
}, },
@ -926,50 +926,52 @@ var UI = {
/* ------^------- /* ------^-------
* /SETTINGS * /SETTINGS
* ============== * ==============
* XVP * POWER
* ------v------*/ * ------v------*/
openXvpPanel: function() { openPowerPanel: function() {
UI.closeAllPanels(); UI.closeAllPanels();
UI.openControlbar(); UI.openControlbar();
document.getElementById('noVNC_xvp') document.getElementById('noVNC_power')
.classList.add("noVNC_open"); .classList.add("noVNC_open");
document.getElementById('noVNC_xvp_button') document.getElementById('noVNC_power_button')
.classList.add("noVNC_selected"); .classList.add("noVNC_selected");
}, },
closeXvpPanel: function() { closePowerPanel: function() {
document.getElementById('noVNC_xvp') document.getElementById('noVNC_power')
.classList.remove("noVNC_open"); .classList.remove("noVNC_open");
document.getElementById('noVNC_xvp_button') document.getElementById('noVNC_power_button')
.classList.remove("noVNC_selected"); .classList.remove("noVNC_selected");
}, },
toggleXvpPanel: function() { togglePowerPanel: function() {
if (document.getElementById('noVNC_xvp') if (document.getElementById('noVNC_power')
.classList.contains("noVNC_open")) { .classList.contains("noVNC_open")) {
UI.closeXvpPanel(); UI.closePowerPanel();
} else { } else {
UI.openXvpPanel(); UI.openPowerPanel();
} }
}, },
// Disable/enable XVP button // Disable/enable power button
updateXvpButton: function(ver) { updatePowerButton: function() {
if (ver >= 1 && !UI.rfb.get_view_only()) { if (UI.connected &&
document.getElementById('noVNC_xvp_button') UI.rfb.get_capabilities().power &&
!UI.rfb.get_view_only()) {
document.getElementById('noVNC_power_button')
.classList.remove("noVNC_hidden"); .classList.remove("noVNC_hidden");
} else { } else {
document.getElementById('noVNC_xvp_button') document.getElementById('noVNC_power_button')
.classList.add("noVNC_hidden"); .classList.add("noVNC_hidden");
// Close XVP panel if open // Close power panel if open
UI.closeXvpPanel(); UI.closePowerPanel();
} }
}, },
/* ------^------- /* ------^-------
* /XVP * /POWER
* ============== * ==============
* CLIPBOARD * CLIPBOARD
* ------v------*/ * ------v------*/

View File

@ -49,6 +49,8 @@ export default function RFB(defaults) {
this._rfb_tightvnc = false; this._rfb_tightvnc = false;
this._rfb_xvp_ver = 0; this._rfb_xvp_ver = 0;
this._capabilities = { power: false };
this._encHandlers = {}; this._encHandlers = {};
this._encStats = {}; this._encStats = {};
@ -140,7 +142,7 @@ export default function RFB(defaults) {
'onFBUComplete': function () { }, // onFBUComplete(rfb): RFB FBU received and processed 'onFBUComplete': function () { }, // onFBUComplete(rfb): RFB FBU received and processed
'onFBResize': function () { }, // onFBResize(rfb, width, height): frame buffer resized 'onFBResize': function () { }, // onFBResize(rfb, width, height): frame buffer resized
'onDesktopName': function () { }, // onDesktopName(rfb, name): desktop name received 'onDesktopName': function () { }, // onDesktopName(rfb, name): desktop name received
'onXvpInit': function () { } // onXvpInit(version): XVP extensions active for this connection 'onCapabilities': function () { } // onCapabilities(rfb, caps): the supported capabilities has changed
}); });
// main setup // main setup
@ -282,23 +284,16 @@ RFB.prototype = {
return true; return true;
}, },
xvpOp: function (ver, op) { machineShutdown: function () {
if (this._rfb_xvp_ver < ver) { return false; } this._xvpOp(1, 2);
Log.Info("Sending XVP operation " + op + " (version " + ver + ")");
RFB.messages.xvpOp(this._sock, ver, op);
return true;
}, },
xvpShutdown: function () { machineReboot: function () {
return this.xvpOp(1, 2); this._xvpOp(1, 3);
}, },
xvpReboot: function () { machineReset: function () {
return this.xvpOp(1, 3); this._xvpOp(1, 4);
},
xvpReset: function () {
return this.xvpOp(1, 4);
}, },
// Send a key press. If 'down' is not specified then send a down key // Send a key press. If 'down' is not specified then send a down key
@ -1282,7 +1277,8 @@ RFB.prototype = {
case 1: // XVP_INIT case 1: // XVP_INIT
this._rfb_xvp_ver = xvp_ver; this._rfb_xvp_ver = xvp_ver;
Log.Info("XVP extensions enabled (version " + this._rfb_xvp_ver + ")"); Log.Info("XVP extensions enabled (version " + this._rfb_xvp_ver + ")");
this._onXvpInit(this._rfb_xvp_ver); this._capabilities.power = true;
this._onCapabilities(this, this._capabilities)
break; break;
default: default:
this._fail("Unexpected server message", this._fail("Unexpected server message",
@ -1480,7 +1476,13 @@ RFB.prototype = {
this._timing.fbu_rt_start = (new Date()).getTime(); this._timing.fbu_rt_start = (new Date()).getTime();
this._updateContinuousUpdates(); this._updateContinuousUpdates();
} },
_xvpOp: function (ver, op) {
if (this._rfb_xvp_ver < ver) { return; }
Log.Info("Sending XVP operation " + op + " (version " + ver + ")");
RFB.messages.xvpOp(this._sock, ver, op);
},
}; };
make_properties(RFB, [ make_properties(RFB, [
@ -1496,6 +1498,7 @@ make_properties(RFB, [
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection ['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to ['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to
['viewportDrag', 'rw', 'bool'], // Move the viewport on mouse drags ['viewportDrag', 'rw', 'bool'], // Move the viewport on mouse drags
['capabilities', 'ro', 'arr'], // Supported capabilities
// Callback functions // Callback functions
['onUpdateState', 'rw', 'func'], // onUpdateState(rfb, state, oldstate): connection state change ['onUpdateState', 'rw', 'func'], // onUpdateState(rfb, state, oldstate): connection state change
@ -1508,7 +1511,7 @@ make_properties(RFB, [
['onFBUComplete', 'rw', 'func'], // onFBUComplete(rfb, fbu): RFB FBU received and processed ['onFBUComplete', 'rw', 'func'], // onFBUComplete(rfb, fbu): RFB FBU received and processed
['onFBResize', 'rw', 'func'], // onFBResize(rfb, width, height): frame buffer resized ['onFBResize', 'rw', 'func'], // onFBResize(rfb, width, height): frame buffer resized
['onDesktopName', 'rw', 'func'], // onDesktopName(rfb, name): desktop name received ['onDesktopName', 'rw', 'func'], // onDesktopName(rfb, name): desktop name received
['onXvpInit', 'rw', 'func'] // onXvpInit(version): XVP extensions active for this connection ['onCapabilities', 'rw', 'func'] // onCapabilities(rfb, caps): the supported capabilities has changed
]); ]);
RFB.prototype.set_local_cursor = function (cursor) { RFB.prototype.set_local_cursor = function (cursor) {

View File

@ -41,6 +41,7 @@ attribute mode is one of the following:
| wsProtocols | arr | RW | ['binary'] | Protocols to use in the WebSocket connection | wsProtocols | arr | RW | ['binary'] | Protocols to use in the WebSocket connection
| repeaterID | str | RW | '' | UltraVNC RepeaterID to connect to | repeaterID | str | RW | '' | UltraVNC RepeaterID to connect to
| viewportDrag | bool | RW | false | Move the viewport on mouse drags | viewportDrag | bool | RW | false | Move the viewport on mouse drags
| capabilities | arr | RO | [] | Supported capabilities (can include: 'power')
## 2 Methods ## 2 Methods
@ -55,10 +56,9 @@ object instance.
| disconnect | () | Disconnect | disconnect | () | Disconnect
| sendCredentials | (credentials) | Send credentials after onCredentialsRequired callback | sendCredentials | (credentials) | Send credentials after onCredentialsRequired callback
| sendCtrlAltDel | () | Send Ctrl-Alt-Del key sequence | sendCtrlAltDel | () | Send Ctrl-Alt-Del key sequence
| xvpOp | (ver, op) | Send a XVP operation (2=shutdown, 3=reboot, 4=reset) | machineShutdown | () | Request a shutdown of the remote machine.
| xvpShutdown | () | Send XVP shutdown. | machineReboot | () | Request a reboot of the remote machine.
| xvpReboot | () | Send XVP reboot. | machineReset | () | Request a reset of the remote machine.
| xvpReset | () | Send XVP reset.
| sendKey | (keysym, code, down) | Send a key press event. If down not specified, send a down and up event. | sendKey | (keysym, code, down) | Send a key press event. If down not specified, send a down and up event.
| clipboardPasteFrom | (text) | Send a clipboard paste event | clipboardPasteFrom | (text) | Send a clipboard paste event
| autoscale | (width, height, downscaleOnly) | Scale the display | autoscale | (width, height, downscaleOnly) | Scale the display
@ -84,7 +84,7 @@ functions.
| onFBUComplete | (rfb, fbu) | RFB FBU received and processed (see details below) | onFBUComplete | (rfb, fbu) | RFB FBU received and processed (see details below)
| onFBResize | (rfb, width, height) | Frame buffer (remote desktop) size changed | onFBResize | (rfb, width, height) | Frame buffer (remote desktop) size changed
| onDesktopName | (rfb, name) | VNC desktop name recieved | onDesktopName | (rfb, name) | VNC desktop name recieved
| onXvpInit | (version) | XVP extensions active for this connection. | onCapabilities | (rfb, capabilities) | The supported capabilities has changed
__RFB onUpdateState callback details__ __RFB onUpdateState callback details__

View File

@ -300,28 +300,23 @@ describe('Remote Frame Buffer Protocol Client', function() {
client._rfb_xvp_ver = 1; client._rfb_xvp_ver = 1;
}); });
it('should send the shutdown signal on #xvpShutdown', function () { it('should send the shutdown signal on #machineShutdown', function () {
client.xvpShutdown(); client.machineShutdown();
expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x02])); expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x02]));
}); });
it('should send the reboot signal on #xvpReboot', function () { it('should send the reboot signal on #machineReboot', function () {
client.xvpReboot(); client.machineReboot();
expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x03])); expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x03]));
}); });
it('should send the reset signal on #xvpReset', function () { it('should send the reset signal on #machineReset', function () {
client.xvpReset(); client.machineReset();
expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x04])); expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x04]));
}); });
it('should support sending arbitrary XVP operations via #xvpOp', function () {
client.xvpOp(1, 7);
expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x07]));
});
it('should not send XVP operations with higher versions than we support', function () { it('should not send XVP operations with higher versions than we support', function () {
expect(client.xvpOp(2, 7)).to.be.false; client._xvpOp(2, 7);
expect(client._sock.flush).to.not.have.been.called; expect(client._sock.flush).to.not.have.been.called;
}); });
}); });
@ -1800,11 +1795,11 @@ describe('Remote Frame Buffer Protocol Client', function() {
}); });
it('should set the XVP version and fire the callback with the version on XVP_INIT', function () { it('should set the XVP version and fire the callback with the version on XVP_INIT', function () {
client.set_onXvpInit(sinon.spy()); client.set_onCapabilities(sinon.spy());
client._sock._websocket._receive_data(new Uint8Array([250, 0, 10, 1])); client._sock._websocket._receive_data(new Uint8Array([250, 0, 10, 1]));
expect(client._rfb_xvp_ver).to.equal(10); expect(client._rfb_xvp_ver).to.equal(10);
expect(client.get_onXvpInit()).to.have.been.calledOnce; expect(client.get_onCapabilities()).to.have.been.calledOnce;
expect(client.get_onXvpInit()).to.have.been.calledWith(10); expect(client.get_onCapabilities()).to.have.been.calledWith(client, { power: true });
}); });
it('should fail on unknown XVP message types', function () { it('should fail on unknown XVP message types', function () {

View File

@ -152,18 +152,18 @@
</div> </div>
</div> </div>
<!-- XVP Shutdown/Reboot --> <!-- Shutdown/Reboot -->
<input type="image" alt="Shutdown/Reboot" src="app/images/power.svg" <input type="image" alt="Shutdown/Reboot" src="app/images/power.svg"
id="noVNC_xvp_button" class="noVNC_button" id="noVNC_power_button" class="noVNC_button"
title="Shutdown/Reboot..." /> title="Shutdown/Reboot..." />
<div class="noVNC_vcenter"> <div class="noVNC_vcenter">
<div id="noVNC_xvp" class="noVNC_panel"> <div id="noVNC_power" class="noVNC_panel">
<div class="noVNC_heading"> <div class="noVNC_heading">
<img src="app/images/power.svg"> Power <img src="app/images/power.svg"> Power
</div> </div>
<input type="button" id="noVNC_xvp_shutdown_button" value="Shutdown" /> <input type="button" id="noVNC_shutdown_button" value="Shutdown" />
<input type="button" id="noVNC_xvp_reboot_button" value="Reboot" /> <input type="button" id="noVNC_reboot_button" value="Reboot" />
<input type="button" id="noVNC_xvp_reset_button" value="Reset" /> <input type="button" id="noVNC_reset_button" value="Reset" />
</div> </div>
</div> </div>

View File

@ -122,16 +122,16 @@
rfb.sendCtrlAltDel(); rfb.sendCtrlAltDel();
return false; return false;
} }
function xvpShutdown() { function machineShutdown() {
rfb.xvpShutdown(); rfb.machineShutdown();
return false; return false;
} }
function xvpReboot() { function machineReboot() {
rfb.xvpReboot(); rfb.machineReboot();
return false; return false;
} }
function xvpReset() { function machineReset() {
rfb.xvpReset(); rfb.machineReset();
return false; return false;
} }
function status(text, level) { function status(text, level) {
@ -176,7 +176,7 @@
cad.disabled = false; cad.disabled = false;
} else { } else {
cad.disabled = true; cad.disabled = true;
xvpInit(0); updatePowerButtons();
} }
} }
@ -199,21 +199,21 @@
}, 500); }, 500);
}; };
function xvpInit(ver) { function updatePowerButtons() {
var xvpbuttons; var powerbuttons;
xvpbuttons = document.getElementById('noVNC_xvp_buttons'); powerbuttons = document.getElementById('noVNC_power_buttons');
if (ver >= 1) { if (rfb.get_capabilities().power) {
xvpbuttons.style.display = 'inline'; powerbuttons.style.display = 'inline';
} else { } else {
xvpbuttons.style.display = 'none'; powerbuttons.style.display = 'none';
} }
} }
document.getElementById('sendCtrlAltDelButton').style.display = "inline"; document.getElementById('sendCtrlAltDelButton').style.display = "inline";
document.getElementById('sendCtrlAltDelButton').onclick = sendCtrlAltDel; document.getElementById('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
document.getElementById('xvpShutdownButton').onclick = xvpShutdown; document.getElementById('machineShutdownButton').onclick = machineShutdown;
document.getElementById('xvpRebootButton').onclick = xvpReboot; document.getElementById('machineRebootButton').onclick = machineReboot;
document.getElementById('xvpResetButton').onclick = xvpReset; document.getElementById('machineResetButton').onclick = machineReset;
WebUtil.init_logging(WebUtil.getConfigVar('logging', 'warn')); WebUtil.init_logging(WebUtil.getConfigVar('logging', 'warn'));
document.title = WebUtil.getConfigVar('title', 'noVNC'); document.title = WebUtil.getConfigVar('title', 'noVNC');
@ -262,7 +262,7 @@
'onNotification': notification, 'onNotification': notification,
'onUpdateState': updateState, 'onUpdateState': updateState,
'onDisconnected': disconnected, 'onDisconnected': disconnected,
'onXvpInit': xvpInit, 'onCapabilities': updatePowerButtons,
'onCredentialsRequired': credentials, 'onCredentialsRequired': credentials,
'onFBUComplete': FBUComplete, 'onFBUComplete': FBUComplete,
'onDesktopName': updateDesktopName}); 'onDesktopName': updateDesktopName});
@ -286,13 +286,13 @@
<td width="1%"><div id="noVNC_buttons"> <td width="1%"><div id="noVNC_buttons">
<input type=button value="Send CtrlAltDel" <input type=button value="Send CtrlAltDel"
id="sendCtrlAltDelButton"> id="sendCtrlAltDelButton">
<span id="noVNC_xvp_buttons"> <span id="noVNC_power_buttons">
<input type=button value="Shutdown" <input type=button value="Shutdown"
id="xvpShutdownButton"> id="machineShutdownButton">
<input type=button value="Reboot" <input type=button value="Reboot"
id="xvpRebootButton"> id="machineRebootButton">
<input type=button value="Reset" <input type=button value="Reset"
id="xvpResetButton"> id="machineResetButton">
</span> </span>
</div></td> </div></td>
</tr></table> </tr></table>