<build>
<plugins>
+
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<target>1.6</target>
</configuration>
</plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <overlays>
+ <overlay>
+ <groupId>net.sourceforge.guacamole</groupId>
+ <artifactId>guacamole-common-js</artifactId>
+ <type>zip</type>
+ </overlay>
+ </overlays>
+ </configuration>
+ </plugin>
+
</plugins>
<extensions>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>net.sourceforge.guacamole</groupId>
+ <artifactId>guacamole-common-js</artifactId>
+ <version>0.3.0-SNAPSHOT</version>
+ <type>zip</type>
+ <scope>runtime</scope>
+ </dependency>
+
</dependencies>
<repositories>
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-.guac-display.guac-loading {
- border: 1px dotted gray;
- background-image: url('../images/spinner92.gif');
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.guac-display.guac-error {
- border: 1px dotted red;
- background-image: url('../images/noimage92.png');
- background-position: center;
- background-repeat: no-repeat;
-}
-
-.guac-hide-cursor {
- cursor: url('../images/mouse/dot.gif'),url('../images/mouse/blank.cur'),default;
-}
-
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-function GuacamoleClient(display) {
-
- var STATE_IDLE = 0;
- var STATE_CONNECTING = 1;
- var STATE_WAITING = 2;
- var STATE_CONNECTED = 3;
- var STATE_DISCONNECTING = 4;
- var STATE_DISCONNECTED = 5;
-
- var currentState = STATE_IDLE;
- var stateChangeHandler = null;
-
- function setState(state) {
- if (state != currentState) {
- currentState = state;
- if (stateChangeHandler)
- stateChangeHandler(currentState);
- }
- }
-
- this.setOnStateChangeHandler = function(handler) {
- stateChangeHandler = handler;
- }
-
- function isConnected() {
- return currentState == STATE_CONNECTED
- || currentState == STATE_WAITING;
- }
-
- // Layers
- var background = null;
- var cursor = null;
-
- var cursorImage = null;
- var cursorHotspotX = 0;
- var cursorHotspotY = 0;
-
- // FIXME: Make object. Clean up.
- var cursorRectX = 0;
- var cursorRectY = 0;
- var cursorRectW = 0;
- var cursorRectH = 0;
-
- var cursorHidden = 0;
-
- function redrawCursor() {
-
- // Hide hardware cursor
- if (cursorHidden == 0) {
- display.className += " guac-hide-cursor";
- cursorHidden = 1;
- }
-
- // Erase old cursor
- cursor.clearRect(cursorRectX, cursorRectY, cursorRectW, cursorRectH);
-
- // Update rect
- cursorRectX = mouse.getX() - cursorHotspotX;
- cursorRectY = mouse.getY() - cursorHotspotY;
- cursorRectW = cursorImage.width;
- cursorRectH = cursorImage.height;
-
- // Draw new cursor
- cursor.drawImage(cursorRectX, cursorRectY, cursorImage);
- }
-
-
-
-
- /*****************************************/
- /*** Keyboard ***/
- /*****************************************/
-
- var keyboard = new GuacamoleKeyboard(document);
-
- this.disableKeyboard = function() {
- keyboard.setKeyPressedHandler(null);
- keyboard.setKeyReleasedHandler(null);
- };
-
- this.enableKeyboard = function() {
- keyboard.setKeyPressedHandler(
- function (keysym) {
- sendKeyEvent(1, keysym);
- }
- );
-
- keyboard.setKeyReleasedHandler(
- function (keysym) {
- sendKeyEvent(0, keysym);
- }
- );
- };
-
- // Enable keyboard by default
- this.enableKeyboard();
-
- function sendKeyEvent(pressed, keysym) {
- // Do not send requests if not connected
- if (!isConnected())
- return;
-
- sendMessage("key:" + keysym + "," + pressed + ";");
- }
-
- this.pressKey = function(keysym) {
- sendKeyEvent(1, keysym);
- };
-
- this.releaseKey = function(keysym) {
- sendKeyEvent(0, keysym);
- };
-
-
- /*****************************************/
- /*** Mouse ***/
- /*****************************************/
-
- var mouse = new GuacamoleMouse(display);
- mouse.setButtonPressedHandler(
- function(mouseState) {
- sendMouseState(mouseState);
- }
- );
-
- mouse.setButtonReleasedHandler(
- function(mouseState) {
- sendMouseState(mouseState);
- }
- );
-
- mouse.setMovementHandler(
- function(mouseState) {
-
- // Draw client-side cursor
- if (cursorImage != null) {
- redrawCursor();
- }
-
- sendMouseState(mouseState);
- }
- );
-
-
- function sendMouseState(mouseState) {
-
- // Do not send requests if not connected
- if (!isConnected())
- return;
-
- // Build mask
- var buttonMask = 0;
- if (mouseState.getLeft()) buttonMask |= 1;
- if (mouseState.getMiddle()) buttonMask |= 2;
- if (mouseState.getRight()) buttonMask |= 4;
- if (mouseState.getUp()) buttonMask |= 8;
- if (mouseState.getDown()) buttonMask |= 16;
-
- // Send message
- sendMessage("mouse:" + mouseState.getX() + "," + mouseState.getY() + "," + buttonMask + ";");
- }
-
- var sendingMessages = 0;
- var outputMessageBuffer = "";
-
- function sendMessage(message) {
-
- // Add event to queue, restart send loop if finished.
- outputMessageBuffer += message;
- if (sendingMessages == 0)
- sendPendingMessages();
-
- }
-
- function sendPendingMessages() {
-
- if (outputMessageBuffer.length > 0) {
-
- sendingMessages = 1;
-
- var message_xmlhttprequest = new XMLHttpRequest();
- message_xmlhttprequest.open("POST", "inbound");
- message_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- message_xmlhttprequest.setRequestHeader("Content-length", outputMessageBuffer.length);
-
- // Once response received, send next queued event.
- message_xmlhttprequest.onreadystatechange = function() {
- if (message_xmlhttprequest.readyState == 4)
- sendPendingMessages();
- }
-
- message_xmlhttprequest.send(outputMessageBuffer);
- outputMessageBuffer = ""; // Clear buffer
-
- }
- else
- sendingMessages = 0;
-
- }
-
-
- /*****************************************/
- /*** Clipboard ***/
- /*****************************************/
-
- this.setClipboard = function(data) {
-
- // Do not send requests if not connected
- if (!isConnected())
- return;
-
- sendMessage("clipboard:" + escapeGuacamoleString(data) + ";");
- }
-
-
- function desaturateFilter(data, width, height) {
-
- for (var i=0; i<data.length; i+=4) {
-
- // Get RGB values
- var r = data[i];
- var g = data[i+1];
- var b = data[i+2];
-
- // Desaturate
- var v = Math.max(r, g, b) / 2;
- data[i] = v;
- data[i+1] = v;
- data[i+2] = v;
-
- }
-
- }
-
-
- var errorHandler = null;
- this.setErrorHandler = function(handler) {
- errorHandler = handler;
- };
-
- var errorEncountered = 0;
- function showError(error) {
- // Only display first error (avoid infinite error loops)
- if (errorEncountered == 0) {
- errorEncountered = 1;
-
- disconnect();
-
- // In case nothing has been rendered yet, use error style
- display.className += " guac-error";
-
- // Show error by desaturating display
- if (background)
- background.filter(desaturateFilter);
-
- if (errorHandler)
- errorHandler(error);
- }
- }
-
- function handleErrors(message) {
- var errors = message.getErrors();
- for (var errorIndex=0; errorIndex<errors.length; errorIndex++)
- showError(errors[errorIndex].getMessage());
- }
-
- var clipboardHandler = null;
- var requests = 0;
-
- this.setClipboardHandler = function(handler) {
- clipboardHandler = handler;
- };
-
-
- function handleResponse(xmlhttprequest) {
-
- var nextRequest = null;
-
- var instructionStart = 0;
- var startIndex = 0;
-
- function parseResponse() {
-
- // Start next request as soon as possible
- if (xmlhttprequest.readyState >= 2 && nextRequest == null)
- nextRequest = makeRequest();
-
- // Parse stream when data is received and when complete.
- if (xmlhttprequest.readyState == 3 ||
- xmlhttprequest.readyState == 4) {
-
- // Halt on error during request
- if (xmlhttprequest.status == 0) {
- showError("Request canceled by browser.");
- return;
- }
- else if (xmlhttprequest.status != 200) {
- showError("Error during request (HTTP " + xmlhttprequest.status + "): " + xmlhttprequest.statusText);
- return;
- }
-
- var current = xmlhttprequest.responseText;
- var instructionEnd;
-
- while ((instructionEnd = current.indexOf(";", startIndex)) != -1) {
-
- // Start next search at next instruction
- startIndex = instructionEnd+1;
-
- var instruction = current.substr(instructionStart,
- instructionEnd - instructionStart);
-
- instructionStart = startIndex;
-
- var opcodeEnd = instruction.indexOf(":");
-
- var opcode;
- var parameters;
- if (opcodeEnd == -1) {
- opcode = instruction;
- parameters = new Array();
- }
- else {
- opcode = instruction.substr(0, opcodeEnd);
- parameters = instruction.substr(opcodeEnd+1).split(",");
- }
-
- // If we're done parsing, handle the next response.
- if (opcode.length == 0) {
-
- if (isConnected()) {
- delete xmlhttprequest;
- if (nextRequest)
- handleResponse(nextRequest);
- }
-
- break;
- }
-
- // Call instruction handler.
- doInstruction(opcode, parameters);
- }
-
- // Start search at end of string.
- startIndex = current.length;
-
- delete instruction;
- delete parameters;
-
- }
-
- }
-
- xmlhttprequest.onreadystatechange = parseResponse;
- parseResponse();
-
- }
-
-
- function makeRequest() {
-
- // Download self
- var xmlhttprequest = new XMLHttpRequest();
- xmlhttprequest.open("POST", "outbound");
- xmlhttprequest.send(null);
-
- return xmlhttprequest;
-
- }
-
- function escapeGuacamoleString(str) {
-
- var escapedString = "";
-
- for (var i=0; i<str.length; i++) {
-
- var c = str.charAt(i);
- if (c == ",")
- escapedString += "\\c";
- else if (c == ";")
- escapedString += "\\s";
- else if (c == "\\")
- escapedString += "\\\\";
- else
- escapedString += c;
-
- }
-
- return escapedString;
-
- }
-
- function unescapeGuacamoleString(str) {
-
- var unescapedString = "";
-
- for (var i=0; i<str.length; i++) {
-
- var c = str.charAt(i);
- if (c == "\\" && i<str.length-1) {
-
- var escapeChar = str.charAt(++i);
- if (escapeChar == "c")
- unescapedString += ",";
- else if (escapeChar == "s")
- unescapedString += ";";
- else if (escapeChar == "\\")
- unescapedString += "\\";
- else
- unescapedString += "\\" + escapeChar;
-
- }
- else
- unescapedString += c;
-
- }
-
- return unescapedString;
-
- }
-
- var instructionHandlers = {
-
- "error": function(parameters) {
- showError(unescapeGuacamoleString(parameters[0]));
- },
-
- "name": function(parameters) {
- document.title = unescapeGuacamoleString(parameters[0]);
- },
-
- "clipboard": function(parameters) {
- clipboardHandler(unescapeGuacamoleString(parameters[0]));
- },
-
- "size": function(parameters) {
-
- var width = parseInt(parameters[0]);
- var height = parseInt(parameters[1]);
-
- // Update (set) display size
- if (display && (background == null || cursor == null)) {
- display.style.width = width + "px";
- display.style.height = height + "px";
-
- background = new Layer(width, height);
- cursor = new Layer(width, height);
-
- display.appendChild(background);
- display.appendChild(cursor);
- }
-
- },
-
- "rect": function(parameters) {
-
- var x = parseInt(parameters[0]);
- var y = parseInt(parameters[1]);
- var w = parseInt(parameters[2]);
- var h = parseInt(parameters[3]);
- var color = parameters[4];
-
- background.drawRect(
- x,
- y,
- w,
- h,
- color
- );
-
- },
-
- "png": function(parameters) {
-
- var x = parseInt(parameters[0]);
- var y = parseInt(parameters[1]);
- var data = parameters[2];
-
- background.draw(
- x,
- y,
- "data:image/png;base64," + data
- );
-
- // If received first update, no longer waiting.
- if (currentState == STATE_WAITING)
- setState(STATE_CONNECTED);
-
- },
-
- "copy": function(parameters) {
-
- var srcX = parseInt(parameters[0]);
- var srcY = parseInt(parameters[1]);
- var srcWidth = parseInt(parameters[2]);
- var srcHeight = parseInt(parameters[3]);
- var dstX = parseInt(parameters[4]);
- var dstY = parseInt(parameters[5]);
-
- background.copyRect(
- srcX,
- srcY,
- srcWidth,
- srcHeight,
- dstX,
- dstY
- );
-
- },
-
- "cursor": function(parameters) {
-
- var x = parseInt(parameters[0]);
- var y = parseInt(parameters[1]);
- var data = parameters[2];
-
- // Start cursor image load
- var image = new Image();
- image.onload = function() {
- cursorImage = image;
- cursorHotspotX = x;
- cursorHotspotY = y;
- redrawCursor();
- };
- image.src = "data:image/png;base64," + data
-
- }
-
- };
-
-
- function doInstruction(opcode, parameters) {
-
- var handler = instructionHandlers[opcode];
- if (handler)
- handler(parameters);
-
- }
-
-
- this.connect = function() {
-
- setState(STATE_CONNECTING);
-
- // Start tunnel and connect synchronously
- var connect_xmlhttprequest = new XMLHttpRequest();
- connect_xmlhttprequest.open("POST", "connect", false);
- connect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- connect_xmlhttprequest.setRequestHeader("Content-length", 0);
- connect_xmlhttprequest.send(null);
-
- // Start reading data
- setState(STATE_WAITING);
- handleResponse(makeRequest());
-
- };
-
-
- function disconnect() {
-
- // Only attempt disconnection not disconnected.
- if (currentState != STATE_DISCONNECTED
- && currentState != STATE_DISCONNECTING) {
-
- var message = "disconnect;";
- setState(STATE_DISCONNECTING);
-
- // Send disconnect message (synchronously... as necessary until handoff is implemented)
- var disconnect_xmlhttprequest = new XMLHttpRequest();
- disconnect_xmlhttprequest.open("POST", "inbound", false);
- disconnect_xmlhttprequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- disconnect_xmlhttprequest.setRequestHeader("Content-length", message.length);
- disconnect_xmlhttprequest.send(message);
-
- setState(STATE_DISCONNECTED);
- }
-
- }
-
- this.disconnect = disconnect;
-
-}
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-function GuacamoleKeyboard(element) {
-
- /*****************************************/
- /*** Keyboard Handler ***/
- /*****************************************/
-
- // Single key state/modifier buffer
- var modShift = 0;
- var modCtrl = 0;
- var modAlt = 0;
-
- var keydownChar = new Array();
-
-
- // ID of routine repeating keystrokes. -1 = not repeating.
- var repeatKeyTimeoutId = -1;
- var repeatKeyIntervalId = -1;
-
- // Starts repeating keystrokes
- function startRepeat(keySym) {
- repeatKeyIntervalId = setInterval(function() {
- sendKeyReleased(keySym);
- sendKeyPressed(keySym);
- }, 50);
- }
-
- // Stops repeating keystrokes
- function stopRepeat() {
- if (repeatKeyTimeoutId != -1) clearInterval(repeatKeyTimeoutId);
- if (repeatKeyIntervalId != -1) clearInterval(repeatKeyIntervalId);
- }
-
-
- function getKeySymFromKeyIdentifier(shifted, keyIdentifier) {
-
- var unicodePrefixLocation = keyIdentifier.indexOf("U+");
- if (unicodePrefixLocation >= 0) {
-
- var hex = keyIdentifier.substring(unicodePrefixLocation+2);
- var codepoint = parseInt(hex, 16);
- var typedCharacter;
-
- // Convert case if shifted
- if (shifted == 0)
- typedCharacter = String.fromCharCode(codepoint).toLowerCase();
- else
- typedCharacter = String.fromCharCode(codepoint).toUpperCase();
-
- // Get codepoint
- codepoint = typedCharacter.charCodeAt(0);
-
- return getKeySymFromCharCode(codepoint);
-
- }
-
- return null;
-
- }
-
- function getKeySymFromCharCode(keyCode) {
-
- if (keyCode >= 0x0000 && keyCode <= 0x00FF)
- return keyCode;
-
- if (keyCode >= 0x0100 && keyCode <= 0x10FFFF)
- return 0x01000000 | keyCode;
-
- return null;
-
- }
-
- function getKeySymFromKeyCode(keyCode) {
-
- var keysym = null;
- if (modShift == 0) keysym = unshiftedKeySym[keyCode];
- else {
- keysym = shiftedKeySym[keyCode];
- if (keysym == null) keysym = unshiftedKeySym[keyCode];
- }
-
- return keysym;
-
- }
-
-
- // Sends a single keystroke over the network
- function sendKeyPressed(keysym) {
- if (keysym != null && keyPressedHandler)
- keyPressedHandler(keysym);
- }
-
- // Sends a single keystroke over the network
- function sendKeyReleased(keysym) {
- if (keysym != null)
- keyReleasedHandler(keysym);
- }
-
-
- var KEYDOWN = 1;
- var KEYPRESS = 2;
-
- var keySymSource = null;
-
- // When key pressed
- var keydownCode = null;
- element.onkeydown = function(e) {
-
- // Only intercept if handler set
- if (!keyPressedHandler) return true;
-
- var keynum;
- if (window.event) keynum = window.event.keyCode;
- else if (e.which) keynum = e.which;
-
- // Ctrl/Alt/Shift
- if (keynum == 16)
- modShift = 1;
- else if (keynum == 17)
- modCtrl = 1;
- else if (keynum == 18)
- modAlt = 1;
-
- var keysym = getKeySymFromKeyCode(keynum);
- if (keysym) {
- // Get keysyms and events from KEYDOWN
- keySymSource = KEYDOWN;
- }
-
- // If modifier keys are held down, and we have keyIdentifier
- else if ((modCtrl == 1 || modAlt == 1) && e.keyIdentifier) {
-
- // Get keysym from keyIdentifier
- keysym = getKeySymFromKeyIdentifier(modShift, e.keyIdentifier);
-
- // Get keysyms and events from KEYDOWN
- keySymSource = KEYDOWN;
-
- }
-
- else
- // Get keysyms and events from KEYPRESS
- keySymSource = KEYPRESS;
-
- keydownCode = keynum;
-
- // Ignore key if we don't need to use KEYPRESS.
- // Send key event here
- if (keySymSource == KEYDOWN) {
-
- if (keydownChar[keynum] != keysym) {
-
- // Send event
- keydownChar[keynum] = keysym;
- sendKeyPressed(keysym);
-
- // Clear old key repeat, if any.
- stopRepeat();
-
- // Start repeating (if not a modifier key) after a short delay
- if (keynum != 16 && keynum != 17 && keynum != 18)
- repeatKeyTimeoutId = setTimeout(function() { startRepeat(keysym); }, 500);
- }
-
- return false;
- }
-
- };
-
- // When key pressed
- element.onkeypress = function(e) {
-
- // Only intercept if handler set
- if (!keyPressedHandler) return true;
-
- if (keySymSource != KEYPRESS) return false;
-
- var keynum;
- if (window.event) keynum = window.event.keyCode;
- else if (e.which) keynum = e.which;
-
- var keysym = getKeySymFromCharCode(keynum);
- if (keysym && keydownChar[keynum] != keysym) {
-
- // If this button already pressed, release first
- var lastKeyDownChar = keydownChar[keydownCode];
- if (lastKeyDownChar)
- sendKeyReleased(lastKeyDownChar);
-
- keydownChar[keydownCode] = keysym;
-
- // Clear old key repeat, if any.
- stopRepeat();
-
- // Send key event
- sendKeyPressed(keysym);
-
- // Start repeating (if not a modifier key) after a short delay
- repeatKeyTimeoutId = setTimeout(function() { startRepeat(keysym); }, 500);
- }
-
- return false;
- };
-
- // When key released
- element.onkeyup = function(e) {
-
- // Only intercept if handler set
- if (!keyReleasedHandler) return true;
-
- var keynum;
- if (window.event) keynum = window.event.keyCode;
- else if (e.which) keynum = e.which;
-
- // Ctrl/Alt/Shift
- if (keynum == 16)
- modShift = 0;
- else if (keynum == 17)
- modCtrl = 0;
- else if (keynum == 18)
- modAlt = 0;
- else
- stopRepeat();
-
- // Get corresponding character
- var lastKeyDownChar = keydownChar[keynum];
-
- // Clear character record
- keydownChar[keynum] = null;
-
- // Send release event
- sendKeyReleased(lastKeyDownChar);
-
- return false;
- };
-
- // When focus is lost, clear modifiers.
- var docOnblur = element.onblur;
- element.onblur = function() {
- modAlt = 0;
- modCtrl = 0;
- modShift = 0;
- if (docOnblur != null) docOnblur();
- };
-
- var keyPressedHandler = null;
- var keyReleasedHandler = null;
-
- this.setKeyPressedHandler = function(kh) { keyPressedHandler = kh; };
- this.setKeyReleasedHandler = function(kh) { keyReleasedHandler = kh; };
-
-}
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-// Keymap
-
-var unshiftedKeySym = new Array();
-unshiftedKeySym[8] = 0xFF08; // backspace
-unshiftedKeySym[9] = 0xFF09; // tab
-unshiftedKeySym[13] = 0xFF0D; // enter
-unshiftedKeySym[16] = 0xFFE1; // shift
-unshiftedKeySym[17] = 0xFFE3; // ctrl
-unshiftedKeySym[18] = 0xFFE9; // alt
-unshiftedKeySym[19] = 0xFF13; // pause/break
-unshiftedKeySym[20] = 0xFFE5; // caps lock
-unshiftedKeySym[27] = 0xFF1B; // escape
-unshiftedKeySym[33] = 0xFF55; // page up
-unshiftedKeySym[34] = 0xFF56; // page down
-unshiftedKeySym[35] = 0xFF57; // end
-unshiftedKeySym[36] = 0xFF50; // home
-unshiftedKeySym[37] = 0xFF51; // left arrow
-unshiftedKeySym[38] = 0xFF52; // up arrow
-unshiftedKeySym[39] = 0xFF53; // right arrow
-unshiftedKeySym[40] = 0xFF54; // down arrow
-unshiftedKeySym[45] = 0xFF63; // insert
-unshiftedKeySym[46] = 0xFFFF; // delete
-unshiftedKeySym[91] = 0xFFEB; // left window key (super_l)
-unshiftedKeySym[92] = 0xFF67; // right window key (menu key?)
-unshiftedKeySym[93] = null; // select key
-unshiftedKeySym[112] = 0xFFBE; // f1
-unshiftedKeySym[113] = 0xFFBF; // f2
-unshiftedKeySym[114] = 0xFFC0; // f3
-unshiftedKeySym[115] = 0xFFC1; // f4
-unshiftedKeySym[116] = 0xFFC2; // f5
-unshiftedKeySym[117] = 0xFFC3; // f6
-unshiftedKeySym[118] = 0xFFC4; // f7
-unshiftedKeySym[119] = 0xFFC5; // f8
-unshiftedKeySym[120] = 0xFFC6; // f9
-unshiftedKeySym[121] = 0xFFC7; // f10
-unshiftedKeySym[122] = 0xFFC8; // f11
-unshiftedKeySym[123] = 0xFFC9; // f12
-unshiftedKeySym[144] = 0xFF7F; // num lock
-unshiftedKeySym[145] = 0xFF14; // scroll lock
-
-// Shifted versions, IF DIFFERENT FROM UNSHIFTED!
-// If any of these are null, the unshifted one will be used.
-var shiftedKeySym = new Array();
-shiftedKeySym[18] = 0xFFE7; // alt
-
-// Constants for keysyms for special keys
-var KEYSYM_CTRL = 65507;
-var KEYSYM_ALT = 65513;
-var KEYSYM_DELETE = 65535;
-var KEYSYM_SHIFT = 65505;
-
-
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-function Layer(width, height) {
-
- // Off-screen buffer
- var display = document.createElement("canvas");
-
- display.style.position = "absolute";
- display.style.left = "0px";
- display.style.right = "0px";
-
- display.width = width;
- display.height = height;
-
- var displayContext = display.getContext("2d");
-
- var readyHandler = null;
- var nextUpdateToDraw = 0;
- var currentUpdate = 0;
- var updates = new Array();
-
- // Given an update ID, either call the provided update callback, or
- // schedule the update for later.
- function setUpdate(updateId, update) {
-
- // If this update is the next to draw...
- if (updateId == nextUpdateToDraw) {
-
- // Call provided update handler.
- update();
-
- // Draw all pending updates.
- var updateCallback;
- while ((updateCallback = updates[++nextUpdateToDraw])) {
- updateCallback();
- delete updates[nextUpdateToDraw];
- }
-
- // If done with updates, call ready handler
- if (display.isReady() && readyHandler != null)
- readyHandler();
-
- }
-
- // If not next to draw, set callback and wait.
- else
- updates[updateId] = update;
-
- }
-
- display.isReady = function() {
- return currentUpdate == nextUpdateToDraw;
- }
-
- display.setReadyHandler = function(handler) {
- readyHandler = handler;
- }
-
-
- display.drawImage = function(x, y, image) {
- var updateId = currentUpdate++;
-
- setUpdate(updateId, function() {
- displayContext.drawImage(image, x, y);
- });
-
- }
-
-
- display.draw = function(x, y, url) {
- var updateId = currentUpdate++;
-
- var image = new Image();
- image.onload = function() {
- setUpdate(updateId, function() {
- displayContext.drawImage(image, x, y);
- });
- };
- image.src = url;
- };
-
-
- display.copyRect = function(srcx, srcy, w, h, x, y) {
- var updateId = currentUpdate++;
-
- setUpdate(updateId, function() {
- displayContext.drawImage(display, srcx, srcy, w, h, x, y, w, h);
- });
-
- };
-
- display.drawRect = function(x, y, w, h, color) {
- var updateId = currentUpdate++;
-
- setUpdate(updateId, function() {
- displayContext.fillStyle = color;
- displayContext.fillRect(x, y, w, h);
- });
-
- };
-
- display.clearRect = function(x, y, w, h) {
- var updateId = currentUpdate++;
-
- setUpdate(updateId, function() {
- displayContext.clearRect(x, y, w, h);
- });
-
- };
-
- display.filter = function(filter) {
- var updateId = currentUpdate++;
-
- setUpdate(updateId, function() {
- var imageData = displayContext.getImageData(0, 0, width, height);
- filter(imageData.data, width, height);
- displayContext.putImageData(imageData, 0, 0);
- });
-
- };
-
- return display;
-
-}
-
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-function GuacamoleMouse(element) {
-
- /*****************************************/
- /*** Mouse Handler ***/
- /*****************************************/
-
-
- var mouseIndex = 0;
-
- var mouseLeftButton = 0;
- var mouseMiddleButton = 0;
- var mouseRightButton = 0;
-
- var mouseX = 0;
- var mouseY = 0;
-
- var absoluteMouseX = 0;
- var absoluteMouseY = 0;
-
-
- function getMouseState(up, down) {
- var mouseState = new MouseEvent(mouseX, mouseY,
- mouseLeftButton, mouseMiddleButton, mouseRightButton, up, down);
-
- return mouseState;
- }
-
-
- // Block context menu so right-click gets sent properly
- element.oncontextmenu = function(e) {return false;};
-
- element.onmousemove = function(e) {
-
- e.stopPropagation();
-
- absoluteMouseX = e.pageX;
- absoluteMouseY = e.pageY;
-
- mouseX = absoluteMouseX - element.offsetLeft;
- mouseY = absoluteMouseY - element.offsetTop;
-
- // This is all JUST so we can get the mouse position within the element
- var parent = element.offsetParent;
- while (parent) {
- if (parent.offsetLeft && parent.offsetTop) {
- mouseX -= parent.offsetLeft;
- mouseY -= parent.offsetTop;
- }
- parent = parent.offsetParent;
- }
-
- movementHandler(getMouseState(0, 0));
- };
-
-
- element.onmousedown = function(e) {
-
- e.stopPropagation();
-
- switch (e.button) {
- case 0:
- mouseLeftButton = 1;
- break;
- case 1:
- mouseMiddleButton = 1;
- break;
- case 2:
- mouseRightButton = 1;
- break;
- }
-
- buttonPressedHandler(getMouseState(0, 0));
- };
-
-
- element.onmouseup = function(e) {
-
- e.stopPropagation();
-
- switch (e.button) {
- case 0:
- mouseLeftButton = 0;
- break;
- case 1:
- mouseMiddleButton = 0;
- break;
- case 2:
- mouseRightButton = 0;
- break;
- }
-
- buttonReleasedHandler(getMouseState(0, 0));
- };
-
- // Override selection on mouse event element.
- element.onselectstart = function() {
- return false;
- };
-
- // Scroll wheel support
- function handleScroll(e) {
-
- var delta = 0;
- if (e.detail)
- delta = e.detail;
- else if (e.wheelDelta)
- delta = -event.wheelDelta;
-
- // Up
- if (delta < 0) {
- buttonPressedHandler(getMouseState(1, 0));
- buttonReleasedHandler(getMouseState(0, 0));
- }
-
- // Down
- if (delta > 0) {
- buttonPressedHandler(getMouseState(0, 1));
- buttonReleasedHandler(getMouseState(0, 0));
- }
-
- if (e.preventDefault)
- e.preventDefault();
-
- e.returnValue = false;
- }
-
- element.addEventListener('DOMMouseScroll', handleScroll, false);
-
- element.onmousewheel = function(e) {
- handleScroll(e);
- }
-
- function MouseEvent(x, y, left, middle, right, up, down) {
-
- this.getX = function() {
- return x;
- };
-
- this.getY = function() {
- return y;
- };
-
- this.getLeft = function() {
- return left;
- };
-
- this.getMiddle = function() {
- return middle;
- };
-
- this.getRight = function() {
- return right;
- };
-
- this.getUp = function() {
- return up;
- };
-
- this.getDown = function() {
- return down;
- };
-
- this.toString = function() {
- return (mouseIndex++) + "," + x + "," + y + "," + left + "," + middle + "," + right + "," + up + "," + down;
- };
-
- }
-
-
- var buttonPressedHandler = null;
- var buttonReleasedHandler = null;
- var movementHandler = null;
-
- this.setButtonPressedHandler = function(mh) {buttonPressedHandler = mh;};
- this.setButtonReleasedHandler = function(mh) {buttonReleasedHandler = mh;};
- this.setMovementHandler = function(mh) {movementHandler = mh;};
-
-
- this.getX = function() {return mouseX;};
- this.getY = function() {return mouseY;};
- this.getLeftButton = function() {return mouseLeftButton;};
- this.getMiddleButton = function() {return mouseMiddleButton;};
- this.getRightButton = function() {return mouseRightButton;};
-
-}
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-function GuacamoleOnScreenKeyboard(url) {
-
- var tabIndex = 1;
- var allKeys = new Array();
- var modifierState = new function() {};
-
- function getKeySize(size) {
- return (5*size) + "ex";
- }
-
- function getCapSize(size) {
- return (5*size - 0.5) + "ex";
- }
-
- function clearModifiers() {
-
- // Send key release events for all pressed modifiers
- for (var k=0; k<allKeys.length; k++) {
-
- var key = allKeys[k];
- var cap = key.getCap();
- var modifier = cap.getModifier();
-
- if (modifier && isModifierActive(modifier) && !cap.isSticky() && key.isPressed())
- key.release();
-
- }
-
- }
-
- function setModifierReleased(modifier) {
- if (isModifierActive(modifier))
- modifierState[modifier]--;
- }
-
- function setModifierPressed(modifier) {
- if (modifierState[modifier] == null)
- modifierState[modifier] = 1;
- else
- modifierState[modifier]++;
- }
-
- function isModifierActive(modifier) {
- if (modifierState[modifier] > 0)
- return true;
-
- return false;
- }
-
- function toggleModifierPressed(modifier) {
- if (isModifierActive(modifier))
- setModifierReleased(modifier);
- else
- setModifierPressed(modifier);
- }
-
- function refreshAllKeysState() {
- for (var k=0; k<allKeys.length; k++)
- allKeys[k].refreshState();
- }
-
- function Key(key) {
-
- function Cap(cap) {
-
- // Displayed text
- var displayText = cap.textContent;
-
- // Keysym
- var keysym = null;
- if (cap.attributes["keysym"])
- keysym = parseInt(cap.attributes["keysym"].value);
-
- // If keysym not specified, get keysym from display text.
- else if (displayText.length == 1) {
-
- var charCode = displayText.charCodeAt(0);
-
- if (charCode >= 0x0000 && charCode <= 0x00FF)
- keysym = charCode;
-
- else if (charCode >= 0x0100 && charCode <= 0x10FFFF)
- keysym = 0x01000000 | charCode;
- }
-
- // Required modifiers for this keycap
- var reqMod = null;
- if (cap.attributes["if"])
- reqMod = cap.attributes["if"].value.split(",");
-
-
- // Modifier represented by this keycap
- var modifier = null;
- if (cap.attributes["modifier"])
- modifier = cap.attributes["modifier"].value;
-
-
- // Whether this key is sticky (toggles)
- // Currently only valid for modifiers.
- var sticky = false;
- if (cap.attributes["sticky"] && cap.attributes["sticky"].value == "true")
- sticky = true;
-
- this.getDisplayText = function() {
- return cap.textContent;
- };
-
- this.getKeySym = function() {
- return keysym;
- };
-
- this.getRequiredModifiers = function() {
- return reqMod;
- };
-
- this.getModifier = function() {
- return modifier;
- };
-
- this.isSticky = function() {
- return sticky;
- };
-
- }
-
- var size = null;
- if (key.attributes["size"])
- size = parseFloat(key.attributes["size"].value);
-
- var caps = key.getElementsByTagName("cap");
- var keycaps = new Array();
- for (var i=0; i<caps.length; i++)
- keycaps.push(new Cap(caps[i]));
-
- var rowKey = document.createElement("div");
- rowKey.className = "key";
-
- var keyCap = document.createElement("div");
- keyCap.className = "cap";
- rowKey.appendChild(keyCap);
-
-
- var STATE_RELEASED = 0;
- var STATE_PRESSED = 1;
- var state = STATE_RELEASED;
-
- rowKey.isPressed = function() {
- return state == STATE_PRESSED;
- }
-
- var currentCap = null;
- function refreshState(modifier) {
-
- // Find current cap
- currentCap = null;
- for (var j=0; j<keycaps.length; j++) {
-
- var keycap = keycaps[j];
- var required = keycap.getRequiredModifiers();
-
- var matches = true;
-
- // If modifiers required, make sure all modifiers are active
- if (required) {
-
- for (var k=0; k<required.length; k++) {
- if (!isModifierActive(required[k])) {
- matches = false;
- break;
- }
- }
-
- }
-
- if (matches)
- currentCap = keycap;
-
- }
-
- rowKey.className = "key";
-
- if (currentCap.getModifier())
- rowKey.className += " modifier";
-
- if (currentCap.isSticky())
- rowKey.className += " sticky";
-
- if (isModifierActive(currentCap.getModifier()))
- rowKey.className += " active";
-
- if (state == STATE_PRESSED)
- rowKey.className += " pressed";
-
- keyCap.textContent = currentCap.getDisplayText();
- }
- rowKey.refreshState = refreshState;
-
- rowKey.getCap = function() {
- return currentCap;
- };
-
- refreshState();
-
- // Set size
- if (size) {
- rowKey.style.width = getKeySize(size);
- keyCap.style.width = getCapSize(size);
- }
-
-
-
- // Set pressed, if released
- function press() {
-
- if (state == STATE_RELEASED) {
-
- state = STATE_PRESSED;
-
- var keysym = currentCap.getKeySym();
- var modifier = currentCap.getModifier();
- var sticky = currentCap.isSticky();
-
- if (keyPressedHandler && keysym)
- keyPressedHandler(keysym);
-
- if (modifier) {
-
- // If sticky modifier, toggle
- if (sticky)
- toggleModifierPressed(modifier);
-
- // Otherwise, just set on.
- else
- setModifierPressed(modifier);
-
- refreshAllKeysState();
- }
- else
- refreshState();
- }
-
- }
- rowKey.press = press;
-
-
- // Set released, if pressed
- function release() {
-
- if (state == STATE_PRESSED) {
-
- state = STATE_RELEASED;
-
- var keysym = currentCap.getKeySym();
- var modifier = currentCap.getModifier();
- var sticky = currentCap.isSticky();
-
- if (keyReleasedHandler && keysym)
- keyReleasedHandler(keysym);
-
- if (modifier) {
-
- // If not sticky modifier, release modifier
- if (!sticky) {
- setModifierReleased(modifier);
- refreshAllKeysState();
- }
- else
- refreshState();
-
- }
- else {
- refreshState();
-
- // If not a modifier, also release all pressed modifiers
- clearModifiers();
- }
-
- }
-
- }
- rowKey.release = release;
-
- // Toggle press/release states
- function toggle() {
- if (state == STATE_PRESSED)
- release();
- else
- press();
- }
-
-
- // Send key press on mousedown
- rowKey.onmousedown = function(e) {
-
- e.stopPropagation();
-
- var modifier = currentCap.getModifier();
- var sticky = currentCap.isSticky();
-
- // Toggle non-sticky modifiers
- if (modifier && !sticky)
- toggle();
-
- // Press all others
- else
- press();
-
- return false;
- };
-
- // Send key release on mouseup/out
- rowKey.onmouseout =
- rowKey.onmouseout =
- rowKey.onmouseup = function(e) {
-
- e.stopPropagation();
-
- var modifier = currentCap.getModifier();
- var sticky = currentCap.isSticky();
-
- // Release non-modifiers and sticky modifiers
- if (!modifier || sticky)
- release();
-
- return false;
- };
-
- rowKey.onselectstart = function() { return false; };
-
- return rowKey;
-
- }
-
- function Gap(gap) {
-
- var keyboardGap = document.createElement("div");
- keyboardGap.className = "gap";
- keyboardGap.textContent = " ";
-
- var size = null;
- if (gap.attributes["size"])
- size = parseFloat(gap.attributes["size"].value);
-
- if (size) {
- keyboardGap.style.width = getKeySize(size);
- keyboardGap.style.height = getKeySize(size);
- }
-
- return keyboardGap;
-
- }
-
- function Row(row) {
-
- var keyboardRow = document.createElement("div");
- keyboardRow.className = "row";
-
- var children = row.childNodes;
- for (var j=0; j<children.length; j++) {
- var child = children[j];
-
- // <row> can contain <key> or <column>
- if (child.tagName == "key") {
- var key = new Key(child);
- keyboardRow.appendChild(key);
- allKeys.push(key);
- }
- else if (child.tagName == "gap") {
- var gap = new Gap(child);
- keyboardRow.appendChild(gap);
- }
- else if (child.tagName == "column") {
- var col = new Column(child);
- keyboardRow.appendChild(col);
- }
-
- }
-
- return keyboardRow;
-
- }
-
- function Column(col) {
-
- var keyboardCol = document.createElement("div");
- keyboardCol.className = "col";
-
- var align = null;
- if (col.attributes["align"])
- align = col.attributes["align"].value;
-
- var children = col.childNodes;
- for (var j=0; j<children.length; j++) {
- var child = children[j];
-
- // <column> can only contain <row>
- if (child.tagName == "row") {
- var row = new Row(child);
- keyboardCol.appendChild(row);
- }
-
- }
-
- if (align)
- keyboardCol.style.textAlign = align;
-
- return keyboardCol;
-
- }
-
-
-
- // Create keyboard
- var keyboard = document.createElement("div");
- keyboard.className = "keyboard";
-
-
- // Retrieve keyboard XML
- var xmlhttprequest = new XMLHttpRequest();
- xmlhttprequest.open("GET", url, false);
- xmlhttprequest.send(null);
-
- var xml = xmlhttprequest.responseXML;
-
- if (xml) {
-
- // Parse document
- var root = xml.documentElement;
- if (root) {
-
- var children = root.childNodes;
- for (var i=0; i<children.length; i++) {
- var child = children[i];
-
- // <keyboard> can contain <row> or <column>
- if (child.tagName == "row") {
- keyboard.appendChild(new Row(child));
- }
- else if (child.tagName == "column") {
- keyboard.appendChild(new Column(child));
- }
-
- }
-
- }
-
- }
-
- var keyPressedHandler = null;
- var keyReleasedHandler = null;
-
- keyboard.setKeyPressedHandler = function(kh) { keyPressedHandler = kh; };
- keyboard.setKeyReleasedHandler = function(kh) { keyReleasedHandler = kh; };
-
- // Do not allow selection or mouse movement to propagate/register.
- keyboard.onselectstart =
- keyboard.onmousemove =
- keyboard.onmouseup =
- keyboard.onmousedown =
- function(e) {
- e.stopPropagation();
- return false;
- };
-
- return keyboard;
-}
-
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-body {
- background: black;
- font-family: sans-serif;
- padding: 0;
- margin: 0;
-}
-
-div#login-ui {
- background: silver;
- height: 100%;
- width: 100%;
- position: fixed;
- left: 0;
- top: 0;
- display: table;
-}
-
-p#login-error {
- text-align: center;
- background: #FDD;
- color: red;
- margin: 0.2em;
-}
-
-div#login-logo {
- position: relative;
- bottom: 0;
- display: inline-block;
- vertical-align: middle;
-}
-
-div#login-dialog-middle {
- width: 100%;
- display: table-cell;
- vertical-align: middle;
- text-align: center;
-}
-
-div#login-dialog {
-
- background: white;
- vertical-align: middle;
-
- padding: 1em;
- border: 0.2em solid black;
-
- -khtml-border-radius: 0.5em;
- -webkit-border-radius: 0.5em;
- -moz-border-radius: 0.5em;
- border-radius: 0.5em;
-
- max-width: 75%;
- text-align: left;
-
- display: inline-block;
-}
-
-div#login-dialog h1 {
- margin-top: 0;
- margin-bottom: 0em;
- text-align: center;
-}
-
-div#login-dialog #buttons {
- padding-top: 0.5em;
- text-align: center;
-}
-
-div#login-dialog #login-fields {
- border-top: 1px solid silver;
- border-bottom: 1px solid silver;
- padding-top: 0.5em;
- padding-bottom: 0.5em;
-}
-
-div.errorDialogOuter {
- display: table;
- height: 100%;
- width: 100%;
- position: fixed;
- left: 0;
- top: 0;
-
- visibility: hidden;
-}
-
-div.errorDialogMiddle {
- width: 100%;
- text-align: center;
- display: table-cell;
- vertical-align: middle;
-}
-
-div.errorDialog {
-
- background: #D44;
- border: 1px solid black;
- padding: 1em;
-
- -khtml-border-radius: 0.5em;
- -webkit-border-radius: 0.5em;
- -moz-border-radius: 0.5em;
- border-radius: 0.5em;
-
- -moz-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
- -webkit-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
- -khtml-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
- box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
-
- max-width: 75%;
- text-align: left;
-
- display: inline-block;
-}
-
-div.errorDialog h1 {
- margin: 0;
- margin-bottom: 0.25em;
- text-align: center;
- text-shadow: 0 0 0.25em white;
-}
-
-div.errorDialog div.buttons {
- margin: 0;
- margin-top: 0.5em;
- text-align: center;
-}
-
-div.errorDialog p {
- margin: 0;
-}
-
-
-#menu {
- margin-left: auto;
- margin-right: auto;
- margin-bottom: 1em;
- font-size: 0.8em;
- background: #FEA;
- border: 1px solid black;
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- z-index: 1;
-}
-
-#menu.connected {
- opacity: 0.5;
-}
-
-#menu.connected:hover {
- opacity: 1;
-}
-
-#menu.error {
- background: #D44;
-}
-
-.error #state {
- font-weight: bold;
-}
-
-img {
- border: none;
-}
-
-img#license {
- border: none;
- float: right;
- margin: 2px;
-}
-
-div#display {
- position: relative;
- width: 640px;
- height: 480px;
- margin-left: auto;
- margin-right: auto;
-}
-
-#menu img {
- vertical-align: middle;
-}
-
-#menu button {
- vertical-align: middle;
-}
-
-#menu span {
- vertical-align: middle;
-}
-
-div#clipboardDiv {
- display: none;
- position: absolute;
- background: #FA5;
- padding: 1em;
-
- border: 1px solid black;
- -khtml-border-radius: 0.5em;
- -webkit-border-radius: 0.5em;
- -moz-border-radius: 0.5em;
- border-radius: 0.5em;
-
- width: 50em;
-}
-
-div#clipboardDiv h2 {
- margin: 0;
- font-size: 1em;
-}
-
-div#clipboardDiv textarea {
- width: 100%;
-}
-
<head>
<link rel="icon" type="image/png" href="images/guacamole-icon-64.png"/>
- <link rel="stylesheet" type="text/css" href="guacamole.css"/>
- <link rel="stylesheet" type="text/css" href="guac-web-lib/css/guacamole.css"/>
- <link rel="stylesheet" type="text/css" href="keyboard.css"/>
+ <link rel="stylesheet" type="text/css" href="styles/guacamole.css"/>
+ <link rel="stylesheet" type="text/css" href="styles/keyboard.css"/>
<title>Guacamole</title>
</head>
<!-- Scripts -->
- <script type="text/javascript" src="guac-web-lib/javascript/keymap.js"></script>
- <script type="text/javascript" src="guac-web-lib/javascript/keyboard.js"></script>
- <script type="text/javascript" src="guac-web-lib/javascript/mouse.js"></script>
- <script type="text/javascript" src="guac-web-lib/javascript/layer.js"></script>
- <script type="text/javascript" src="guac-web-lib/javascript/guacamole.js"></script>
- <script type="text/javascript" src="guac-web-lib/javascript/oskeyboard.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/keymap.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/keyboard.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/mouse.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/layer.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/guacamole.js"></script>
+ <script type="text/javascript" src="guacamole-common-js/oskeyboard.js"></script>
<!-- Init -->
<script type="text/javascript"> /* <![CDATA[ */
+++ /dev/null
-
-/*
- * Guacamole - Clientless Remote Desktop
- * Copyright (C) 2010 Michael Jumper
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-div#keyboardContainer {
- position: fixed;
- left: 0px;
- bottom: 0px;
- text-align: center;
- width: 100%;
- display: none;
- z-index: 1;
-}
-
-div.keyboard {
-
- font-size: 10pt;
- white-space: pre;
-
- border: 1px solid black;
- -moz-border-radius: 0.5em;
- -webkit-border-radius: 0.5em;
- -khtml-border-radius: 0.5em;
- border-radius: 0.5em;
- background: #222;
-
- cursor: default;
-
- opacity: 0.85;
-
- padding: 0.25em;
- margin: 0.25em;
-
- display: inline-block;
- text-align: left;
-}
-
-div.key {
-
- margin: 0;
- padding: 0;
-
- width: 5ex;
- height: 5ex;
-
- display: inline-block;
- text-align: center;
-}
-
-div.cap {
-
- border: 1px solid #888;
- -moz-border-radius: 0.25em;
- -webkit-border-radius: 0.25em;
- -khtml-border-radius: 0.25em;
- border-radius: 0.25em;
- background: #444;
-
- margin: 0;
- padding: 0;
-
- color: white;
- text-shadow: 0 0.1em 0.1em black;
-
- width: 4.5ex;
- height: 4.5ex;
- line-height: 4.5ex;
- white-space: pre;
-
- display: inline-block;
- text-align: center;
-}
-
-div.key:hover div.cap {
- background: #666;
- border-color: #666;
- cursor: pointer;
-}
-
-div.key.pressed div.cap {
- background: #822;
- border-color: #D44;
-}
-
-div.key.sticky.active div.cap {
- background: #882;
- border-color: #DD4;
-}
-
-div.gap {
- margin: 0;
- padding: 0;
-
- width: 5ex;
- height: 5ex;
-
- display: inline-block;
-}
-
-div.row {
- vertical-align: top;
-}
-
-div.col {
- display: inline-block;
- vertical-align: top;
-}
-
--- /dev/null
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+body {
+ background: black;
+ font-family: sans-serif;
+ padding: 0;
+ margin: 0;
+}
+
+div#login-ui {
+ background: silver;
+ height: 100%;
+ width: 100%;
+ position: fixed;
+ left: 0;
+ top: 0;
+ display: table;
+}
+
+p#login-error {
+ text-align: center;
+ background: #FDD;
+ color: red;
+ margin: 0.2em;
+}
+
+div#login-logo {
+ position: relative;
+ bottom: 0;
+ display: inline-block;
+ vertical-align: middle;
+}
+
+div#login-dialog-middle {
+ width: 100%;
+ display: table-cell;
+ vertical-align: middle;
+ text-align: center;
+}
+
+div#login-dialog {
+
+ background: white;
+ vertical-align: middle;
+
+ padding: 1em;
+ border: 0.2em solid black;
+
+ -khtml-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ -moz-border-radius: 0.5em;
+ border-radius: 0.5em;
+
+ max-width: 75%;
+ text-align: left;
+
+ display: inline-block;
+}
+
+div#login-dialog h1 {
+ margin-top: 0;
+ margin-bottom: 0em;
+ text-align: center;
+}
+
+div#login-dialog #buttons {
+ padding-top: 0.5em;
+ text-align: center;
+}
+
+div#login-dialog #login-fields {
+ border-top: 1px solid silver;
+ border-bottom: 1px solid silver;
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+}
+
+div.errorDialogOuter {
+ display: table;
+ height: 100%;
+ width: 100%;
+ position: fixed;
+ left: 0;
+ top: 0;
+
+ visibility: hidden;
+}
+
+div.errorDialogMiddle {
+ width: 100%;
+ text-align: center;
+ display: table-cell;
+ vertical-align: middle;
+}
+
+div.errorDialog {
+
+ background: #D44;
+ border: 1px solid black;
+ padding: 1em;
+
+ -khtml-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ -moz-border-radius: 0.5em;
+ border-radius: 0.5em;
+
+ -moz-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
+ -webkit-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
+ -khtml-box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
+ box-shadow: 0 0.25em 0.75em black, inset 0.1em 0.1em 0.5em #F99, inset -0.1em -0.1em 0.75em #800;
+
+ max-width: 75%;
+ text-align: left;
+
+ display: inline-block;
+}
+
+div.errorDialog h1 {
+ margin: 0;
+ margin-bottom: 0.25em;
+ text-align: center;
+ text-shadow: 0 0 0.25em white;
+}
+
+div.errorDialog div.buttons {
+ margin: 0;
+ margin-top: 0.5em;
+ text-align: center;
+}
+
+div.errorDialog p {
+ margin: 0;
+}
+
+
+#menu {
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1em;
+ font-size: 0.8em;
+ background: #FEA;
+ border: 1px solid black;
+ position: fixed;
+ left: 0;
+ top: 0;
+ width: 100%;
+ z-index: 1;
+}
+
+#menu.connected {
+ opacity: 0.5;
+}
+
+#menu.connected:hover {
+ opacity: 1;
+}
+
+#menu.error {
+ background: #D44;
+}
+
+.error #state {
+ font-weight: bold;
+}
+
+img {
+ border: none;
+}
+
+img#license {
+ border: none;
+ float: right;
+ margin: 2px;
+}
+
+div#display {
+ position: relative;
+ width: 640px;
+ height: 480px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#menu img {
+ vertical-align: middle;
+}
+
+#menu button {
+ vertical-align: middle;
+}
+
+#menu span {
+ vertical-align: middle;
+}
+
+div#clipboardDiv {
+ display: none;
+ position: absolute;
+ background: #FA5;
+ padding: 1em;
+
+ border: 1px solid black;
+ -khtml-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ -moz-border-radius: 0.5em;
+ border-radius: 0.5em;
+
+ width: 50em;
+}
+
+div#clipboardDiv h2 {
+ margin: 0;
+ font-size: 1em;
+}
+
+div#clipboardDiv textarea {
+ width: 100%;
+}
+
+.guac-display.guac-loading {
+ border: 1px dotted gray;
+ background-image: url('../images/spinner92.gif');
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.guac-display.guac-error {
+ border: 1px dotted red;
+ background-image: url('../images/noimage92.png');
+ background-position: center;
+ background-repeat: no-repeat;
+}
+
+.guac-hide-cursor {
+ cursor: url('../images/mouse/dot.gif'),url('../images/mouse/blank.cur'),default;
+}
+
--- /dev/null
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+div#keyboardContainer {
+ position: fixed;
+ left: 0px;
+ bottom: 0px;
+ text-align: center;
+ width: 100%;
+ display: none;
+ z-index: 1;
+}
+
+div.keyboard {
+
+ font-size: 10pt;
+ white-space: pre;
+
+ border: 1px solid black;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ -khtml-border-radius: 0.5em;
+ border-radius: 0.5em;
+ background: #222;
+
+ cursor: default;
+
+ opacity: 0.85;
+
+ padding: 0.25em;
+ margin: 0.25em;
+
+ display: inline-block;
+ text-align: left;
+}
+
+div.key {
+
+ margin: 0;
+ padding: 0;
+
+ width: 5ex;
+ height: 5ex;
+
+ display: inline-block;
+ text-align: center;
+}
+
+div.cap {
+
+ border: 1px solid #888;
+ -moz-border-radius: 0.25em;
+ -webkit-border-radius: 0.25em;
+ -khtml-border-radius: 0.25em;
+ border-radius: 0.25em;
+ background: #444;
+
+ margin: 0;
+ padding: 0;
+
+ color: white;
+ text-shadow: 0 0.1em 0.1em black;
+
+ width: 4.5ex;
+ height: 4.5ex;
+ line-height: 4.5ex;
+ white-space: pre;
+
+ display: inline-block;
+ text-align: center;
+}
+
+div.key:hover div.cap {
+ background: #666;
+ border-color: #666;
+ cursor: pointer;
+}
+
+div.key.pressed div.cap {
+ background: #822;
+ border-color: #D44;
+}
+
+div.key.sticky.active div.cap {
+ background: #882;
+ border-color: #DD4;
+}
+
+div.gap {
+ margin: 0;
+ padding: 0;
+
+ width: 5ex;
+ height: 5ex;
+
+ display: inline-block;
+}
+
+div.row {
+ vertical-align: top;
+}
+
+div.col {
+ display: inline-block;
+ vertical-align: top;
+}
+