diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 0000000..8b0099f --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,41 @@ +# This is a basic workflow to help you get started with Actions + +name: linter + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@master + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: install libvirt-dev + run: | + sudo apt-get install -y libvirt-dev + - name: Install dependencies + run: | + python3 -m pip install --upgrade pip + if [ -f dev/requirements.txt ]; then pip3 install -r dev/requirements.txt; fi + - name: Super-Linter + uses: github/super-linter@v2.1.0 + env: + VALIDATE_RUBY: false + VALIDATE_ANSIBLE: false diff --git a/console/templates/console-base.html b/console/templates/console-base.html index be027ec..7875f7e 100644 --- a/console/templates/console-base.html +++ b/console/templates/console-base.html @@ -1,6 +1,7 @@ {% load staticfiles %} {% load i18n %} <html> + <head> <meta charset="utf-8"> <link rel="shortcut icon" href="{% static "favicon.ico" %}"> @@ -9,19 +10,13 @@ <link href="{% static "css/webvirtcloud.css" %}" rel="stylesheet"> <style> - body { - margin: 0; - padding: 0; - background-color: #313131; - } - #main_container { padding: 0; width: 100%; max-width: none; height: 100%; - background-color:#494949; - border-bottom-right-radius: 800px 600px; + background-color: #494949; + border-bottom-right-radius: 850px 600px; } @@ -32,102 +27,90 @@ margin-right: auto; display: block; } - - #status { - z-index: 10000; - width: 80%; - position: absolute; - top: 5px; - left: 10%; - text-align: center; - } </style> -{% block head %}{% endblock %} + {% block head %}{% endblock %} </head> <body> -<div id='main_container' class="container"> -<nav class="navbar navbar-expand-md navbar-dark bg-primary" arial-label="console navbar"> - <div class="container"> - <a class="navbar-brand">{{ instance.name }}</a> - <button type="button" class="navbar-toggler" data-toggle="collapse" data-target=".navbar-collapse" aria-expanded="false" aria-label="Toggle navigation"> - <span class="navbar-toggler-icon"></span> - </button> + <div id='main_container' class="container"> + <nav class="navbar navbar-expand-md navbar-dark bg-primary" arial-label="console navbar"> + <div class="container"> + <a class="navbar-brand">{{ instance.name }}</a> + <button type="button" class="navbar-toggler" data-toggle="collapse" data-target=".navbar-collapse" + aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> - <div class="collapse navbar-collapse"> - <ul class="navbar-nav mr-auto mt-2 mt-md-0"> - <li class="nav-item dropdown"> - <a href="#" class="nav-link dropdown-toggle" - data-toggle="dropdown" - role="button" - id="dropdownMenuLink" - data-toggle="dropdown" - aria-haspopup="true" - aria-expanded="false"> - {% trans "Send key(s)" %} - </a> - <div class="dropdown-menu" aria-labelledby="dropdownMenuLink"> - <a class="dropdown-item" id="ctrlaltdel" href='#'>Ctrl+Alt+Del</a> - <div class="dropdown-divider"></div> - <a class="dropdown-item" id="ctrlaltf1" href='#'>Ctrl+Alt+F1</a> - <a class="dropdown-item" id="ctrlaltf2" href='#'>Ctrl+Alt+F2</a> - <a class="dropdown-item" id="ctrlaltf3" href='#'>Ctrl+Alt+F3</a> - <a class="dropdown-item" id="ctrlaltf4" href='#'>Ctrl+Alt+F4</a> - <a class="dropdown-item" id="ctrlaltf5" href='#'>Ctrl+Alt+F5</a> - <a class="dropdown-item" id="ctrlaltf6" href='#'>Ctrl+Alt+F6</a> - <a class="dropdown-item" id="ctrlaltf7" href='#'>Ctrl+Alt+F7</a> - <a class="dropdown-item" id="ctrlaltf8" href='#'>Ctrl+Alt+F8</a> - <a class="dropdown-item" id="ctrlaltf9" href='#'>Ctrl+Alt+F9</a> - <a class="dropdown-item" id="ctrlaltf10" href='#'>Ctrl+Alt+F10</a> - <a class="dropdown-item" id="ctrlaltf11" href='#'>Ctrl+Alt+F11</a> - <a class="dropdown-item" id="ctrlaltf12" href='#'>Ctrl+Alt+F12</a> + <div class="collapse navbar-collapse"> + <ul class="navbar-nav mr-auto mt-2 mt-md-0"> + <li class="nav-item dropdown"> + <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown" role="button" + id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> + {% trans "Send key(s)" %} + </a> + <div class="dropdown-menu" aria-labelledby="dropdownMenuLink"> + <a class="dropdown-item" id="ctrlaltdel" href='#'>Ctrl+Alt+Del</a> + <div class="dropdown-divider"></div> + <a class="dropdown-item" id="ctrlaltf1" href='#'>Ctrl+Alt+F1</a> + <a class="dropdown-item" id="ctrlaltf2" href='#'>Ctrl+Alt+F2</a> + <a class="dropdown-item" id="ctrlaltf3" href='#'>Ctrl+Alt+F3</a> + <a class="dropdown-item" id="ctrlaltf4" href='#'>Ctrl+Alt+F4</a> + <a class="dropdown-item" id="ctrlaltf5" href='#'>Ctrl+Alt+F5</a> + <a class="dropdown-item" id="ctrlaltf6" href='#'>Ctrl+Alt+F6</a> + <a class="dropdown-item" id="ctrlaltf7" href='#'>Ctrl+Alt+F7</a> + <a class="dropdown-item" id="ctrlaltf8" href='#'>Ctrl+Alt+F8</a> + <a class="dropdown-item" id="ctrlaltf9" href='#'>Ctrl+Alt+F9</a> + <a class="dropdown-item" id="ctrlaltf10" href='#'>Ctrl+Alt+F10</a> + <a class="dropdown-item" id="ctrlaltf11" href='#'>Ctrl+Alt+F11</a> + <a class="dropdown-item" id="ctrlaltf12" href='#'>Ctrl+Alt+F12</a> + </div> + </li> + <li class="nav-item" id="fullscreen_button"> + <a class="nav-link" href='#'>{% trans "Fullscreen" %}</a> + </li> + {% block navbarmenu %}{% endblock %} + </ul> </div> - </li> - <li class="nav-item" id="fullscreen_button"> - <a class="nav-link" href='#'>{% trans "Fullscreen" %}</a> - </li> -{% block navbarmenu %}{% endblock %} - </ul> - </div> -</nav> + </div> + </nav> + {% block content %}{% endblock %} + </div> + <script src="{% static "js/jquery.js" %}"></script> + <script src="{% static "js/bootstrap.bundle.min.js" %}"></script> -{% block content %}{% endblock %} -</div> -<script src="{% static "js/jquery.js" %}"></script> -<script src="{% static "js/bootstrap.bundle.min.js" %}"></script> - -<script> - function log_message(msg,type) { - var exist=$('#status').is('div'); - status_div=$('<div id="status" class="alert alert-'+type+' role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>'+msg+'</div>'); - if (exist) { - $('#status').remove(); - $('body').prepend(status_div); + <script> + function log_message(msg, type) { + var exist = $('#status').is('div'); + status_div = $('<div id="status" class="alert alert-' + type + ' role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + msg + '</div>'); + if (exist) { + $('#status').remove(); + $('body').prepend(status_div); + } + else { + status_div.hide(); + $('body').prepend(status_div); + status_div.fadeIn(200); + } + if (type != 'danger') { + status_div.delay(3000).fadeOut(200); + } } - else { - status_div.hide(); - $('body').prepend(status_div); - status_div.fadeIn(200); - } - if (type!='danger') { - status_div.delay(3000).fadeOut(200); - } - } - function log_error(msg) { - log_message(msg,'danger'); - } + function log_error(msg) { + log_message(msg, 'danger'); + } - function log_info(msg) { - log_message(msg,'info'); - } - {% if console_error %} + function log_info(msg) { + log_message(msg, 'info'); + } + {% if console_error %} log_error('{{ console_error|escapejs }}'); - {% endif %} -</script> + {% endif %} + </script> -{% block foot %}{% endblock %} + {% block foot %}{% endblock %} </body> -</html> + +</html> \ No newline at end of file diff --git a/console/templates/console-spice-full.html b/console/templates/console-spice-full.html index aac780d..6c3d635 100644 --- a/console/templates/console-spice-full.html +++ b/console/templates/console-spice-full.html @@ -27,138 +27,116 @@ {% load staticfiles %} {% block head %} - <title>WebVirtCloud - Spice Client - Full</title> - <link rel="stylesheet" type="text/css" href="{% static "js/spice-html5/spice.css" %}" /> +<title>WebVirtCloud - Spice Client - Full</title> +<link rel="stylesheet" type="text/css" href="{% static "js/spice-html5/spice.css" %}" /> - <!-- ES2015/ES6 modules polyfill --> - <script type="module"> - window._spice_has_module_support = true; - </script> - <script> - window.addEventListener("load", function() { - if (window._spice_has_module_support) return; - var loader = document.createElement("script"); - loader.src = '{% static "thirdparty/browser-es-module-loader/dist/browser-es-module-loader.js" %}'; - document.head.appendChild(loader); - }); - </script> +<!-- ES2015/ES6 modules polyfill --> +<script type="module"> + window._spice_has_module_support = true; +</script> +<script> + window.addEventListener("load", function () { + if (window._spice_has_module_support) return; + var loader = document.createElement("script"); + loader.src = '{% static "thirdparty/browser-es-module-loader/dist/browser-es-module-loader.js" %}'; + document.head.appendChild(loader); + }); +</script> - <script type="module" crossorigin="anonymous"> +<script type="module" crossorigin="anonymous"> - import * as SpiceHtml5 from '{% static "js/spice-html5/main.js" %}'; + import * as SpiceHtml5 from '{% static "js/spice-html5/main.js" %}'; - var host = null, port = null; - var sc; + var host = null, port = null; + var sc; - function spice_error(e) { + function spice_error(e) { + disconnect(); + } + + function connect() { + var host, port, password, scheme = "ws://", uri; + + host = document.getElementById("host").value; + port = document.getElementById("port").value; + password = document.getElementById("password").value; + + if ((!host) || (!port)) { + console.log("must set host and port"); + return; + } + + if (sc) { + sc.stop(); + } + + uri = scheme + host + ":" + port; + + document.getElementById('connectButton').innerHTML = "Stop"; + document.getElementById('connectButton').onclick = disconnect; + + try { + sc = new SpiceHtml5.SpiceMainConn({ + uri: uri, screen_id: "spice-screen", dump_id: "debug-div", + message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected + }); + } + catch (e) { + alert(e.toString()); disconnect(); } + } - function connect() { - var host, port, password, scheme = "ws://", uri; - - host = document.getElementById("host").value; - port = document.getElementById("port").value; - password = document.getElementById("password").value; - - if ((!host) || (!port)) { - console.log("must set host and port"); - return; + function disconnect() { + console.log(">> disconnect"); + if (sc) { + sc.stop(); + } + document.getElementById('connectButton').innerHTML = "Start"; + document.getElementById('connectButton').onclick = connect; + if (window.File && window.FileReader && window.FileList && window.Blob) { + var spice_xfer_area = document.getElementById('spice-xfer-area'); + if (spice_xfer_area != null) { + document.getElementById('spice-area').removeChild(spice_xfer_area); } + document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false); + document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false); + } + console.log("<< disconnect"); + } - if (sc) { - sc.stop(); - } + function agent_connected(sc) { + window.addEventListener('resize', SpiceHtml5.handle_resize); + window.spice_connection = this; - uri = scheme + host + ":" + port; + SpiceHtml5.resize_helper(this); - document.getElementById('connectButton').innerHTML = "Stop"; - document.getElementById('connectButton').onclick = disconnect; + if (window.File && window.FileReader && window.FileList && window.Blob) { + var spice_xfer_area = document.createElement("div"); + spice_xfer_area.setAttribute('id', 'spice-xfer-area'); + document.getElementById('spice-area').appendChild(spice_xfer_area); + document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false); + document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false); + } + else { + console.log("File API is not supported"); + } + } - try { - sc = new SpiceHtml5.SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div", - message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected }); - } - catch (e) { - alert(e.toString()); - disconnect(); - } + function toggle_console() { + var checkbox = document.getElementById('show_console'); + var m = document.getElementById('message-div'); + + if (checkbox.checked) { + m.style.display = 'block'; + } + else { + m.style.display = 'none'; } - function disconnect() { - console.log(">> disconnect"); - if (sc) { - sc.stop(); - } - document.getElementById('connectButton').innerHTML = "Start"; - document.getElementById('connectButton').onclick = connect; - if (window.File && window.FileReader && window.FileList && window.Blob) { - var spice_xfer_area = document.getElementById('spice-xfer-area'); - if (spice_xfer_area != null) { - document.getElementById('spice-area').removeChild(spice_xfer_area); - } - document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false); - document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false); - } - console.log("<< disconnect"); - } - - function agent_connected(sc) { - window.addEventListener('resize', SpiceHtml5.handle_resize); - window.spice_connection = this; - - SpiceHtml5.resize_helper(this); - - if (window.File && window.FileReader && window.FileList && window.Blob) { - var spice_xfer_area = document.createElement("div"); - spice_xfer_area.setAttribute('id', 'spice-xfer-area'); - document.getElementById('spice-area').appendChild(spice_xfer_area); - document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false); - document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false); - } - else { - console.log("File API is not supported"); - } - } - - function toggle_console() { - var checkbox = document.getElementById('show_console'); - var m = document.getElementById('message-div'); - - if (checkbox.checked) { - m.style.display = 'block'; - } - else { - m.style.display = 'none'; - } - - window.addEventListener('resize', SpiceHtml5.handle_resize); - if (sc) { - SpiceHtml5.resize_helper(sc); - } - } - /* SPICE port event listeners - window.addEventListener('spice-port-data', function(event) { - // Here we convert data to text, but really we can obtain binary data also - var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data)); - DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); - }); - - window.addEventListener('spice-port-event', function(event) { - DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); - }); - */ - - function fullscreen() { - var screen=document.getElementById('spice-screen'); - if(screen.requestFullscreen) { - screen.requestFullscreen(); - } else if(screen.mozRequestFullScreen) { - screen.mozRequestFullScreen(); - } else if(screen.webkitRequestFullscreen) { - screen.webkitRequestFullscreen(); - } else if(screen.msRequestFullscreen) { - screen.msRequestFullscreen(); + window.addEventListener('resize', SpiceHtml5.handle_resize); + if (sc) { + SpiceHtml5.resize_helper(sc); } } /* SPICE port event listeners @@ -168,24 +146,53 @@ DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); }); + window.addEventListener('spice-port-event', function(event) { + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); + }); + */ + + function fullscreen() { + var screen = document.getElementById('spice-screen'); + if (screen.requestFullscreen) { + screen.requestFullscreen(); + } else if (screen.mozRequestFullScreen) { + screen.mozRequestFullScreen(); + } else if (screen.webkitRequestFullscreen) { + screen.webkitRequestFullscreen(); + } else if (screen.msRequestFullscreen) { + screen.msRequestFullscreen(); + } + } + + function sendctrlaltfn(f) { + SpiceHtml5.sendCtrlAltFN(sc, f); + return false; + } + /* SPICE port event listeners + window.addEventListener('spice-port-data', function(event) { + // Here we convert data to text, but really we can obtain binary data also + var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data)); + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); + }); + window.addEventListener('spice-port-event', function(event) { DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); }); */ document.getElementById("fullscreen_button").addEventListener('click', fullscreen); - document.getElementById('ctrlaltdel').addEventListener('click', function(){sendCtrlAltDel(sc);}); - document.getElementById('ctrlaltf1').addEventListener('click', function(){sendCtrlAltFN(0);}); - document.getElementById('ctrlaltf2').addEventListener('click', function(){sendCtrlAltFN(1);}); - document.getElementById('ctrlaltf3').addEventListener('click', function(){sendCtrlAltFN(2);}); - document.getElementById('ctrlaltf4').addEventListener('click', function(){sendCtrlAltFN(3);}); - document.getElementById('ctrlaltf5').addEventListener('click', function(){sendCtrlAltFN(4);}); - document.getElementById('ctrlaltf6').addEventListener('click', function(){sendCtrlAltFN(5);}); - document.getElementById('ctrlaltf7').addEventListener('click', function(){sendCtrlAltFN(6);}); - document.getElementById('ctrlaltf8').addEventListener('click', function(){sendCtrlAltFN(7);}); - document.getElementById('ctrlaltf9').addEventListener('click', function(){sendCtrlAltFN(8);}); - document.getElementById('ctrlaltf10').addEventListener('click', function(){sendCtrlAltFN(9);}); - document.getElementById('ctrlaltf11').addEventListener('click', function(){sendCtrlAltFN(10);}); - document.getElementById('ctrlaltf12').addEventListener('click', function(){sendCtrlAltFN(11);}); + document.getElementById('ctrlaltdel').addEventListener('click', function () { sendCtrlAltDel(sc); }); + document.getElementById('ctrlaltf1').addEventListener('click', function () { sendctrlaltfn(0) }); + document.getElementById('ctrlaltf2').addEventListener('click', function () { sendctrlaltfn(1) }); + document.getElementById('ctrlaltf3').addEventListener('click', function () { sendctrlaltfn(2) }); + document.getElementById('ctrlaltf4').addEventListener('click', function () { sendctrlaltfn(3) }); + document.getElementById('ctrlaltf5').addEventListener('click', function () { sendctrlaltfn(4) }); + document.getElementById('ctrlaltf6').addEventListener('click', function () { sendctrlaltfn(5) }); + document.getElementById('ctrlaltf7').addEventListener('click', function () { sendctrlaltfn(6) }); + document.getElementById('ctrlaltf8').addEventListener('click', function () { sendctrlaltfn(7) }); + document.getElementById('ctrlaltf9').addEventListener('click', function () { sendctrlaltfn(8) }); + document.getElementById('ctrlaltf10').addEventListener('click', function () { sendctrlaltfn(9) }); + document.getElementById('ctrlaltf11').addEventListener('click', function () { sendctrlaltfn(10) }); + document.getElementById('ctrlaltf12').addEventListener('click', function () { sendctrlaltfn(11) }); document.getElementById('connectButton').onclick = connect; document.getElementById('show_console').onchange = toggle_console; @@ -193,27 +200,29 @@ {% endblock %} {% block content %} - <div id="login"> - <span class="logo">SPICE</span> - <label for="host">{% trans 'Host' %}:</label> <input type='text' id='host' value='{{ ws_host }}'> <!-- localhost --> - <label for="port">{% trans 'Port' %}:</label> <input type='text' id='port' value='{{ ws_port }}'> - <label for="password">{% trans 'Password' %}:</label> <input type='password' id='password' value='{{ console_passwd }}'> - <label for="show_console">{% trans 'Show console' %}</label><input type="checkbox" id="show_console" value="1" onchange="toggle_console()" checked> - <button id="connectButton">{% trans 'Start' %}</button> - </div> +<div id="login"> + <span class="logo">SPICE</span> + <label for="host">{% trans 'Host' %}:</label> <input type='text' id='host' value='{{ ws_host }}'> <!-- localhost --> + <label for="port">{% trans 'Port' %}:</label> <input type='text' id='port' value='{{ ws_port }}'> + <label for="password">{% trans 'Password' %}:</label> <input type='password' id='password' + value='{{ console_passwd }}'> + <label for="show_console">{% trans 'Show console' %}</label><input type="checkbox" id="show_console" value="1" + onchange="toggle_console()" checked> + <button id="connectButton">{% trans 'Start' %}</button> +</div> - <div id="spice-area"> - <div id="spice-screen" class="spice-screen"></div> - </div> +<div id="spice-area"> + <div id="spice-screen" class="spice-screen"></div> +</div> - <div id="message-div" class="spice-message"></div> +<div id="message-div" class="spice-message"></div> - <div id="debug-div"> +<div id="debug-div"> <!-- If DUMPXXX is turned on, dumped images will go here --> - </div> +</div> {% endblock %} {% block foot %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/console/templates/console-spice-lite.html b/console/templates/console-spice-lite.html index 1498b43..b03d7c2 100644 --- a/console/templates/console-spice-lite.html +++ b/console/templates/console-spice-lite.html @@ -27,198 +27,205 @@ {% load staticfiles %} {% block head %} - <title>WebVirtCloud - Spice - Lite</title> - <link rel="stylesheet" type="text/css" href="{% static "js/spice-html5/spice.css" %}" /> +<title>WebVirtCloud - Spice - Lite</title> +<link rel="stylesheet" type="text/css" href="{% static "js/spice-html5/spice.css" %}" /> - <!-- ES2015/ES6 modules polyfill --> - <script type="module"> - window._spice_has_module_support = true; - </script> - <script> - window.addEventListener("load", function() { - if (window._spice_has_module_support) return; - var loader = document.createElement("script"); - loader.src = '{% static "thirdparty/browser-es-module-loader/dist/browser-es-module-loader.js" %}'; - document.head.appendChild(loader); - }); - </script> +<!-- ES2015/ES6 modules polyfill --> +<script type="module"> + window._spice_has_module_support = true; +</script> +<script> + window.addEventListener("load", function () { + if (window._spice_has_module_support) return; + var loader = document.createElement("script"); + loader.src = '{% static "thirdparty/browser-es-module-loader/dist/browser-es-module-loader.js" %}'; + document.head.appendChild(loader); + }); +</script> - <script type="module" crossorigin="anonymous"> - import * as SpiceHtml5 from '{% static "js/spice-html5/main.js" %}'; +<script type="module" crossorigin="anonymous"> + import * as SpiceHtml5 from '{% static "js/spice-html5/main.js" %}'; - var host = null, port = null; - var sc; + var host = null, port = null; + var sc; - function spice_set_cookie(name, value, days) { - var date, expires; - date = new Date(); - date.setTime(date.getTime() + (days*24*60*60*1000)); - expires = "; expires=" + date.toGMTString(); - document.cookie = name + "=" + value + expires + "; path=/"; - }; + function spice_set_cookie(name, value, days) { + var date, expires; + date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + document.cookie = name + "=" + value + expires + "; path=/"; + }; - function spice_query_var(name, defvalue) { - var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); - return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : defvalue; + function spice_query_var(name, defvalue) { + var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); + return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : defvalue; + } + + function spice_error(e) { + disconnect(); + if (e !== undefined && e.message === "Permission denied.") { + var pass = prompt("Password"); + connect(pass); + } + } + + function connect(password) { + var host, port, scheme = "ws://", uri; + + // By default, use the host and port of server that served this file + // host = spice_query_var('host', window.location.hostname); + host = '{{ ws_host| safe }}'; + + // Note that using the web server port only makes sense + // if your web server has a reverse proxy to relay the WebSocket + // traffic to the correct destination port. + var default_port = window.location.port; + if (!default_port) { + if (window.location.protocol == 'http:') { + default_port = 80; + } + else if (window.location.protocol == 'https:') { + default_port = 443; + } + } + //port = spice_query_var('port', default_port); + port = '{{ ws_port| safe }}'; + if (window.location.protocol == 'https:') { + scheme = "wss://"; } - function spice_error(e) { + // If a token variable is passed in, set the parameter in a cookie. + // This is used by nova-spiceproxy. + var token = spice_query_var('token', null); + if (token) { + spice_set_cookie('token', token, 1) + } + + if (password === undefined) { + password = spice_query_var('password', ''); + password = '{{ console_passwd | safe }}'; + } + if (password === 'None') password = ''; + + var path = spice_query_var('path', 'websockify'); + + if ((!host) || (!port)) { + console.log(_("must specify host and port in URL")); + return; + } + + if (sc) { + sc.stop(); + } + + uri = scheme + host + ":" + port; + + if (path) { + uri += path[0] == '/' ? path : ('/' + path); + } + + try { + sc = new SpiceHtml5.SpiceMainConn({ + uri: uri, screen_id: "spice-screen", dump_id: "debug-div", + message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected + }); + } + catch (e) { + alert(e.toString()); disconnect(); - if (e !== undefined && e.message === "Permission denied.") { - var pass = prompt("Password"); - connect(pass); - } } - function connect(password) { - var host, port, scheme = "ws://", uri; - - // By default, use the host and port of server that served this file - // host = spice_query_var('host', window.location.hostname); - host = '{{ ws_host| safe }}'; - - // Note that using the web server port only makes sense - // if your web server has a reverse proxy to relay the WebSocket - // traffic to the correct destination port. - var default_port = window.location.port; - if (!default_port) { - if (window.location.protocol == 'http:') { - default_port = 80; - } - else if (window.location.protocol == 'https:') { - default_port = 443; - } - } - //port = spice_query_var('port', default_port); - port = '{{ ws_port| safe }}'; - if (window.location.protocol == 'https:') { - scheme = "wss://"; - } - - // If a token variable is passed in, set the parameter in a cookie. - // This is used by nova-spiceproxy. - var token = spice_query_var('token', null); - if (token) { - spice_set_cookie('token', token, 1) - } - - if (password === undefined) { - password = spice_query_var('password', ''); - password = '{{ console_passwd | safe }}'; - } - if (password === 'None') password = ''; - - var path = spice_query_var('path', 'websockify'); - - if ((!host) || (!port)) { - console.log(_("must specify host and port in URL")); - return; - } - - if (sc) { - sc.stop(); - } - - uri = scheme + host + ":" + port; - - if (path) { - uri += path[0] == '/' ? path : ('/' + path); - } - - try { - sc = new SpiceHtml5.SpiceMainConn({uri: uri, screen_id: "spice-screen", dump_id: "debug-div", - message_id: "message-div", password: password, onerror: spice_error, onagent: agent_connected }); - } - catch (e) { - alert(e.toString()); - disconnect(); - } + } + function disconnect() { + console.log(">> disconnect"); + if (sc) { + sc.stop(); } - - function disconnect() { - console.log(">> disconnect"); - if (sc) { - sc.stop(); + if (window.File && window.FileReader && window.FileList && window.Blob) { + var spice_xfer_area = document.getElementById('spice-xfer-area'); + if (spice_xfer_area != null) { + document.getElementById('spice-area').removeChild(spice_xfer_area); } - if (window.File && window.FileReader && window.FileList && window.Blob) { - var spice_xfer_area = document.getElementById('spice-xfer-area'); - if (spice_xfer_area != null) { - document.getElementById('spice-area').removeChild(spice_xfer_area); - } - document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false); - document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false); - } - console.log("<< disconnect"); + document.getElementById('spice-area').removeEventListener('dragover', SpiceHtml5.handle_file_dragover, false); + document.getElementById('spice-area').removeEventListener('drop', SpiceHtml5.handle_file_drop, false); } + console.log("<< disconnect"); + } - function agent_connected(sc) { - window.addEventListener('resize', SpiceHtml5.handle_resize); - window.spice_connection = this; + function agent_connected(sc) { + window.addEventListener('resize', SpiceHtml5.handle_resize); + window.spice_connection = this; - SpiceHtml5.resize_helper(this); + SpiceHtml5.resize_helper(this); - if (window.File && window.FileReader && window.FileList && window.Blob) { - var spice_xfer_area = document.createElement("div"); - spice_xfer_area.setAttribute('id', 'spice-xfer-area'); - document.getElementById('spice-area').appendChild(spice_xfer_area); - document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false); - document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false); - } - else { - console.log("File API is not supported"); - } + if (window.File && window.FileReader && window.FileList && window.Blob) { + var spice_xfer_area = document.createElement("div"); + spice_xfer_area.setAttribute('id', 'spice-xfer-area'); + document.getElementById('spice-area').appendChild(spice_xfer_area); + document.getElementById('spice-area').addEventListener('dragover', SpiceHtml5.handle_file_dragover, false); + document.getElementById('spice-area').addEventListener('drop', SpiceHtml5.handle_file_drop, false); } - - function fullscreen() { - var screen=document.getElementById('spice-screen'); - if(screen.requestFullscreen) { - screen.requestFullscreen(); - } else if(screen.mozRequestFullScreen) { - screen.mozRequestFullScreen(); - } else if(screen.webkitRequestFullscreen) { - screen.webkitRequestFullscreen(); - } else if(screen.msRequestFullscreen) { - screen.msRequestFullscreen(); - } + else { + console.log("File API is not supported"); } + } - /* SPICE port event listeners - window.addEventListener('spice-port-data', function(event) { - // Here we convert data to text, but really we can obtain binary data also - var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data)); - DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); - }); + function fullscreen() { + var screen = document.getElementById('spice-screen'); + if (screen.requestFullscreen) { + screen.requestFullscreen(); + } else if (screen.mozRequestFullScreen) { + screen.mozRequestFullScreen(); + } else if (screen.webkitRequestFullscreen) { + screen.webkitRequestFullscreen(); + } else if (screen.msRequestFullscreen) { + screen.msRequestFullscreen(); + } + } - window.addEventListener('spice-port-event', function(event) { - DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); - }); - */ - document.getElementById("fullscreen_button").addEventListener('click', fullscreen); - document.getElementById('ctrlaltdel').addEventListener('click', function(){sendCtrlAltDel(sc);}); - document.getElementById('ctrlaltf1').addEventListener('click', function(){sendCtrlAltFN(0);}); - document.getElementById('ctrlaltf2').addEventListener('click', function(){sendCtrlAltFN(1);}); - document.getElementById('ctrlaltf3').addEventListener('click', function(){sendCtrlAltFN(2);}); - document.getElementById('ctrlaltf4').addEventListener('click', function(){sendCtrlAltFN(3);}); - document.getElementById('ctrlaltf5').addEventListener('click', function(){sendCtrlAltFN(4);}); - document.getElementById('ctrlaltf6').addEventListener('click', function(){sendCtrlAltFN(5);}); - document.getElementById('ctrlaltf7').addEventListener('click', function(){sendCtrlAltFN(6);}); - document.getElementById('ctrlaltf8').addEventListener('click', function(){sendCtrlAltFN(7);}); - document.getElementById('ctrlaltf9').addEventListener('click', function(){sendCtrlAltFN(8);}); - document.getElementById('ctrlaltf10').addEventListener('click', function(){sendCtrlAltFN(9);}); - document.getElementById('ctrlaltf11').addEventListener('click', function(){sendCtrlAltFN(10);}); - document.getElementById('ctrlaltf12').addEventListener('click', function(){sendCtrlAltFN(11);}); - connect(undefined); - </script> + function sendctrlaltfn(f) { + SpiceHtml5.sendCtrlAltFN(sc, f); + return false; + } + + /* SPICE port event listeners + window.addEventListener('spice-port-data', function(event) { + // Here we convert data to text, but really we can obtain binary data also + var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data)); + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); + }); + + window.addEventListener('spice-port-event', function(event) { + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); + }); + */ + document.getElementById("fullscreen_button").addEventListener('click', fullscreen); + document.getElementById('ctrlaltdel').addEventListener('click', function () { sendCtrlAltDel(sc); }); + document.getElementById('ctrlaltf1').addEventListener('click', function () { sendctrlaltfn(0) }); + document.getElementById('ctrlaltf2').addEventListener('click', function () { sendctrlaltfn(1) }); + document.getElementById('ctrlaltf3').addEventListener('click', function () { sendctrlaltfn(2) }); + document.getElementById('ctrlaltf4').addEventListener('click', function () { sendctrlaltfn(3) }); + document.getElementById('ctrlaltf5').addEventListener('click', function () { sendctrlaltfn(4) }); + document.getElementById('ctrlaltf6').addEventListener('click', function () { sendctrlaltfn(5) }); + document.getElementById('ctrlaltf7').addEventListener('click', function () { sendctrlaltfn(6) }); + document.getElementById('ctrlaltf8').addEventListener('click', function () { sendctrlaltfn(7) }); + document.getElementById('ctrlaltf9').addEventListener('click', function () { sendctrlaltfn(8) }); + document.getElementById('ctrlaltf10').addEventListener('click', function () { sendctrlaltfn(9) }); + document.getElementById('ctrlaltf11').addEventListener('click', function () { sendctrlaltfn(10) }); + document.getElementById('ctrlaltf12').addEventListener('click', function () { sendctrlaltfn(11) }); + connect(undefined); +</script> {% endblock %} {% block content %} - <div id="spice-area"> - <div id="spice-screen" class="spice-screen"></div> - </div> +<div id="spice-area"> + <div id="spice-screen" class="spice-screen"></div> +</div> - <div id="message-div" class="spice-message"></div> +<div id="message-div" class="spice-message"></div> - <div id="debug-div"> - <!-- If DUMPXXX is turned on, dumped images will go here --> - </div> -{% endblock %} +<div id="debug-div"> + <!-- If DUMPXXX is turned on, dumped images will go here --> +</div> +{% endblock %} \ No newline at end of file diff --git a/console/templates/console-vnc-lite.html b/console/templates/console-vnc-lite.html index 70e10e6..3fd7db2 100755 --- a/console/templates/console-vnc-lite.html +++ b/console/templates/console-vnc-lite.html @@ -3,306 +3,228 @@ {% load staticfiles %} {% block head %} - <!-- + +<!-- noVNC example: lightweight example using minimal UI and features - Copyright (C) 2012 Joel Martin - Copyright (C) 2017 Samuel Mannehed for Cendio AB + This is a self-contained file which doesn't import WebUtil or external CSS. + Copyright (C) 2019 The noVNC Authors noVNC is licensed under the MPL 2.0 (see LICENSE.txt) This file is licensed under the 2-Clause BSD license (see LICENSE.txt). - Connect parameters are provided in query string: - http://example.com/?host=HOST&port=PORT&encrypt=1 - or the fragment: - http://example.com/#host=HOST&port=PORT&encrypt=1 - --> - <title>WebVirtCloud - noVNC - Lite</title> + http://example.com/?host=HOST&port=PORT&scale=true +--> +<title>WebVirtCloud - noVNC - Lite</title> - <meta charset="utf-8"> +<meta charset="utf-8"> - <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame - Remove this if you use the .htaccess --> - <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> +<!-- Always force latest IE rendering engine (even in intranet) & + Chrome Frame. Remove this if you use the .htaccess --> +<meta http-equiv="X-UA-Compatible" content="IE=edge" /> - <!-- Icons (see Makefile for what the sizes are for) --> - <link rel="icon" sizes="16x16" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-16x16.png" %}"> - <link rel="icon" sizes="24x24" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-24x24.png" %}"> - <link rel="icon" sizes="32x32" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-32x32.png" %}"> - <link rel="icon" sizes="48x48" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-48x48.png" %}"> - <link rel="icon" sizes="60x60" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-60x60.png" %}"> - <link rel="icon" sizes="64x64" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-64x64.png" %}"> - <link rel="icon" sizes="72x72" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-72x72.png" %}"> - <link rel="icon" sizes="76x76" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-76x76.png" %}"> - <link rel="icon" sizes="96x96" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-96x96.png" %}"> - <link rel="icon" sizes="120x120" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-120x120.png" %}"> - <link rel="icon" sizes="144x144" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-144x144.png" %}"> - <link rel="icon" sizes="152x152" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-152x152.png" %}"> - <link rel="icon" sizes="192x192" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-192x192.png" %}"> - <!-- Firefox currently mishandles SVG, see #1419039 - <link rel="icon" sizes="any" type="image/svg+xml" href="{% static "js/novnc/app/images/icons/novnc-icon.svg" %}"> - --> - <!-- Repeated last so that legacy handling will pick this --> - <link rel="icon" sizes="16x16" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-16x16.png" %}"> +<!-- Stylesheets --> +<link rel="stylesheet" href='{% static "js/novnc/app/styles/lite.css" %}'> - <!-- Apple iOS Safari settings --> - <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> - <meta name="apple-mobile-web-app-capable" content="yes" /> - <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /> - <!-- Home Screen Icons (favourites and bookmarks use the normal icons) --> - <link rel="apple-touch-icon" sizes="60x60" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-60x60.png" %}"> - <link rel="apple-touch-icon" sizes="76x76" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-76x76.png" %}"> - <link rel="apple-touch-icon" sizes="120x120" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-120x120.png" %}"> - <link rel="apple-touch-icon" sizes="152x152" type="image/png" href="{% static "js/novnc/app/images/icons/novnc-152x152.png" %}"> +<!-- Promise polyfill for IE11 --> +<script src="{% static 'js/novnc/vendor/promise.js' %}"></script> - <!-- Stylesheets --> - <link rel="stylesheet" href="{% static "js/novnc/app/styles/lite.css" %}"> +<!-- ES2015/ES6 modules polyfill --> +<script nomodule + src="{% static 'js/novnc/vendor/browser-es-module-loader/dist/browser-es-module-loader.js' %}"></script> - <!-- - <script type='text/javascript' - src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> - --> +<!-- actual script modules --> +<script type="module" crossorigin="anonymous"> + // RFB holds the API to connect and communicate with a VNC server + import RFB from '{% static "js/novnc/core/rfb.js" %}'; - <!-- promise polyfills promises for IE11 --> - <script src="{% static "js/novnc/vendor/promise.js" %}"></script> - <!-- ES2015/ES6 modules polyfill --> - <script type="module"> window._noVNC_has_module_support = true;</script> - <script> - window.addEventListener("load", function() { - if (window._noVNC_has_module_support) return; - var loader = document.createElement("script"); - loader.src = "{% static "js/novnc/vendor/browser-es-module-loader/dist/browser-es-module-loader.js" %}"; - document.head.appendChild(loader); - }); - </script> + let rfb; + let desktopName; - <!-- actual script modules --> - <script type="module" crossorigin="anonymous"> - // Load supporting scripts - import * as WebUtil from '{% static "js/novnc/app/webutil.js" %}'; - import RFB from '{% static "js/novnc/core/rfb.js" %}'; + // When this function is called we have + // successfully connected to a server + function connectedToServer(e) { + status("Connected to " + desktopName); + } - var rfb; - var desktopName; - - function updateDesktopName(e) { - desktopName = e.detail.name; + // This function is called when we are disconnected + function disconnectedFromServer(e) { + if (e.detail.clean) { + status("Disconnected"); + } else { + status("Something went wrong, connection is closed"); } - function credentials(e) { - var html; + } - var form = document.createElement('form'); - form.innerHTML = '<label></label>'; - form.innerHTML += '<input type=password size=10 id="password_input">'; - form.onsubmit = setPassword; + // When this function is called, the server requires + // credentials to authenticate + function credentialsAreRequired(e) { + const password = prompt("Password Required:"); + rfb.sendCredentials({ password: password }); + } - // bypass status() because it sets text content - document.getElementById('noVNC_status_bar').setAttribute("class", "noVNC_status_warn"); - document.getElementById('noVNC_status').innerHTML = ''; - document.getElementById('noVNC_status').appendChild(form); - document.getElementById('noVNC_status').querySelector('label').textContent = 'Password Required: '; - } - function setPassword() { - rfb.sendCredentials({ password: document.getElementById('password_input').value }); - return false; - } - function fullscreen() { - if (document.fullscreenElement || // alternative standard method - document.mozFullScreenElement || // currently working methods - document.webkitFullscreenElement || - document.msFullscreenElement) { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.webkitExitFullscreen) { - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - document.msExitFullscreen(); - } - } else { - if (document.documentElement.requestFullscreen) { - document.documentElement.requestFullscreen(); - } else if (document.documentElement.mozRequestFullScreen) { - document.documentElement.mozRequestFullScreen(); - } else if (document.documentElement.webkitRequestFullscreen) { - document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); - } else if (document.body.msRequestFullscreen) { - document.body.msRequestFullscreen(); - } + // When this function is called we have received + // a desktop name from the server + function updateDesktopName(e) { + desktopName = e.detail.name; + } + + // Since most operating systems will catch Ctrl+Alt+Del + // before they get a chance to be intercepted by the browser, + // we provide a way to emulate this key sequence. + function sendCtrlAltDel() { + rfb.sendCtrlAltDel(); + return false; + } + + function fullscreen() { + if (document.fullscreenElement || // alternative standard method + document.mozFullScreenElement || // currently working methods + document.webkitFullscreenElement || + document.msFullscreenElement) { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); } - return false; - } - function sendCtrlAltFN(f) { - rfb.sendCtrlAltFN(f); - return false; - } - function sendCtrlAltDel() { - rfb.sendCtrlAltDel(); - return false; - } - function machineShutdown() { - rfb.machineShutdown(); - return false; - } - function machineReboot() { - rfb.machineReboot(); - return false; - } - function machineReset() { - rfb.machineReset(); - return false; - } - function status(text, level) { - switch (level) { - case 'normal': - case 'warn': - case 'error': - break; - default: - level = "warn"; - } - document.getElementById('noVNC_status_bar').className = "noVNC_status_" + level; - document.getElementById('noVNC_status').textContent = text; - } - - function connected(e) { - document.getElementById('sendCtrlAltDelButton').disabled = false; - if (WebUtil.getConfigVar('encrypt', (window.location.protocol === "https:"))) { - status("Connected (encrypted) to " + desktopName, "normal"); - } else { - status("Connected (unencrypted) to " + desktopName, "normal"); + } else { + if (document.documentElement.requestFullscreen) { + document.documentElement.requestFullscreen(); + } else if (document.documentElement.mozRequestFullScreen) { + document.documentElement.mozRequestFullScreen(); + } else if (document.documentElement.webkitRequestFullscreen) { + document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else if (document.body.msRequestFullscreen) { + document.body.msRequestFullscreen(); } } + return false; + } + function sendCtrlAltFN(f) { + rfb.sendCtrlAltFN(f); + return false; + } + function machineShutdown() { + rfb.machineShutdown(); + return false; + } + function machineReboot() { + rfb.machineReboot(); + return false; + } + function machineReset() { + rfb.machineReset(); + return false; + } - function disconnected(e) { - document.getElementById('sendCtrlAltDelButton').disabled = true; - updatePowerButtons(); - if (e.detail.clean) { - status("Disconnected", "normal"); - } else { - status("Something went wrong, connection is closed", "error"); - } + // Show a status text in the top bar + function status(text) { + document.getElementById('noVNC_status').textContent = text; + } + + // This function extracts the value of one variable from the + // query string. If the variable isn't defined in the URL + // it returns the default value instead. + function readQueryVariable(name, defaultValue) { + // A URL with a query parameter can look like this: + // https://www.example.com?myqueryparam=myvalue + // + // Note that we use location.href instead of location.search + // because Firefox < 53 has a bug w.r.t location.search + const re = new RegExp('.*[?&]' + name + '=([^&#]*)'), + match = document.location.href.match(re); + + if (match) { + // We have to decode the URL since want the cleartext value + return decodeURIComponent(match[1]); } - function updatePowerButtons() { - var powerbuttons; - powerbuttons = document.getElementById('noVNC_power_buttons'); - if (rfb.capabilities.power) { - powerbuttons.className= "noVNC_shown"; - } else { - powerbuttons.className = "noVNC_hidden"; - } - } + return defaultValue; + } - document.getElementById('sendCtrlAltDelButton').onclick = sendCtrlAltDel; - document.getElementById('machineShutdownButton').onclick = machineShutdown; - document.getElementById('machineRebootButton').onclick = machineReboot; - document.getElementById('machineResetButton').onclick = machineReset; - document.getElementById('fullscreen_button').onclick = fullscreen; + document.getElementById('sendCtrlAltDelButton').onclick = sendCtrlAltDel; + document.getElementById('machineShutdownButton').onclick = machineShutdown; + document.getElementById('machineRebootButton').onclick = machineReboot; + document.getElementById('machineResetButton').onclick = machineReset; + document.getElementById('fullscreen_button').onclick = fullscreen; - document.getElementById('ctrlaltdel').addEventListener('click', sendCtrlAltDel); - document.getElementById('ctrlaltf1').addEventListener('click', function(){sendCtrlAltFN(0);}); - document.getElementById('ctrlaltf2').addEventListener('click', function(){sendCtrlAltFN(1);}); - document.getElementById('ctrlaltf3').addEventListener('click', function(){sendCtrlAltFN(2);}); - document.getElementById('ctrlaltf4').addEventListener('click', function(){sendCtrlAltFN(3);}); - document.getElementById('ctrlaltf5').addEventListener('click', function(){sendCtrlAltFN(4);}); - document.getElementById('ctrlaltf6').addEventListener('click', function(){sendCtrlAltFN(5);}); - document.getElementById('ctrlaltf7').addEventListener('click', function(){sendCtrlAltFN(6);}); - document.getElementById('ctrlaltf8').addEventListener('click', function(){sendCtrlAltFN(7);}); - document.getElementById('ctrlaltf9').addEventListener('click', function(){sendCtrlAltFN(8);}); - document.getElementById('ctrlaltf10').addEventListener('click', function(){sendCtrlAltFN(9);}); - document.getElementById('ctrlaltf11').addEventListener('click', function(){sendCtrlAltFN(10);}); - document.getElementById('ctrlaltf12').addEventListener('click', function(){sendCtrlAltFN(11);}); + document.getElementById('ctrlaltdel').addEventListener('click', sendCtrlAltDel); + document.getElementById('ctrlaltf1').addEventListener('click', function () { sendCtrlAltFN(0); }); + document.getElementById('ctrlaltf2').addEventListener('click', function () { sendCtrlAltFN(1); }); + document.getElementById('ctrlaltf3').addEventListener('click', function () { sendCtrlAltFN(2); }); + document.getElementById('ctrlaltf4').addEventListener('click', function () { sendCtrlAltFN(3); }); + document.getElementById('ctrlaltf5').addEventListener('click', function () { sendCtrlAltFN(4); }); + document.getElementById('ctrlaltf6').addEventListener('click', function () { sendCtrlAltFN(5); }); + document.getElementById('ctrlaltf7').addEventListener('click', function () { sendCtrlAltFN(6); }); + document.getElementById('ctrlaltf8').addEventListener('click', function () { sendCtrlAltFN(7); }); + document.getElementById('ctrlaltf9').addEventListener('click', function () { sendCtrlAltFN(8); }); + document.getElementById('ctrlaltf10').addEventListener('click', function () { sendCtrlAltFN(9); }); + document.getElementById('ctrlaltf11').addEventListener('click', function () { sendCtrlAltFN(10); }); + document.getElementById('ctrlaltf12').addEventListener('click', function () { sendCtrlAltFN(11); }); - WebUtil.init_logging(WebUtil.getConfigVar('logging', 'warn')); - document.title = WebUtil.getConfigVar('title', 'noVNC'); - // By default, use the host and port of server that served this file - //var host = WebUtil.getConfigVar('host', window.location.hostname); - //var port = WebUtil.getConfigVar('port', window.location.port); - var host = '{{ ws_host }}'; - var port = '{{ ws_port }}'; + // Read parameters specified in the URL query string + // By default, use the host and port of server that served this file + const host = readQueryVariable('host', '{{ ws_host }}'); + let port = readQueryVariable('port', '{{ ws_port }}'); + const password = readQueryVariable('password'); + const path = readQueryVariable('path', 'websockify'); - // if port == 80 (or 443) then it won't be present and should be - // set manually - if (!port) { - if (window.location.protocol.substring(0,5) == 'https') { - port = 443; - } - else if (window.location.protocol.substring(0,4) == 'http') { - port = 80; - } - } - //var password = WebUtil.getConfigVar('password', ''); - var password = '{{ console_passwd }}'; + // | | | | | | + // | | | Connect | | | + // v v v v v v - var path = WebUtil.getConfigVar('path', 'websockify'); + status("Connecting"); - // If a token variable is passed in, set the parameter in a cookie. - // This is used by nova-novncproxy. - var token = WebUtil.getConfigVar('token', null); - if (token) { - // if token is already present in the path we should use it - path = WebUtil.injectParamIfMissing(path, "token", token); + // Build the websocket URL used to connect + let url; + if (window.location.protocol === "https:") { + url = 'wss'; + } else { + url = 'ws'; + } + url += '://' + host; + if (port) { + url += ':' + port; + } + url += '/' + path; - WebUtil.createCookie('token', token, 1) - } + // Creating a new RFB object will start a new connection + rfb = new RFB(document.getElementById('noVNC_container'), url, + { credentials: { password: password } }); - (function() { + // Add listeners to important events from the RFB module + rfb.addEventListener("connect", connectedToServer); + rfb.addEventListener("disconnect", disconnectedFromServer); + rfb.addEventListener("credentialsrequired", credentialsAreRequired); + rfb.addEventListener("desktopname", updateDesktopName); + rfb.addEventListener("capabilities", function () { updatePowerButtons(); }); - status("Connecting", "normal"); + // Set parameters that can be changed on an active connection + rfb.viewOnly = readQueryVariable('view_only', {{ view_only }}); + rfb.scaleViewport = readQueryVariable('scale', {{ scale }}); + rfb.resizeSession = readQueryVariable('resize', {{ resize_session }}); + rfb.clipViewport = readQueryVariable('clip_viewport', {{ clip_viewport }}); - if ((!host) || (!port)) { - status('Must specify host and port in URL', 'error'); - } - - var url; - - if (WebUtil.getConfigVar('encrypt', (window.location.protocol === "https:"))) { - url = 'wss'; - } else { - url = 'ws'; - } - - url += '://' + host; - if(port) { - url += ':' + port; - } - url += '/' + path; - - //rfb = new RFB(document.body, url, - // { repeaterID: WebUtil.getConfigVar('repeaterID', ''), - // shared: WebUtil.getConfigVar('shared', true), - // credentials: { password: password } }); - rfb = new RFB(document.getElementById('noVNC_container'), url, - { repeaterID: WebUtil.getConfigVar('repeaterID', ''), - shared: WebUtil.getConfigVar('shared', true), - credentials: { password: password } }); - - rfb.viewOnly = WebUtil.getConfigVar('view_only', false); - rfb.addEventListener("connect", connected); - rfb.addEventListener("disconnect", disconnected); - rfb.addEventListener("capabilities", function () { updatePowerButtons(); }); - rfb.addEventListener("credentialsrequired", credentials); - rfb.addEventListener("desktopname", updateDesktopName); - rfb.scaleViewport = WebUtil.getConfigVar('scale', false); - rfb.resizeSession = WebUtil.getConfigVar('resize', false); - })(); - </script> +</script> {% endblock %} - {% block content %} - <div id="noVNC_status_bar"> - <div id="noVNC_left_dummy_elem"></div> - <div id="noVNC_status">{% trans 'Loading' %}</div> - <div id="noVNC_buttons"> - <input type="button" value="Send CtrlAltDel" id="sendCtrlAltDelButton" class="noVNC_shown"> - <span id="noVNC_power_buttons" class="noVNC_hidden"> - <input type=button value="Shutdown" id="machineShutdownButton"> - <input type=button value="Reboot" id="machineRebootButton"> - <input type=button value="Reset" id="machineResetButton"> - </span> - </div> +<div id="noVNC_status_bar"> + <div id="noVNC_left_dummy_elem"></div> + <div id="noVNC_status">{% trans 'Loading' %}</div> + <div id="noVNC_buttons"> + <input type="button" value="Send CtrlAltDel" id="sendCtrlAltDelButton" class="noVNC_shown"> + <span id="noVNC_power_buttons" class="noVNC_hidden"> + <input type="button" value="Shutdown" id="machineShutdownButton"> + <input type="button" value="Reboot" id="machineRebootButton"> + <input type="button" value="Reset" id="machineResetButton"> + </span> </div> - <div id='noVNC_container'></div> -{% endblock %} +</div> +<div id="noVNC_container"> + <!-- This is where the remote screen will appear --> +</div> +{% endblock %} \ No newline at end of file diff --git a/console/views.py b/console/views.py index 27d864f..e7fc64a 100644 --- a/console/views.py +++ b/console/views.py @@ -16,6 +16,10 @@ def console(request): if request.method == 'GET': token = request.GET.get('token', '') view_type = request.GET.get('view', 'lite') + view_only = request.GET.get('view_only', 0) + scale = request.GET.get('scale', 0) + resize_session = request.GET.get('resize_session', 0) + clip_viewport = request.GET.get('clip_viewport', 0) try: temptoken = token.split('-', 1) diff --git a/static/js/novnc/app/styles/lite.css b/static/js/novnc/app/styles/lite.css index a6a9218..39d45ef 100755 --- a/static/js/novnc/app/styles/lite.css +++ b/static/js/novnc/app/styles/lite.css @@ -10,7 +10,7 @@ body { margin:0; background-color:#313131; border-bottom-right-radius: 800px 600px; - height:100%; + height: 100%; display: flex; flex-direction: column; } diff --git a/static/js/spice-html5/inputs.js b/static/js/spice-html5/inputs.js index c6fd3f7..ff9f3e6 100755 --- a/static/js/spice-html5/inputs.js +++ b/static/js/spice-html5/inputs.js @@ -38,8 +38,7 @@ var Meta_state = -1; ** SpiceInputsConn ** Drive the Spice Inputs channel (e.g. mouse + keyboard) **--------------------------------------------------------------------------*/ -function SpiceInputsConn() -{ +function SpiceInputsConn() { SpiceConn.apply(this, arguments); this.mousex = undefined; @@ -49,26 +48,22 @@ function SpiceInputsConn() } SpiceInputsConn.prototype = Object.create(SpiceConn.prototype); -SpiceInputsConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == Constants.SPICE_MSG_INPUTS_INIT) - { +SpiceInputsConn.prototype.process_channel_message = function (msg) { + if (msg.type == Constants.SPICE_MSG_INPUTS_INIT) { var inputs_init = new Messages.SpiceMsgInputsInit(msg.data); this.keyboard_modifiers = inputs_init.keyboard_modifiers; DEBUG > 1 && console.log("MsgInputsInit - modifier " + this.keyboard_modifiers); // FIXME - We don't do anything with the keyboard modifiers... return true; } - if (msg.type == Constants.SPICE_MSG_INPUTS_KEY_MODIFIERS) - { + if (msg.type == Constants.SPICE_MSG_INPUTS_KEY_MODIFIERS) { var key = new Messages.SpiceMsgInputsKeyModifiers(msg.data); this.keyboard_modifiers = key.keyboard_modifiers; DEBUG > 1 && console.log("MsgInputsKeyModifiers - modifier " + this.keyboard_modifiers); // FIXME - We don't do anything with the keyboard modifiers... return true; } - if (msg.type == Constants.SPICE_MSG_INPUTS_MOUSE_MOTION_ACK) - { + if (msg.type == Constants.SPICE_MSG_INPUTS_MOUSE_MOTION_ACK) { DEBUG > 1 && console.log("mouse motion ack"); this.waiting_for_ack -= Constants.SPICE_INPUT_MOTION_ACK_BUNCH; return true; @@ -78,35 +73,28 @@ SpiceInputsConn.prototype.process_channel_message = function(msg) -function handle_mousemove(e) -{ +function handle_mousemove(e) { var msg = new Messages.SpiceMiniData(); var move; - if (this.sc.mouse_mode == Constants.SPICE_MOUSE_MODE_CLIENT) - { + if (this.sc.mouse_mode == Constants.SPICE_MOUSE_MODE_CLIENT) { move = new Messages.SpiceMsgcMousePosition(this.sc, e) msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_POSITION, move); } - else - { + else { move = new Messages.SpiceMsgcMouseMotion(this.sc, e) msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_MOTION, move); } - if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") - { - if (this.sc.inputs.waiting_for_ack < (2 * Constants.SPICE_INPUT_MOTION_ACK_BUNCH)) - { + if (this.sc && this.sc.inputs && this.sc.inputs.state === "ready") { + if (this.sc.inputs.waiting_for_ack < (2 * Constants.SPICE_INPUT_MOTION_ACK_BUNCH)) { this.sc.inputs.send_msg(msg); this.sc.inputs.waiting_for_ack++; } - else - { + else { DEBUG > 0 && this.sc.log_info("Discarding mouse motion"); } } - if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) - { + if (this.sc && this.sc.cursor && this.sc.cursor.spice_simulated_cursor) { this.sc.cursor.spice_simulated_cursor.style.display = 'block'; this.sc.cursor.spice_simulated_cursor.style.left = e.pageX - this.sc.cursor.spice_simulated_cursor.spice_hot_x + 'px'; this.sc.cursor.spice_simulated_cursor.style.top = e.pageY - this.sc.cursor.spice_simulated_cursor.spice_hot_y + 'px'; @@ -115,8 +103,7 @@ function handle_mousemove(e) } -function handle_mousedown(e) -{ +function handle_mousedown(e) { var press = new Messages.SpiceMsgcMousePress(this.sc, e) var msg = new Messages.SpiceMiniData(); msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_PRESS, press); @@ -126,14 +113,12 @@ function handle_mousedown(e) e.preventDefault(); } -function handle_contextmenu(e) -{ +function handle_contextmenu(e) { e.preventDefault(); return false; } -function handle_mouseup(e) -{ +function handle_mouseup(e) { var release = new Messages.SpiceMsgcMouseRelease(this.sc, e) var msg = new Messages.SpiceMiniData(); msg.build_msg(Constants.SPICE_MSGC_INPUTS_MOUSE_RELEASE, release); @@ -143,8 +128,7 @@ function handle_mouseup(e) e.preventDefault(); } -function handle_mousewheel(e) -{ +function handle_mousewheel(e) { var press = new Messages.SpiceMsgcMousePress; var release = new Messages.SpiceMsgcMouseRelease; if (e.deltaY < 0) @@ -166,8 +150,7 @@ function handle_mousewheel(e) e.preventDefault(); } -function handle_keydown(e) -{ +function handle_keydown(e) { var key = new Messages.SpiceMsgcKeyDown(e) var msg = new Messages.SpiceMiniData(); check_and_update_modifiers(e, key.code, this.sc); @@ -178,8 +161,7 @@ function handle_keydown(e) e.preventDefault(); } -function handle_keyup(e) -{ +function handle_keyup(e) { var key = new Messages.SpiceMsgcKeyUp(e) var msg = new Messages.SpiceMiniData(); check_and_update_modifiers(e, key.code, this.sc); @@ -190,9 +172,8 @@ function handle_keyup(e) e.preventDefault(); } -function sendCtrlAltDel(sc) -{ - if (sc && sc.inputs && sc.inputs.state === "ready"){ +function sendCtrlAltDel(sc) { + if (sc && sc.inputs && sc.inputs.state === "ready") { var key = new Messages.SpiceMsgcKeyDown(); var msg = new Messages.SpiceMiniData(); @@ -205,22 +186,55 @@ function sendCtrlAltDel(sc) msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key); sc.inputs.send_msg(msg); - if(Ctrl_state == false) update_modifier(false, KeyNames.KEY_LCtrl, sc); - if(Alt_state == false) update_modifier(false, KeyNames.KEY_Alt, sc); + if (Ctrl_state == false) update_modifier(false, KeyNames.KEY_LCtrl, sc); + if (Alt_state == false) update_modifier(false, KeyNames.KEY_Alt, sc); } } -function update_modifier(state, code, sc) -{ +function sendCtrlAltFN(sc, f) { + if (sc && sc.inputs && sc.inputs.state === "ready") { + var keys_code = [ + KeyNames.KEY_F1, + KeyNames.KEY_F2, + KeyNames.KEY_F3, + KeyNames.KEY_F4, + KeyNames.KEY_F5, + KeyNames.KEY_F6, + KeyNames.KEY_F7, + KeyNames.KEY_F8, + KeyNames.KEY_F9, + KeyNames.KEY_F10, + KeyNames.KEY_F11, + KeyNames.KEY_F12]; + + if (keys_code[f] == undefined) { + return; + } + var key = new Messages.SpiceMsgcKeyDown(); + var msg = new Messages.SpiceMiniData(); + + update_modifier(true, KeyNames.KEY_LCtrl, sc); + update_modifier(true, KeyNames.KEY_Alt, sc); + + key.code = keys_code[f]; + msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_DOWN, key); + sc.inputs.send_msg(msg); + msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key); + sc.inputs.send_msg(msg); + + if (Ctrl_state == false) update_modifier(false, KeyNames.KEY_LCtrl, sc); + if (Alt_state == false) update_modifier(false, KeyNames.KEY_Alt, sc); + } +} + +function update_modifier(state, code, sc) { var msg = new Messages.SpiceMiniData(); - if (!state) - { + if (!state) { var key = new Messages.SpiceMsgcKeyUp() - key.code =(0x80|code); + key.code = (0x80 | code); msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_UP, key); } - else - { + else { var key = new Messages.SpiceMsgcKeyDown() key.code = code; msg.build_msg(Constants.SPICE_MSGC_INPUTS_KEY_DOWN, key); @@ -229,10 +243,8 @@ function update_modifier(state, code, sc) sc.inputs.send_msg(msg); } -function check_and_update_modifiers(e, code, sc) -{ - if (Shift_state === -1) - { +function check_and_update_modifiers(e, code, sc) { + if (Shift_state === -1) { Shift_state = e.shiftKey; Ctrl_state = e.ctrlKey; Alt_state = e.altKey; @@ -247,37 +259,32 @@ function check_and_update_modifiers(e, code, sc) Ctrl_state = true; else if (code === 0xE0B5) Meta_state = true; - else if (code === (0x80|KeyNames.KEY_ShiftL)) + else if (code === (0x80 | KeyNames.KEY_ShiftL)) Shift_state = false; - else if (code === (0x80|KeyNames.KEY_Alt)) + else if (code === (0x80 | KeyNames.KEY_Alt)) Alt_state = false; - else if (code === (0x80|KeyNames.KEY_LCtrl)) + else if (code === (0x80 | KeyNames.KEY_LCtrl)) Ctrl_state = false; - else if (code === (0x80|0xE0B5)) + else if (code === (0x80 | 0xE0B5)) Meta_state = false; - if (sc && sc.inputs && sc.inputs.state === "ready") - { - if (Shift_state != e.shiftKey) - { + if (sc && sc.inputs && sc.inputs.state === "ready") { + if (Shift_state != e.shiftKey) { console.log("Shift state out of sync"); update_modifier(e.shiftKey, KeyNames.KEY_ShiftL, sc); Shift_state = e.shiftKey; } - if (Alt_state != e.altKey) - { + if (Alt_state != e.altKey) { console.log("Alt state out of sync"); update_modifier(e.altKey, KeyNames.KEY_Alt, sc); Alt_state = e.altKey; } - if (Ctrl_state != e.ctrlKey) - { + if (Ctrl_state != e.ctrlKey) { console.log("Ctrl state out of sync"); update_modifier(e.ctrlKey, KeyNames.KEY_LCtrl, sc); Ctrl_state = e.ctrlKey; } - if (Meta_state != e.metaKey) - { + if (Meta_state != e.metaKey) { console.log("Meta state out of sync"); update_modifier(e.metaKey, 0xE0B5, sc); Meta_state = e.metaKey; @@ -286,13 +293,14 @@ function check_and_update_modifiers(e, code, sc) } export { - SpiceInputsConn, - handle_mousemove, - handle_mousedown, - handle_contextmenu, - handle_mouseup, - handle_mousewheel, - handle_keydown, - handle_keyup, - sendCtrlAltDel, + SpiceInputsConn, + handle_mousemove, + handle_mousedown, + handle_contextmenu, + handle_mouseup, + handle_mousewheel, + handle_keydown, + handle_keyup, + sendCtrlAltDel, + sendCtrlAltFN }; diff --git a/static/js/spice-html5/main.js b/static/js/spice-html5/main.js index 4a37b55..eac6f57 100755 --- a/static/js/spice-html5/main.js +++ b/static/js/spice-html5/main.js @@ -24,7 +24,7 @@ import { SpiceCursorConn } from './cursor.js'; import { SpiceConn } from './spiceconn.js'; import { DEBUG } from './utils.js'; import { SpiceFileXferTask } from './filexfer.js'; -import { SpiceInputsConn, sendCtrlAltDel } from './inputs.js'; +import { SpiceInputsConn, sendCtrlAltDel, sendCtrlAltFN } from './inputs.js'; import { SpiceDisplayConn } from './display.js'; import { SpicePlaybackConn } from './playback.js'; import { SpicePortConn } from './port.js'; @@ -63,8 +63,7 @@ import { resize_helper, handle_resize } from './resize.js'; ** browser, including WebSocket and WebSocket.binaryType == arraybuffer ** **--------------------------------------------------------------------------*/ -function SpiceMainConn() -{ +function SpiceMainConn() { if (typeof WebSocket === "undefined") throw new Error("WebSocket unavailable. You need to use a different browser."); @@ -78,47 +77,42 @@ function SpiceMainConn() } SpiceMainConn.prototype = Object.create(SpiceConn.prototype); -SpiceMainConn.prototype.process_channel_message = function(msg) -{ - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN) - { +SpiceMainConn.prototype.process_channel_message = function (msg) { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN) { this.known_unimplemented(msg.type, "Main Migrate Begin"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_CANCEL) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_CANCEL) { this.known_unimplemented(msg.type, "Main Migrate Cancel"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_INIT) - { + if (msg.type == Constants.SPICE_MSG_MAIN_INIT) { this.log_info("Connected to " + this.ws.url); this.report_success("Connected") this.main_init = new Messages.SpiceMsgMainInit(msg.data); this.connection_id = this.main_init.session_id; this.agent_tokens = this.main_init.agent_tokens; - if (DEBUG > 0) - { + if (DEBUG > 0) { // FIXME - there is a lot here we don't handle; mouse modes, agent, // ram_hint, multi_media_time - this.log_info("session id " + this.main_init.session_id + - " ; display_channels_hint " + this.main_init.display_channels_hint + - " ; supported_mouse_modes " + this.main_init.supported_mouse_modes + - " ; current_mouse_mode " + this.main_init.current_mouse_mode + - " ; agent_connected " + this.main_init.agent_connected + - " ; agent_tokens " + this.main_init.agent_tokens + - " ; multi_media_time " + this.main_init.multi_media_time + - " ; ram_hint " + this.main_init.ram_hint); + this.log_info("session id " + this.main_init.session_id + + " ; display_channels_hint " + this.main_init.display_channels_hint + + " ; supported_mouse_modes " + this.main_init.supported_mouse_modes + + " ; current_mouse_mode " + this.main_init.current_mouse_mode + + " ; agent_connected " + this.main_init.agent_connected + + " ; agent_tokens " + this.main_init.agent_tokens + + " ; multi_media_time " + this.main_init.multi_media_time + + " ; ram_hint " + this.main_init.ram_hint); } this.our_mm_time = Date.now(); this.mm_time = this.main_init.multi_media_time; this.handle_mouse_mode(this.main_init.current_mouse_mode, - this.main_init.supported_mouse_modes); + this.main_init.supported_mouse_modes); if (this.main_init.agent_connected) this.connect_agent(); @@ -130,45 +124,39 @@ SpiceMainConn.prototype.process_channel_message = function(msg) return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MOUSE_MODE) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MOUSE_MODE) { var mode = new Messages.SpiceMsgMainMouseMode(msg.data); DEBUG > 0 && this.log_info("Mouse supported modes " + mode.supported_modes + "; current " + mode.current_mode); this.handle_mouse_mode(mode.current_mode, mode.supported_modes); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MULTI_MEDIA_TIME) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MULTI_MEDIA_TIME) { this.known_unimplemented(msg.type, "Main Multi Media Time"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_CHANNELS_LIST) - { + if (msg.type == Constants.SPICE_MSG_MAIN_CHANNELS_LIST) { var i; var chans; DEBUG > 0 && console.log("channels"); chans = new Messages.SpiceMsgChannels(msg.data); - for (i = 0; i < chans.channels.length; i++) - { + for (i = 0; i < chans.channels.length; i++) { var conn = { - uri: this.ws.url, - parent: this, - connection_id : this.connection_id, - type : chans.channels[i].type, - chan_id : chans.channels[i].id - }; - if (chans.channels[i].type == Constants.SPICE_CHANNEL_DISPLAY) - { + uri: this.ws.url, + parent: this, + connection_id: this.connection_id, + type: chans.channels[i].type, + chan_id: chans.channels[i].id + }; + if (chans.channels[i].type == Constants.SPICE_CHANNEL_DISPLAY) { if (chans.channels[i].id == 0) { this.display = new SpiceDisplayConn(conn); } else { this.log_warn("The spice-html5 client does not handle multiple heads."); } } - else if (chans.channels[i].type == Constants.SPICE_CHANNEL_INPUTS) - { + else if (chans.channels[i].type == Constants.SPICE_CHANNEL_INPUTS) { this.inputs = new SpiceInputsConn(conn); this.inputs.mouse_mode = this.mouse_mode; } @@ -178,9 +166,8 @@ SpiceMainConn.prototype.process_channel_message = function(msg) this.cursor = new SpicePlaybackConn(conn); else if (chans.channels[i].type == Constants.SPICE_CHANNEL_PORT) this.ports.push(new SpicePortConn(conn)); - else - { - if (! ("extra_channels" in this)) + else { + if (!("extra_channels" in this)) this.extra_channels = []; this.extra_channels[i] = new SpiceConn(conn); this.log_err("Channel type " + this.extra_channels[i].channel_type() + " not implemented"); @@ -191,29 +178,25 @@ SpiceMainConn.prototype.process_channel_message = function(msg) return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED) - { + if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED) { this.connect_agent(); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS) - { + if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_CONNECTED_TOKENS) { var connected_tokens = new Messages.SpiceMsgMainAgentTokens(msg.data); this.agent_tokens = connected_tokens.num_tokens; this.connect_agent(); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_TOKEN) - { + if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_TOKEN) { var remaining_tokens, tokens = new Messages.SpiceMsgMainAgentTokens(msg.data); this.agent_tokens += tokens.num_tokens; this.send_agent_message_queue(); remaining_tokens = this.agent_tokens; - while (remaining_tokens > 0 && this.file_xfer_read_queue.length > 0) - { + while (remaining_tokens > 0 && this.file_xfer_read_queue.length > 0) { var xfer_task = this.file_xfer_read_queue.shift(); this.file_xfer_read(xfer_task, xfer_task.read_bytes); remaining_tokens--; @@ -221,24 +204,20 @@ SpiceMainConn.prototype.process_channel_message = function(msg) return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DISCONNECTED) - { + if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DISCONNECTED) { this.agent_connected = false; return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DATA) - { + if (msg.type == Constants.SPICE_MSG_MAIN_AGENT_DATA) { var agent_data = new Messages.SpiceMsgMainAgentData(msg.data); - if (agent_data.type == Constants.VD_AGENT_ANNOUNCE_CAPABILITIES) - { + if (agent_data.type == Constants.VD_AGENT_ANNOUNCE_CAPABILITIES) { var agent_caps = new Messages.VDAgentAnnounceCapabilities(agent_data.data); if (agent_caps.request) this.announce_agent_capabilities(0); return true; } - else if (agent_data.type == Constants.VD_AGENT_FILE_XFER_STATUS) - { + else if (agent_data.type == Constants.VD_AGENT_FILE_XFER_STATUS) { this.handle_file_xfer_status(new Messages.VDAgentFileXferStatusMessage(agent_data.data)); return true; } @@ -246,44 +225,37 @@ SpiceMainConn.prototype.process_channel_message = function(msg) return false; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST) { this.known_unimplemented(msg.type, "Main Migrate Switch Host"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_END) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_END) { this.known_unimplemented(msg.type, "Main Migrate End"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_NAME) - { + if (msg.type == Constants.SPICE_MSG_MAIN_NAME) { this.known_unimplemented(msg.type, "Main Name"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_UUID) - { + if (msg.type == Constants.SPICE_MSG_MAIN_UUID) { this.known_unimplemented(msg.type, "Main UUID"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_BEGIN_SEAMLESS) { this.known_unimplemented(msg.type, "Main Migrate Begin Seamless"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_ACK) { this.known_unimplemented(msg.type, "Main Migrate Dst Seamless ACK"); return true; } - if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK) - { + if (msg.type == Constants.SPICE_MSG_MAIN_MIGRATE_DST_SEAMLESS_NACK) { this.known_unimplemented(msg.type, "Main Migrate Dst Seamless NACK"); return true; } @@ -291,24 +263,20 @@ SpiceMainConn.prototype.process_channel_message = function(msg) return false; } -SpiceMainConn.prototype.stop = function(msg) -{ +SpiceMainConn.prototype.stop = function (msg) { this.state = "closing"; - if (this.inputs) - { + if (this.inputs) { this.inputs.cleanup(); this.inputs = undefined; } - if (this.cursor) - { + if (this.cursor) { this.cursor.cleanup(); this.cursor = undefined; } - if (this.display) - { + if (this.display) { this.display.cleanup(); this.display.destroy_surfaces(); this.display = undefined; @@ -322,30 +290,26 @@ SpiceMainConn.prototype.stop = function(msg) this.extra_channels = undefined; } -SpiceMainConn.prototype.send_agent_message_queue = function(message) -{ +SpiceMainConn.prototype.send_agent_message_queue = function (message) { if (!this.agent_connected) return; if (message) this.agent_msg_queue.push(message); - while (this.agent_tokens > 0 && this.agent_msg_queue.length > 0) - { + while (this.agent_tokens > 0 && this.agent_msg_queue.length > 0) { var mr = this.agent_msg_queue.shift(); this.send_msg(mr); this.agent_tokens--; } } -SpiceMainConn.prototype.send_agent_message = function(type, message) -{ +SpiceMainConn.prototype.send_agent_message = function (type, message) { var agent_data = new Messages.SpiceMsgcMainAgentData(type, message); var sb = 0, maxsize = Constants.VD_AGENT_MAX_DATA_SIZE - Messages.SpiceMiniData.prototype.buffer_size(); var data = new ArrayBuffer(agent_data.buffer_size()); agent_data.to_buffer(data); - while (sb < agent_data.buffer_size()) - { + while (sb < agent_data.buffer_size()) { var eb = Math.min(sb + maxsize, agent_data.buffer_size()); var mr = new Messages.SpiceMiniData(); mr.type = Constants.SPICE_MSGC_MAIN_AGENT_DATA; @@ -356,22 +320,19 @@ SpiceMainConn.prototype.send_agent_message = function(type, message) } } -SpiceMainConn.prototype.announce_agent_capabilities = function(request) -{ +SpiceMainConn.prototype.announce_agent_capabilities = function (request) { var caps = new Messages.VDAgentAnnounceCapabilities(request, (1 << Constants.VD_AGENT_CAP_MOUSE_STATE) | - (1 << Constants.VD_AGENT_CAP_MONITORS_CONFIG) | - (1 << Constants.VD_AGENT_CAP_REPLY)); + (1 << Constants.VD_AGENT_CAP_MONITORS_CONFIG) | + (1 << Constants.VD_AGENT_CAP_REPLY)); this.send_agent_message(Constants.VD_AGENT_ANNOUNCE_CAPABILITIES, caps); } -SpiceMainConn.prototype.resize_window = function(flags, width, height, depth, x, y) -{ +SpiceMainConn.prototype.resize_window = function (flags, width, height, depth, x, y) { var monitors_config = new Messages.VDAgentMonitorsConfig(flags, width, height, depth, x, y); this.send_agent_message(Constants.VD_AGENT_MONITORS_CONFIG, monitors_config); } -SpiceMainConn.prototype.file_xfer_start = function(file) -{ +SpiceMainConn.prototype.file_xfer_start = function (file) { var task_id, xfer_start, task; task_id = this.file_xfer_task_id++; @@ -382,16 +343,13 @@ SpiceMainConn.prototype.file_xfer_start = function(file) this.send_agent_message(Constants.VD_AGENT_FILE_XFER_START, xfer_start); } -SpiceMainConn.prototype.handle_file_xfer_status = function(file_xfer_status) -{ +SpiceMainConn.prototype.handle_file_xfer_status = function (file_xfer_status) { var xfer_error, xfer_task; - if (!this.file_xfer_tasks[file_xfer_status.id]) - { + if (!this.file_xfer_tasks[file_xfer_status.id]) { return; } xfer_task = this.file_xfer_tasks[file_xfer_status.id]; - switch (file_xfer_status.result) - { + switch (file_xfer_status.result) { case Constants.VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA: this.file_xfer_read(xfer_task); return; @@ -411,8 +369,7 @@ SpiceMainConn.prototype.handle_file_xfer_status = function(file_xfer_status) this.file_xfer_completed(xfer_task, xfer_error) } -SpiceMainConn.prototype.file_xfer_read = function(file_xfer_task, start_byte) -{ +SpiceMainConn.prototype.file_xfer_read = function (file_xfer_task, start_byte) { var FILE_XFER_CHUNK_SIZE = 32 * Constants.VD_AGENT_MAX_DATA_SIZE; var _this = this; var sb, eb; @@ -420,36 +377,32 @@ SpiceMainConn.prototype.file_xfer_read = function(file_xfer_task, start_byte) if (!file_xfer_task || !this.file_xfer_tasks[file_xfer_task.id] || - (start_byte > 0 && start_byte == file_xfer_task.file.size)) - { + (start_byte > 0 && start_byte == file_xfer_task.file.size)) { return; } - if (file_xfer_task.cancelled) - { + if (file_xfer_task.cancelled) { var xfer_status = new Messages.VDAgentFileXferStatusMessage(file_xfer_task.id, - Constants.VD_AGENT_FILE_XFER_STATUS_CANCELLED); + Constants.VD_AGENT_FILE_XFER_STATUS_CANCELLED); this.send_agent_message(Constants.VD_AGENT_FILE_XFER_STATUS, xfer_status); delete this.file_xfer_tasks[file_xfer_task.id]; return; } sb = start_byte || 0, - eb = Math.min(sb + FILE_XFER_CHUNK_SIZE, file_xfer_task.file.size); + eb = Math.min(sb + FILE_XFER_CHUNK_SIZE, file_xfer_task.file.size); - if (!this.agent_tokens) - { + if (!this.agent_tokens) { file_xfer_task.read_bytes = sb; this.file_xfer_read_queue.push(file_xfer_task); return; } reader = new FileReader(); - reader.onload = function(e) - { + reader.onload = function (e) { var xfer_data = new Messages.VDAgentFileXferDataMessage(file_xfer_task.id, - e.target.result.byteLength, - e.target.result); + e.target.result.byteLength, + e.target.result); _this.send_agent_message(Constants.VD_AGENT_FILE_XFER_DATA, xfer_data); _this.file_xfer_read(file_xfer_task, eb); file_xfer_task.update_progressbar(eb); @@ -459,20 +412,18 @@ SpiceMainConn.prototype.file_xfer_read = function(file_xfer_task, start_byte) reader.readAsArrayBuffer(slice); } -SpiceMainConn.prototype.file_xfer_completed = function(file_xfer_task, error) -{ +SpiceMainConn.prototype.file_xfer_completed = function (file_xfer_task, error) { if (error) this.log_err(error); else - this.log_info("transfer of '" + file_xfer_task.file.name +"' was successful"); + this.log_info("transfer of '" + file_xfer_task.file.name + "' was successful"); file_xfer_task.remove_progressbar(); delete this.file_xfer_tasks[file_xfer_task.id]; } -SpiceMainConn.prototype.connect_agent = function() -{ +SpiceMainConn.prototype.connect_agent = function () { this.agent_connected = true; var agent_start = new Messages.SpiceMsgcMainAgentStart(~0); @@ -487,11 +438,9 @@ SpiceMainConn.prototype.connect_agent = function() } -SpiceMainConn.prototype.handle_mouse_mode = function(current, supported) -{ +SpiceMainConn.prototype.handle_mouse_mode = function (current, supported) { this.mouse_mode = current; - if (current != Constants.SPICE_MOUSE_MODE_CLIENT && (supported & Constants.SPICE_MOUSE_MODE_CLIENT)) - { + if (current != Constants.SPICE_MOUSE_MODE_CLIENT && (supported & Constants.SPICE_MOUSE_MODE_CLIENT)) { var mode_request = new Messages.SpiceMsgcMainMouseModeRequest(Constants.SPICE_MOUSE_MODE_CLIENT); var mr = new Messages.SpiceMiniData(); mr.build_msg(Constants.SPICE_MSGC_MAIN_MOUSE_MODE_REQUEST, mode_request); @@ -503,17 +452,17 @@ SpiceMainConn.prototype.handle_mouse_mode = function(current, supported) } /* Shift current time to attempt to get a time matching that of the server */ -SpiceMainConn.prototype.relative_now = function() -{ +SpiceMainConn.prototype.relative_now = function () { var ret = (Date.now() - this.our_mm_time) + this.mm_time; return ret; } export { - SpiceMainConn, - handle_file_dragover, - handle_file_drop, - resize_helper, - handle_resize, - sendCtrlAltDel, + SpiceMainConn, + handle_file_dragover, + handle_file_drop, + resize_helper, + handle_resize, + sendCtrlAltDel, + sendCtrlAltFN, }; diff --git a/static/js/spice-html5/spice.css b/static/js/spice-html5/spice.css index 968ba16..2ffe5e6 100755 --- a/static/js/spice-html5/spice.css +++ b/static/js/spice-html5/spice.css @@ -63,7 +63,6 @@ body #spice-area { - height: 100%; width: 95%; padding: 0; margin-left: auto; @@ -74,13 +73,13 @@ body box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.2); -moz-border-radius: 10px; -webkit-border-radius: 10px; - border-radius: 10px; + border-radius: 1px; } .spice-screen { min-height: 600px; height: 100%; - margin: 10px; + margin: 5px; padding: 0; background-color: #333333; }