diff --git a/app/styles/base.css b/app/styles/base.css index 790837a0..b8ce81bd 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -591,17 +591,17 @@ select:active { padding: 0 10px; } -/* XVP Shutdown/Reboot */ -:root:not(.noVNC_connected) #noVNC_xvp_button { +/* Shutdown/Reboot */ +:root:not(.noVNC_connected) #noVNC_power_button { display: none; } -#noVNC_xvp { +#noVNC_power { } -#noVNC_xvp_buttons { +#noVNC_power_buttons { display: none; } -#noVNC_xvp input[type=button] { +#noVNC_power input[type=button] { width: 100%; } diff --git a/app/ui.js b/app/ui.js index 6e08172a..6f1690ec 100644 --- a/app/ui.js +++ b/app/ui.js @@ -91,7 +91,7 @@ var UI = { UI.addControlbarHandlers(); UI.addTouchSpecificHandlers(); UI.addExtraKeysHandlers(); - UI.addXvpHandlers(); + UI.addMachineHandlers(); UI.addConnectionControlHandlers(); UI.addClipboardHandlers(); UI.addSettingsHandlers(); @@ -207,7 +207,7 @@ var UI = { 'onUpdateState': UI.updateState, 'onDisconnected': UI.disconnectFinished, 'onCredentialsRequired': UI.credentials, - 'onXvpInit': UI.updateXvpButton, + 'onCapabilities': UI.updatePowerButton, 'onClipboard': UI.clipboardReceive, 'onBell': UI.bell, 'onFBUComplete': UI.initialResize, @@ -332,15 +332,15 @@ var UI = { .addEventListener('click', UI.sendCtrlAltDel); }, - addXvpHandlers: function() { - document.getElementById("noVNC_xvp_shutdown_button") - .addEventListener('click', function() { UI.rfb.xvpShutdown(); }); - document.getElementById("noVNC_xvp_reboot_button") - .addEventListener('click', function() { UI.rfb.xvpReboot(); }); - document.getElementById("noVNC_xvp_reset_button") - .addEventListener('click', function() { UI.rfb.xvpReset(); }); - document.getElementById("noVNC_xvp_button") - .addEventListener('click', UI.toggleXvpPanel); + addMachineHandlers: function() { + document.getElementById("noVNC_shutdown_button") + .addEventListener('click', function() { UI.rfb.machineShutdown(); }); + document.getElementById("noVNC_reboot_button") + .addEventListener('click', function() { UI.rfb.machineReboot(); }); + document.getElementById("noVNC_reset_button") + .addEventListener('click', function() { UI.rfb.machineReset(); }); + document.getElementById("noVNC_power_button") + .addEventListener('click', UI.togglePowerPanel); }, addConnectionControlHandlers: function() { @@ -489,7 +489,7 @@ var UI = { UI.enableSetting('port'); UI.enableSetting('path'); UI.enableSetting('repeaterID'); - UI.updateXvpButton(0); + UI.updatePowerButton(); UI.keepControlbar(); } @@ -868,7 +868,7 @@ var UI = { closeAllPanels: function() { UI.closeSettingsPanel(); - UI.closeXvpPanel(); + UI.closePowerPanel(); UI.closeClipboardPanel(); UI.closeExtraKeys(); }, @@ -926,50 +926,52 @@ var UI = { /* ------^------- * /SETTINGS * ============== - * XVP + * POWER * ------v------*/ - openXvpPanel: function() { + openPowerPanel: function() { UI.closeAllPanels(); UI.openControlbar(); - document.getElementById('noVNC_xvp') + document.getElementById('noVNC_power') .classList.add("noVNC_open"); - document.getElementById('noVNC_xvp_button') + document.getElementById('noVNC_power_button') .classList.add("noVNC_selected"); }, - closeXvpPanel: function() { - document.getElementById('noVNC_xvp') + closePowerPanel: function() { + document.getElementById('noVNC_power') .classList.remove("noVNC_open"); - document.getElementById('noVNC_xvp_button') + document.getElementById('noVNC_power_button') .classList.remove("noVNC_selected"); }, - toggleXvpPanel: function() { - if (document.getElementById('noVNC_xvp') + togglePowerPanel: function() { + if (document.getElementById('noVNC_power') .classList.contains("noVNC_open")) { - UI.closeXvpPanel(); + UI.closePowerPanel(); } else { - UI.openXvpPanel(); + UI.openPowerPanel(); } }, - // Disable/enable XVP button - updateXvpButton: function(ver) { - if (ver >= 1 && !UI.rfb.get_view_only()) { - document.getElementById('noVNC_xvp_button') + // Disable/enable power button + updatePowerButton: function() { + if (UI.connected && + UI.rfb.get_capabilities().power && + !UI.rfb.get_view_only()) { + document.getElementById('noVNC_power_button') .classList.remove("noVNC_hidden"); } else { - document.getElementById('noVNC_xvp_button') + document.getElementById('noVNC_power_button') .classList.add("noVNC_hidden"); - // Close XVP panel if open - UI.closeXvpPanel(); + // Close power panel if open + UI.closePowerPanel(); } }, /* ------^------- - * /XVP + * /POWER * ============== * CLIPBOARD * ------v------*/ diff --git a/core/rfb.js b/core/rfb.js index 18380e7e..5b66abb4 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -49,6 +49,8 @@ export default function RFB(defaults) { this._rfb_tightvnc = false; this._rfb_xvp_ver = 0; + this._capabilities = { power: false }; + this._encHandlers = {}; this._encStats = {}; @@ -140,7 +142,7 @@ export default function RFB(defaults) { 'onFBUComplete': function () { }, // onFBUComplete(rfb): RFB FBU received and processed 'onFBResize': function () { }, // onFBResize(rfb, width, height): frame buffer resized '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 @@ -282,23 +284,16 @@ RFB.prototype = { return true; }, - xvpOp: function (ver, op) { - if (this._rfb_xvp_ver < ver) { return false; } - Log.Info("Sending XVP operation " + op + " (version " + ver + ")"); - RFB.messages.xvpOp(this._sock, ver, op); - return true; + machineShutdown: function () { + this._xvpOp(1, 2); }, - xvpShutdown: function () { - return this.xvpOp(1, 2); + machineReboot: function () { + this._xvpOp(1, 3); }, - xvpReboot: function () { - return this.xvpOp(1, 3); - }, - - xvpReset: function () { - return this.xvpOp(1, 4); + machineReset: function () { + this._xvpOp(1, 4); }, // Send a key press. If 'down' is not specified then send a down key @@ -1282,7 +1277,8 @@ RFB.prototype = { case 1: // XVP_INIT this._rfb_xvp_ver = 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; default: this._fail("Unexpected server message", @@ -1480,7 +1476,13 @@ RFB.prototype = { this._timing.fbu_rt_start = (new Date()).getTime(); 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, [ @@ -1496,6 +1498,7 @@ make_properties(RFB, [ ['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection ['repeaterID', 'rw', 'str'], // [UltraVNC] RepeaterID to connect to ['viewportDrag', 'rw', 'bool'], // Move the viewport on mouse drags + ['capabilities', 'ro', 'arr'], // Supported capabilities // Callback functions ['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 ['onFBResize', 'rw', 'func'], // onFBResize(rfb, width, height): frame buffer resized ['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) { diff --git a/docs/API.md b/docs/API.md index 9052daaf..92222e67 100644 --- a/docs/API.md +++ b/docs/API.md @@ -41,6 +41,7 @@ attribute mode is one of the following: | wsProtocols | arr | RW | ['binary'] | Protocols to use in the WebSocket connection | repeaterID | str | RW | '' | UltraVNC RepeaterID to connect to | viewportDrag | bool | RW | false | Move the viewport on mouse drags +| capabilities | arr | RO | [] | Supported capabilities (can include: 'power') ## 2 Methods @@ -55,10 +56,9 @@ object instance. | disconnect | () | Disconnect | sendCredentials | (credentials) | Send credentials after onCredentialsRequired callback | sendCtrlAltDel | () | Send Ctrl-Alt-Del key sequence -| xvpOp | (ver, op) | Send a XVP operation (2=shutdown, 3=reboot, 4=reset) -| xvpShutdown | () | Send XVP shutdown. -| xvpReboot | () | Send XVP reboot. -| xvpReset | () | Send XVP reset. +| machineShutdown | () | Request a shutdown of the remote machine. +| machineReboot | () | Request a reboot of the remote machine. +| machineReset | () | Request a reset of the remote machine. | 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 | autoscale | (width, height, downscaleOnly) | Scale the display @@ -84,7 +84,7 @@ functions. | onFBUComplete | (rfb, fbu) | RFB FBU received and processed (see details below) | onFBResize | (rfb, width, height) | Frame buffer (remote desktop) size changed | 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__ diff --git a/tests/test.rfb.js b/tests/test.rfb.js index e4336f6f..f59a2fe3 100644 --- a/tests/test.rfb.js +++ b/tests/test.rfb.js @@ -300,28 +300,23 @@ describe('Remote Frame Buffer Protocol Client', function() { client._rfb_xvp_ver = 1; }); - it('should send the shutdown signal on #xvpShutdown', function () { - client.xvpShutdown(); + it('should send the shutdown signal on #machineShutdown', function () { + client.machineShutdown(); expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x02])); }); - it('should send the reboot signal on #xvpReboot', function () { - client.xvpReboot(); + it('should send the reboot signal on #machineReboot', function () { + client.machineReboot(); expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x03])); }); - it('should send the reset signal on #xvpReset', function () { - client.xvpReset(); + it('should send the reset signal on #machineReset', function () { + client.machineReset(); 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 () { - expect(client.xvpOp(2, 7)).to.be.false; + client._xvpOp(2, 7); 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 () { - client.set_onXvpInit(sinon.spy()); + client.set_onCapabilities(sinon.spy()); client._sock._websocket._receive_data(new Uint8Array([250, 0, 10, 1])); expect(client._rfb_xvp_ver).to.equal(10); - expect(client.get_onXvpInit()).to.have.been.calledOnce; - expect(client.get_onXvpInit()).to.have.been.calledWith(10); + expect(client.get_onCapabilities()).to.have.been.calledOnce; + expect(client.get_onCapabilities()).to.have.been.calledWith(client, { power: true }); }); it('should fail on unknown XVP message types', function () { diff --git a/vnc.html b/vnc.html index 40d89c7f..e2799d6e 100644 --- a/vnc.html +++ b/vnc.html @@ -152,18 +152,18 @@ - +