diff --git a/extensions/guacamole-display-statistics/.gitignore b/extensions/guacamole-display-statistics/.gitignore
new file mode 100644
index 000000000..e55f47f1f
--- /dev/null
+++ b/extensions/guacamole-display-statistics/.gitignore
@@ -0,0 +1 @@
+src/main/resources/generated/
diff --git a/extensions/guacamole-display-statistics/.ratignore b/extensions/guacamole-display-statistics/.ratignore
new file mode 100644
index 000000000..da318d12f
--- /dev/null
+++ b/extensions/guacamole-display-statistics/.ratignore
@@ -0,0 +1 @@
+src/main/resources/html/*.html
diff --git a/extensions/guacamole-display-statistics/pom.xml b/extensions/guacamole-display-statistics/pom.xml
new file mode 100644
index 000000000..403d974cf
--- /dev/null
+++ b/extensions/guacamole-display-statistics/pom.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ 4.0.0
+ org.apache.guacamole
+ guacamole-display-statistics
+ jar
+ 1.4.0
+ guacamole-display-statistics
+ http://guacamole.apache.org/
+
+
+ org.apache.guacamole
+ extensions
+ 1.4.0
+ ../
+
+
+
+
+
+
+
+ com.keithbranton.mojo
+ angular-maven-plugin
+ 0.3.4
+
+
+ generate-resources
+
+ html2js
+
+
+
+
+ ${basedir}/src/main/resources
+ **/*.html
+ ${basedir}/src/main/resources/generated/templates-main/templates.js
+ app/ext/display-stats
+
+
+
+
+
+ com.github.buckelieg
+ minify-maven-plugin
+
+
+ default-cli
+
+ UTF-8
+
+ ${basedir}/src/main/resources
+ ${project.build.directory}/classes
+
+ /
+ /
+ display-stats.css
+
+
+ license.txt
+
+
+
+ **/*.css
+
+
+ /
+ /
+ display-stats.js
+
+
+ license.txt
+
+
+
+ **/*.js
+
+
+
+
+ **/*.test.js
+
+ CLOSURE
+
+
+
+ OFF
+ OFF
+
+
+
+
+ minify
+
+
+
+
+
+
+
+
+
diff --git a/extensions/guacamole-display-statistics/src/main/assembly/dist.xml b/extensions/guacamole-display-statistics/src/main/assembly/dist.xml
new file mode 100644
index 000000000..0b16a7147
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/assembly/dist.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ dist
+ ${project.artifactId}-${project.version}
+
+
+
+ tar.gz
+
+
+
+
+
+
+
+
+ target/licenses
+
+
+
+
+ target
+
+
+ *.jar
+
+
+
+
+
+
diff --git a/extensions/guacamole-display-statistics/src/main/resources/directives/guacClientStatistics.js b/extensions/guacamole-display-statistics/src/main/resources/directives/guacClientStatistics.js
new file mode 100644
index 000000000..4dc6b8a15
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/directives/guacClientStatistics.js
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * A directive which displays frame rendering performance statistics for a
+ * Guacamole client.
+ */
+angular.module('client').directive('guacClientStatistics', [function guacClientStatistics() {
+
+ const directive = {
+ restrict: 'E',
+ templateUrl: 'app/ext/display-stats/templates/guacClientStatistics.html',
+ };
+
+ directive.scope = {
+
+ /**
+ * The Guacamole client to display frame rendering statistics for.
+ *
+ * @type ManagedClient
+ */
+ client : '='
+
+ };
+
+ directive.controller = ['$scope', function guacClientStatisticsController($scope) {
+
+ /**
+ * Updates the displayed frame rendering statistics to the values
+ * within the given statistics object.
+ *
+ * @param {!Guacamole.Display.Statistics} stats
+ * An object containing general rendering performance statistics for
+ * the remote desktop, Guacamole server, and Guacamole client.
+ */
+ var updateStatistics = function updateStatistics(stats) {
+ $scope.$apply(function statisticsChanged() {
+ $scope.statistics = stats;
+ });
+ };
+
+ /**
+ * Returns whether the given value is a defined value that should be
+ * rendered within the statistics toolbar.
+ *
+ * @param {number} value
+ * The value to test.
+ *
+ * @returns {!boolean}
+ * true if the given value should be rendered within the statistics
+ * toolbar, false otherwise.
+ */
+ $scope.hasValue = function hasValue(value) {
+ return value || value === 0;
+ };
+
+ /**
+ * Rounds the given numeric value to the nearest hundredth (two decimal places).
+ *
+ * @param {!number} value
+ * The value to round.
+ *
+ * @param {!number}
+ * The given value, rounded to the nearest hundredth.
+ */
+ $scope.round = function round(value) {
+ return Math.round(value * 100) / 100;
+ };
+
+ // Assign/remove onstatistics handlers to track the statistics of the
+ // current client
+ $scope.$watch('client', function clientChanged(client, oldClient) {
+
+ if (oldClient)
+ oldClient.managedDisplay.display.onstatistics = null;
+
+ client.managedDisplay.display.statisticWindow = 1000;
+ client.managedDisplay.display.onstatistics = updateStatistics;
+
+ });
+
+ // Clear onstatistics handler when directive is being unloaded
+ $scope.$on('$destroy', function scopeDestroyed() {
+ if ($scope.client)
+ $scope.client.managedDisplay.display.onstatistics = null;
+ });
+
+ }];
+
+ return directive;
+
+}]);
diff --git a/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json b/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json
new file mode 100644
index 000000000..71c84b384
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json
@@ -0,0 +1,28 @@
+{
+
+ "guacamoleVersion" : "1.4.0",
+
+ "name" : "Display Statistic Toolbar",
+ "namespace" : "display-stats",
+
+ "translations" : [
+ "translations/en.json"
+ ],
+
+ "js" : [
+ "display-stats.min.js"
+ ],
+
+ "css" : [
+ "display-stats.min.css"
+ ],
+
+ "html" : [
+ "html/add-statistics.html"
+ ],
+
+ "resources" : {
+ "templates/guacClientStatistics.html" : "text/html"
+ }
+
+}
diff --git a/extensions/guacamole-display-statistics/src/main/resources/html/add-statistics.html b/extensions/guacamole-display-statistics/src/main/resources/html/add-statistics.html
new file mode 100644
index 000000000..5978f7f58
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/html/add-statistics.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/extensions/guacamole-display-statistics/src/main/resources/license.txt b/extensions/guacamole-display-statistics/src/main/resources/license.txt
new file mode 100644
index 000000000..042f3ce1f
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/license.txt
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
diff --git a/extensions/guacamole-display-statistics/src/main/resources/styles/clientStatistics.css b/extensions/guacamole-display-statistics/src/main/resources/styles/clientStatistics.css
new file mode 100644
index 000000000..ba4661469
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/styles/clientStatistics.css
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+guac-client-statistics {
+ font-size: 13px;
+ color: white;
+ background: #111;
+}
+
+guac-client-statistics dl.client-statistics {
+ display: table;
+ margin: 0;
+ padding: 0.25em;
+}
+
+guac-client-statistics dl.client-statistics dt,
+guac-client-statistics dl.client-statistics dd {
+ display: table-cell;
+ padding: 0.25em;
+}
+
+guac-client-statistics dl.client-statistics dt {
+ padding-right: 0.5em;
+ padding-left: 1em;
+}
+
+guac-client-statistics dl.client-statistics dt:first-child {
+ padding-left: 0.5em;
+}
+
+guac-client-statistics dl.client-statistics dd {
+ min-width: 6em;
+ border: 1px solid rgba(255, 255, 255, 0.125);
+ border-radius: 3px;
+ background: black;
+}
+
+guac-client-statistics dl.client-statistics dd.no-value::before {
+ color: #888;
+ content: '-';
+}
diff --git a/extensions/guacamole-display-statistics/src/main/resources/templates/guacClientStatistics.html b/extensions/guacamole-display-statistics/src/main/resources/templates/guacClientStatistics.html
new file mode 100644
index 000000000..ae7537c0f
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/templates/guacClientStatistics.html
@@ -0,0 +1,39 @@
+
+
+ -
+ {{ 'CLIENT.FIELD_HEADER_DESKTOP_FRAMERATE' | translate }}
+
+ -
+
+
+
+ -
+ {{ 'CLIENT.FIELD_HEADER_SERVER_FRAMERATE' | translate }}
+
+ -
+
+
+
+ -
+ {{ 'CLIENT.FIELD_HEADER_CLIENT_FRAMERATE' | translate }}
+
+ -
+
+
+
+ -
+ {{ 'CLIENT.FIELD_HEADER_DROP_FRAMERATE' | translate }}
+
+ -
+
+
+
+
\ No newline at end of file
diff --git a/extensions/guacamole-display-statistics/src/main/resources/translations/en.json b/extensions/guacamole-display-statistics/src/main/resources/translations/en.json
new file mode 100644
index 000000000..ef42908e4
--- /dev/null
+++ b/extensions/guacamole-display-statistics/src/main/resources/translations/en.json
@@ -0,0 +1,12 @@
+{
+ "CLIENT" : {
+
+ "FIELD_HEADER_CLIENT_FRAMERATE" : "Guacamole (Client):",
+ "FIELD_HEADER_DESKTOP_FRAMERATE" : "Remote Desktop:",
+ "FIELD_HEADER_DROP_FRAMERATE" : "Drop:",
+ "FIELD_HEADER_SERVER_FRAMERATE" : "Guacamole (Server):",
+
+ "INFO_FRAMERATE" : "{VALUE} fps"
+
+ }
+}
diff --git a/extensions/pom.xml b/extensions/pom.xml
index de2b24556..3bab33257 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -53,6 +53,9 @@
guacamole-history-recording-storage
guacamole-vault
+
+ guacamole-display-statistics
+