From e9224ff1104949ba50ad20de1f845460041ce0ac Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 18 Dec 2011 20:35:54 -0800 Subject: [PATCH 1/7] Added changelog --- guacamole/ChangeLog | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 guacamole/ChangeLog diff --git a/guacamole/ChangeLog b/guacamole/ChangeLog new file mode 100644 index 000000000..af5a4ed53 --- /dev/null +++ b/guacamole/ChangeLog @@ -0,0 +1,23 @@ +2011-12-11 Michael Jumper + + * Improved UI usability + * Support for multiple connections per user + * Real support for authentication providers + * Logout button + * Connection type icons (thanks to Tango Desktop Project) + * Fixed Ctrl-Alt-Delete bug (ticket #57) + * Fixed arrow key rendering (Chrome-specific issue) + * Fixed exception in XMLReader.parse() (ticket #66) + +2011-07-13 Michael Jumper + + * Migrated to new tunnel API + * Major cleanup of UI + * Fixed corrupt mouse cursor image + * Improved JavaScript style + * Logging (via SLF4J) + +2011-03-02 Michael Jumper + + * Initial release of modern 0.3.0+ series + From 256e9675c901ab136be9f6d9e40af9607e3d52b9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 18 Dec 2011 20:36:02 -0800 Subject: [PATCH 2/7] Added README --- guacamole/README | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 guacamole/README diff --git a/guacamole/README b/guacamole/README new file mode 100644 index 000000000..0ac4c4777 --- /dev/null +++ b/guacamole/README @@ -0,0 +1,70 @@ + +------------------------------------------------------------ + About this README +------------------------------------------------------------ + +This README is intended to provide quick and to-the-point documentation for +technical users intending to compile parts of Guacamole themselves. + +Distribution-specific packages are available from the files section of the main +project page: + + http://sourceforge.net/projects/guacamole/files/ + +Distribution-specific documentation is provided on the Guacamole wiki: + + http://guac-dev.org/ + + +------------------------------------------------------------ + What is Guacamole? +------------------------------------------------------------ + +Guacamole is an HTML5 web application that provides access to your desktop using +remote desktop protocols. A centralized server acts as a tunnel and proxy, +allowing access to multiple desktops through a web browser; no plugins needed. +The client requires nothing more than a web browser supporting HTML5 and AJAX. + +The Guacamole project maintains this web application and the Java and C +libraries and programs it depends on. These libraries and programs are +separate in order to enable others to implement other applications using the +same underlying technology. + +All components and dependencies of Guacamole are free and open source. + + +------------------------------------------------------------ + Compiling and installing Guacamole +------------------------------------------------------------ + +Guacamole is built using Maven. Building Guacamole compiles all classes and +packages them into a deployable .war file. This .war file can be installed +and deployed under servlet containers like Apache Tomcat or Jetty. + +1) Run mvn package + + $ mvn package + + Maven will download any needed dependencies for building the .jar file. + Once all dependencies have been downloaded, the .war file will be + created in the target/ subdirectory of the current directory. + +2) Copy the .war file as directed in the instructions provided with + your servlet container. + + Apache Tomcat, Jetty, and other servlet containers have specific and + varying locations that .war files must be placed for the web + application to be deployed. + + You will likely need to do this as root. + + +------------------------------------------------------------ + Reporting problems +------------------------------------------------------------ + +Please report any bugs encountered by opening a new ticket at the Trac system +hosted at: + + http://guac-dev.org/trac/ + From f34e577082244039b1afc27b70d9045c39e25489 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 18 Dec 2011 21:33:51 -0800 Subject: [PATCH 3/7] Fixed comments. --- .../BasicFileAuthenticationProvider.java | 21 +++++- .../basic/BasicGuacamoleTunnelServlet.java | 6 ++ .../guacamole/net/basic/BasicLogin.java | 11 ++++ .../guacamole/net/basic/BasicLogout.java | 6 ++ .../net/basic/ConfigurationList.java | 10 +-- .../net/basic/GuacamoleClassLoader.java | 66 ++++++++++++++----- .../AuthenticationProviderProperty.java | 6 ++ .../properties/BasicGuacamoleProperties.java | 26 +++++--- 8 files changed, 120 insertions(+), 32 deletions(-) diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicFileAuthenticationProvider.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicFileAuthenticationProvider.java index 26c41b32c..0b5b6488f 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicFileAuthenticationProvider.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicFileAuthenticationProvider.java @@ -32,7 +32,7 @@ import java.util.HashMap; import java.util.Map; import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.auth.UsernamePassword; -import net.sourceforge.guacamole.net.basic.properties.BasicGuacamoleProperties; +import net.sourceforge.guacamole.properties.FileGuacamoleProperty; import net.sourceforge.guacamole.properties.GuacamoleProperties; import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; import org.slf4j.Logger; @@ -44,6 +44,13 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; +/** + * Authenticates users against a static list of username/password pairs. + * Each username/password may be associated with exactly one configuration. + * This list is stored in an XML file which is reread if modified. + * + * @author Michael Jumper + */ public class BasicFileAuthenticationProvider implements AuthenticationProvider { private Logger logger = LoggerFactory.getLogger(BasicFileAuthenticationProvider.class); @@ -51,10 +58,20 @@ public class BasicFileAuthenticationProvider implements AuthenticationProvider mapping; + /** + * The filename of the XML file to read the user mapping from. + */ + public static final FileGuacamoleProperty BASIC_USER_MAPPING = new FileGuacamoleProperty() { + + @Override + public String getName() { return "basic-user-mapping"; } + + }; + private File getUserMappingFile() throws GuacamoleException { // Get user mapping file - return GuacamoleProperties.getProperty(BasicGuacamoleProperties.BASIC_USER_MAPPING); + return GuacamoleProperties.getProperty(BASIC_USER_MAPPING); } diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java index b1376f2db..e1b5d292c 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java @@ -33,6 +33,12 @@ import net.sourceforge.guacamole.servlet.GuacamoleHTTPTunnelServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Connects users to a tunnel associated with the authorized configuration + * having the given ID. + * + * @author Michael Jumper + */ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet { private Logger logger = LoggerFactory.getLogger(BasicGuacamoleTunnelServlet.class); diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogin.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogin.java index 34a72e798..6fe2f106e 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogin.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogin.java @@ -34,6 +34,17 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Retrieves the authorized configurations associated with a given + * username/password pair using the authentication provider defined in + * guacamole.properties. + * + * All authorized configurations will be stored in the current HttpSession. + * + * Success and failure are logged. + * + * @author Michael Jumper + */ public class BasicLogin extends HttpServlet { private Logger logger = LoggerFactory.getLogger(BasicLogin.class); diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogout.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogout.java index e978a0e5d..df1447d33 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogout.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicLogout.java @@ -24,6 +24,12 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +/** + * Logs out the current user by invalidating the associated HttpSession and + * redirecting the user to the login page. + * + * @author Michael Jumper + */ public class BasicLogout extends HttpServlet { @Override diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/ConfigurationList.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/ConfigurationList.java index fc45474e3..dcbc446e6 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/ConfigurationList.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/ConfigurationList.java @@ -27,13 +27,15 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import net.sourceforge.guacamole.protocol.GuacamoleConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +/** + * Simple HttpServlet which outputs XML containing a list of all authorized + * configurations for the current user. + * + * @author Michael Jumper + */ public class ConfigurationList extends HttpServlet { - private Logger logger = LoggerFactory.getLogger(ConfigurationList.class); - @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/GuacamoleClassLoader.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/GuacamoleClassLoader.java index b1a398a69..75540e1f4 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/GuacamoleClassLoader.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/GuacamoleClassLoader.java @@ -1,6 +1,42 @@ package net.sourceforge.guacamole.net.basic; +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is guacamole-common. + * + * The Initial Developer of the Original Code is + * Michael Jumper. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; @@ -12,24 +48,12 @@ import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.net.basic.properties.BasicGuacamoleProperties; import net.sourceforge.guacamole.properties.GuacamoleProperties; -/* - * 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 . +/** + * A ClassLoader implementation which finds classes within a configurable + * directory. This directory is set within guacamole.properties. + * + * @author Michael Jumper */ - public class GuacamoleClassLoader extends ClassLoader { private URLClassLoader classLoader = null; @@ -101,6 +125,14 @@ public class GuacamoleClassLoader extends ClassLoader { } + /** + * Returns an instance of a GuacamoleClassLoader which finds classes + * within the directory configured in guacamole.properties. + * + * @return An instance of a GuacamoleClassLoader. + * @throws GuacamoleException If no instance could be returned due to an + * error. + */ public static GuacamoleClassLoader getInstance() throws GuacamoleException { // If instance could not be created, rethrow original exception diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/AuthenticationProviderProperty.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/AuthenticationProviderProperty.java index 90e982e32..cb1eb03a7 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/AuthenticationProviderProperty.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/AuthenticationProviderProperty.java @@ -24,6 +24,12 @@ import net.sourceforge.guacamole.net.auth.AuthenticationProvider; import net.sourceforge.guacamole.net.basic.GuacamoleClassLoader; import net.sourceforge.guacamole.properties.GuacamoleProperty; +/** + * A GuacamoleProperty whose value is the name of a class to use to + * authenticate users. This class must implement AuthenticationProvider. + * + * @author Michael Jumper + */ public abstract class AuthenticationProviderProperty implements GuacamoleProperty { @Override diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/BasicGuacamoleProperties.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/BasicGuacamoleProperties.java index cb9430e96..4110b4606 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/BasicGuacamoleProperties.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/properties/BasicGuacamoleProperties.java @@ -1,8 +1,6 @@ package net.sourceforge.guacamole.net.basic.properties; -import net.sourceforge.guacamole.properties.FileGuacamoleProperty; - /* * Guacamole - Clientless Remote Desktop * Copyright (C) 2010 Michael Jumper @@ -21,17 +19,24 @@ import net.sourceforge.guacamole.properties.FileGuacamoleProperty; * along with this program. If not, see . */ +import net.sourceforge.guacamole.properties.FileGuacamoleProperty; + +/** + * Properties used by the default Guacamole web application. + * + * @author Michael Jumper + */ public class BasicGuacamoleProperties { + /** + * This class should not be instantiated. + */ private BasicGuacamoleProperties() {} - public static final FileGuacamoleProperty BASIC_USER_MAPPING = new FileGuacamoleProperty() { - - @Override - public String getName() { return "basic-user-mapping"; } - - }; - + /** + * The authentication provider to user when retrieving the authorized + * configurations of a user. + */ public static final AuthenticationProviderProperty AUTH_PROVIDER = new AuthenticationProviderProperty() { @Override @@ -39,6 +44,9 @@ public class BasicGuacamoleProperties { }; + /** + * The directory to search for authentication provider classes. + */ public static final FileGuacamoleProperty LIB_DIRECTORY = new FileGuacamoleProperty() { @Override From 6cfde7df70a3a7a120eba320d94c5033416d4207 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 19 Dec 2011 15:56:12 -0800 Subject: [PATCH 4/7] Initial fixes for buggy menu hiding feature. --- guacamole/src/main/webapp/client.xhtml | 6 +- .../src/main/webapp/scripts/interface.js | 96 ++++++++++++++++--- guacamole/src/main/webapp/styles/client.css | 28 +++--- 3 files changed, 103 insertions(+), 27 deletions(-) diff --git a/guacamole/src/main/webapp/client.xhtml b/guacamole/src/main/webapp/client.xhtml index be2250951..ee9cd21cf 100644 --- a/guacamole/src/main/webapp/client.xhtml +++ b/guacamole/src/main/webapp/client.xhtml @@ -56,10 +56,14 @@
+ + + +
-
+
diff --git a/guacamole/src/main/webapp/scripts/interface.js b/guacamole/src/main/webapp/scripts/interface.js index c2d5a5d09..4d24b9279 100644 --- a/guacamole/src/main/webapp/scripts/interface.js +++ b/guacamole/src/main/webapp/scripts/interface.js @@ -2,10 +2,11 @@ // UI Definition var GuacamoleUI = { - "display": document.getElementById("display"), - "menu" : document.getElementById("menu"), - "logo" : document.getElementById("status-logo"), - "state" : document.getElementById("state"), + "display" : document.getElementById("display"), + "menu" : document.getElementById("menu"), + "menuControl" : document.getElementById("menuControl"), + "logo" : document.getElementById("status-logo"), + "state" : document.getElementById("state"), "buttons": { @@ -137,13 +138,84 @@ var GuacamoleUI = { window.location.href = "logout"; }; - GuacamoleUI.display.onmouseout = function() { - GuacamoleUI.showMenu(); - }; + var detectMenuOpenTimeout = null; + var detectMenuCloseTimeout = null; + + GuacamoleUI.menu.addEventListener('mouseover', function() { + + // If we were waiting for menu close, we're not anymore + if (detectMenuCloseTimeout != null) { + window.clearTimeout(detectMenuCloseTimeout); + detectMenuCloseTimeout = null; + } + + }, true); + + GuacamoleUI.menu.addEventListener('mouseout', function(e) { + + // Get parent of the element the mouse pointer is leaving + if (!e) e = window.event; + var target = e.relatedTarget || e.toElement; + + // Ensure target is not menu nor child of menu + var targetParent = target; + while (targetParent != null) { + if (targetParent == GuacamoleUI.menu) return; + targetParent = targetParent.parentNode; + } + + // If not already waiting, start detection of mouse leave + if (detectMenuCloseTimeout == null) { + detectMenuCloseTimeout = window.setTimeout(function() { + GuacamoleUI.shadeMenu(); + detectMenuCloseTimeout = null; + }, 750); + } + + }, true); + + // When mouse hovers over top of screen, start detection of mouse hover + GuacamoleUI.menuControl.addEventListener('mousemove', function() { + + // If we were waiting for menu close, we're not anymore + if (detectMenuCloseTimeout != null) { + window.clearTimeout(detectMenuCloseTimeout); + detectMenuCloseTimeout = null; + } + + // Clear old timeout if mouse moved while we were waiting + if (detectMenuOpenTimeout != null) { + window.clearTimeout(detectMenuOpenTimeout); + detectMenuOpenTimeout = null; + } + + // If not alread waiting, wait for 250ms before showing menu + detectMenuOpenTimeout = window.setTimeout(function() { + GuacamoleUI.showMenu(); + detectMenuOpenTimeout = null; + }, 250); + + }, true); + + // When mouse leaves top of screen, cancel showing the menu + GuacamoleUI.menuControl.addEventListener('mouseout', function() { + + // If we were waiting for menu open, we're not anymore + if (detectMenuOpenTimeout != null) { + window.clearTimeout(detectMenuOpenTimeout); + detectMenuCloseTimeout = null; + } + + // If not already waiting, start detection of mouse leave + if (detectMenuCloseTimeout == null) { + detectMenuCloseTimeout = window.setTimeout(function() { + GuacamoleUI.shadeMenu(); + detectMenuCloseTimeout = null; + }, 750); + } + + }, true); - GuacamoleUI.display.onmouseover = function() { - GuacamoleUI.shadeMenu(); - }; // Reconnect button GuacamoleUI.buttons.reconnect.onclick = function() { @@ -163,10 +235,6 @@ GuacamoleUI.attach = function(guac) { var mouse = new Guacamole.Mouse(GuacamoleUI.display); mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = function(mouseState) { - - if (mouseState.y <= 5) - GuacamoleUI.showMenu(); - guac.sendMouseState(mouseState); }; diff --git a/guacamole/src/main/webapp/styles/client.css b/guacamole/src/main/webapp/styles/client.css index 3dfe2bf6a..4b4099106 100644 --- a/guacamole/src/main/webapp/styles/client.css +++ b/guacamole/src/main/webapp/styles/client.css @@ -73,17 +73,14 @@ div.errorDialog p { #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; + z-index: 4; + background: #FEA; + border-bottom: 1px solid black; + font-size: 0.8em; } #menu.error { @@ -127,11 +124,7 @@ div#clipboardDiv { border: 1px solid black; width: 50em; - opacity: 0.5; -} - -#menu:hover div#clipboardDiv { - opacity: 1; + z-index: 2; } div#clipboardDiv h2 { @@ -161,3 +154,14 @@ div#clipboardDiv textarea { cursor: url('../images/mouse/dot.gif'),url('../images/mouse/blank.cur'),default; } +div#menuControl { + position: fixed; + top: 0; + left: 0; + + width: 100%; + height: 1.5em; + background: none; + + z-index: 3; +} From 5048d171d5edaba4088087f74fbc2b57ce447555 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 19 Dec 2011 16:45:23 -0800 Subject: [PATCH 5/7] Improved menu hiding behavior and style. --- .../src/main/webapp/scripts/interface.js | 64 +++++++++---------- guacamole/src/main/webapp/styles/client.css | 7 +- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/guacamole/src/main/webapp/scripts/interface.js b/guacamole/src/main/webapp/scripts/interface.js index 4d24b9279..57ef57c76 100644 --- a/guacamole/src/main/webapp/scripts/interface.js +++ b/guacamole/src/main/webapp/scripts/interface.js @@ -56,7 +56,7 @@ var GuacamoleUI = { if (!menu_shaded) { - var step = Math.floor(GuacamoleUI.menu.offsetHeight / 5) + 1; + var step = Math.floor(GuacamoleUI.menu.offsetHeight / 10) + 1; var offset = 0; menu_shaded = true; @@ -151,31 +151,7 @@ var GuacamoleUI = { }, true); - GuacamoleUI.menu.addEventListener('mouseout', function(e) { - - // Get parent of the element the mouse pointer is leaving - if (!e) e = window.event; - var target = e.relatedTarget || e.toElement; - - // Ensure target is not menu nor child of menu - var targetParent = target; - while (targetParent != null) { - if (targetParent == GuacamoleUI.menu) return; - targetParent = targetParent.parentNode; - } - - // If not already waiting, start detection of mouse leave - if (detectMenuCloseTimeout == null) { - detectMenuCloseTimeout = window.setTimeout(function() { - GuacamoleUI.shadeMenu(); - detectMenuCloseTimeout = null; - }, 750); - } - - }, true); - - // When mouse hovers over top of screen, start detection of mouse hover - GuacamoleUI.menuControl.addEventListener('mousemove', function() { + function menuShowHandler() { // If we were waiting for menu close, we're not anymore if (detectMenuCloseTimeout != null) { @@ -189,21 +165,42 @@ var GuacamoleUI = { detectMenuOpenTimeout = null; } - // If not alread waiting, wait for 250ms before showing menu + // If not alread waiting, wait before showing menu detectMenuOpenTimeout = window.setTimeout(function() { GuacamoleUI.showMenu(); detectMenuOpenTimeout = null; - }, 250); + }, 325); + } + + // Show menu of mouseover any part of menu + GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true); + + // When mouse hovers over top of screen, start detection of mouse hover + GuacamoleUI.menuControl.addEventListener('mousemove', menuShowHandler, true); + document.addEventListener('mouseout', function(e) { + + // Get parent of the element the mouse pointer is leaving + if (!e) e = window.event; + var target = e.relatedTarget || e.toElement; + + // Ensure target is not menu nor child of menu + var targetParent = target; + while (targetParent != null) { + if (targetParent == document) return; + targetParent = targetParent.parentNode; + } + + menuShowHandler(); + }, true); - // When mouse leaves top of screen, cancel showing the menu - GuacamoleUI.menuControl.addEventListener('mouseout', function() { + GuacamoleUI.display.addEventListener('mouseover', function() { - // If we were waiting for menu open, we're not anymore + // If we were detecting menu open, stop it if (detectMenuOpenTimeout != null) { window.clearTimeout(detectMenuOpenTimeout); - detectMenuCloseTimeout = null; + detectMenuOpenTimeout = null; } // If not already waiting, start detection of mouse leave @@ -211,12 +208,11 @@ var GuacamoleUI = { detectMenuCloseTimeout = window.setTimeout(function() { GuacamoleUI.shadeMenu(); detectMenuCloseTimeout = null; - }, 750); + }, 500); } }, true); - // Reconnect button GuacamoleUI.buttons.reconnect.onclick = function() { window.location.reload(); diff --git a/guacamole/src/main/webapp/styles/client.css b/guacamole/src/main/webapp/styles/client.css index 4b4099106..f853effa3 100644 --- a/guacamole/src/main/webapp/styles/client.css +++ b/guacamole/src/main/webapp/styles/client.css @@ -125,6 +125,11 @@ div#clipboardDiv { width: 50em; z-index: 2; + opacity: 0.5; +} + +#menu:hover div#clipboardDiv { + opacity: 1; } div#clipboardDiv h2 { @@ -160,7 +165,7 @@ div#menuControl { left: 0; width: 100%; - height: 1.5em; + height: 3px; background: none; z-index: 3; From 6e3ff98b5a0cccbb6008b3251b6fdb4ff0980803 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 19 Dec 2011 17:01:41 -0800 Subject: [PATCH 6/7] Cleaned up menu shading code. --- .../src/main/webapp/scripts/interface.js | 89 ++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/guacamole/src/main/webapp/scripts/interface.js b/guacamole/src/main/webapp/scripts/interface.js index 57ef57c76..03f83ee23 100644 --- a/guacamole/src/main/webapp/scripts/interface.js +++ b/guacamole/src/main/webapp/scripts/interface.js @@ -138,34 +138,33 @@ var GuacamoleUI = { window.location.href = "logout"; }; + // Timeouts for detecting if users wants menu to open or close var detectMenuOpenTimeout = null; var detectMenuCloseTimeout = null; - GuacamoleUI.menu.addEventListener('mouseover', function() { + // Clear detection timeouts + function resetMenuDetect() { - // If we were waiting for menu close, we're not anymore - if (detectMenuCloseTimeout != null) { - window.clearTimeout(detectMenuCloseTimeout); - detectMenuCloseTimeout = null; - } - - }, true); - - function menuShowHandler() { - - // If we were waiting for menu close, we're not anymore - if (detectMenuCloseTimeout != null) { - window.clearTimeout(detectMenuCloseTimeout); - detectMenuCloseTimeout = null; - } - - // Clear old timeout if mouse moved while we were waiting if (detectMenuOpenTimeout != null) { window.clearTimeout(detectMenuOpenTimeout); detectMenuOpenTimeout = null; } - // If not alread waiting, wait before showing menu + if (detectMenuCloseTimeout != null) { + window.clearTimeout(detectMenuCloseTimeout); + detectMenuCloseTimeout = null; + } + + } + + // Initiate detection of menu open action. If not canceled through some + // user event, menu will open. + function startMenuOpenDetect() { + + // Clear detection state + resetMenuDetect(); + + // Wait and then show menu detectMenuOpenTimeout = window.setTimeout(function() { GuacamoleUI.showMenu(); detectMenuOpenTimeout = null; @@ -173,46 +172,52 @@ var GuacamoleUI = { } - // Show menu of mouseover any part of menu + // Initiate detection of menu close action. If not canceled through some + // user event, menu will close. + function startMenuCloseDetect() { + + // Clear detection state + resetMenuDetect(); + + // Wait and then shade menu + detectMenuCloseTimeout = window.setTimeout(function() { + GuacamoleUI.shadeMenu(); + detectMenuCloseTimeout = null; + }, 500); + + } + + // Show menu if mouseover any part of menu GuacamoleUI.menu.addEventListener('mouseover', GuacamoleUI.showMenu, true); - // When mouse hovers over top of screen, start detection of mouse hover - GuacamoleUI.menuControl.addEventListener('mousemove', menuShowHandler, true); + // Stop detecting menu state change intents if mouse is over menu + GuacamoleUI.menu.addEventListener('mouseover', resetMenuDetect, true); + + // When mouse hovers over top of screen, start detection of intent to open menu + GuacamoleUI.menuControl.addEventListener('mousemove', startMenuOpenDetect, true); + + // When mouse enters display, start detection of intent to close menu + GuacamoleUI.display.addEventListener('mouseover', startMenuCloseDetect, true); + + // Show menu if mouse leaves document document.addEventListener('mouseout', function(e) { // Get parent of the element the mouse pointer is leaving if (!e) e = window.event; var target = e.relatedTarget || e.toElement; - // Ensure target is not menu nor child of menu + // Ensure target is not document nor child of document var targetParent = target; while (targetParent != null) { if (targetParent == document) return; targetParent = targetParent.parentNode; } - menuShowHandler(); + // Start detection of intent to open menu + startMenuOpenDetect(); }, true); - GuacamoleUI.display.addEventListener('mouseover', function() { - - // If we were detecting menu open, stop it - if (detectMenuOpenTimeout != null) { - window.clearTimeout(detectMenuOpenTimeout); - detectMenuOpenTimeout = null; - } - - // If not already waiting, start detection of mouse leave - if (detectMenuCloseTimeout == null) { - detectMenuCloseTimeout = window.setTimeout(function() { - GuacamoleUI.shadeMenu(); - detectMenuCloseTimeout = null; - }, 500); - } - - }, true); - // Reconnect button GuacamoleUI.buttons.reconnect.onclick = function() { window.location.reload(); From 8481bc4f0c611103606facfd7d4a163c7517050e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 20 Dec 2011 00:00:39 -0800 Subject: [PATCH 7/7] Changed 'No authorized configurations' message to something more reasonable. --- .../guacamole/net/basic/BasicGuacamoleTunnelServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java index e1b5d292c..44123c305 100644 --- a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java +++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/BasicGuacamoleTunnelServlet.java @@ -57,7 +57,7 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet { // If no configs in session, not authorized if (configs == null) - throw new GuacamoleException("No authorized configurations."); + throw new GuacamoleException("Cannot connect - user not logged in."); // Get authorized config GuacamoleConfiguration config = configs.get(id);