Browse Source

Initial commit

johni0702 7 years ago
commit
7bad9baaaf
63 changed files with 2135 additions and 0 deletions
  1. 54 0
      .gitignore
  2. 91 0
      README.md
  3. BIN
      app/favicon/android-chrome-192x192.png
  4. BIN
      app/favicon/android-chrome-512x512.png
  5. BIN
      app/favicon/apple-touch-icon.png
  6. 9 0
      app/favicon/browserconfig.xml
  7. BIN
      app/favicon/favicon-16x16.png
  8. BIN
      app/favicon/favicon-32x32.png
  9. BIN
      app/favicon/favicon.ico
  10. 17 0
      app/favicon/manifest.json
  11. BIN
      app/favicon/mstile-144x144.png
  12. BIN
      app/favicon/mstile-150x150.png
  13. BIN
      app/favicon/mstile-310x150.png
  14. BIN
      app/favicon/mstile-310x310.png
  15. BIN
      app/favicon/mstile-70x70.png
  16. 44 0
      app/favicon/safari-pinned-tab.svg
  17. 221 0
      app/index.html
  18. 512 0
      app/index.js
  19. 48 0
      package.json
  20. 33 0
      themes/MetroMumbleLight/loading.css
  21. 252 0
      themes/MetroMumbleLight/main.css
  22. 23 0
      themes/MetroMumbleLight/svg/applications-internet.svg
  23. 16 0
      themes/MetroMumbleLight/svg/audio-input-microphone-muted.svg
  24. 16 0
      themes/MetroMumbleLight/svg/audio-input-microphone.svg
  25. 15 0
      themes/MetroMumbleLight/svg/audio-output-deafened.svg
  26. 30 0
      themes/MetroMumbleLight/svg/audio-output.svg
  27. 7 0
      themes/MetroMumbleLight/svg/authenticated.svg
  28. 7 0
      themes/MetroMumbleLight/svg/branch_closed.svg
  29. 7 0
      themes/MetroMumbleLight/svg/branch_open.svg
  30. 6 0
      themes/MetroMumbleLight/svg/channel.svg
  31. 6 0
      themes/MetroMumbleLight/svg/channel_active.svg
  32. 23 0
      themes/MetroMumbleLight/svg/channel_linked.svg
  33. 13 0
      themes/MetroMumbleLight/svg/comment.svg
  34. 9 0
      themes/MetroMumbleLight/svg/comment_seen.svg
  35. 24 0
      themes/MetroMumbleLight/svg/config_basic.svg
  36. 15 0
      themes/MetroMumbleLight/svg/deafened_self.svg
  37. 15 0
      themes/MetroMumbleLight/svg/deafened_server.svg
  38. 16 0
      themes/MetroMumbleLight/svg/default_avatar.svg
  39. 35 0
      themes/MetroMumbleLight/svg/filter.svg
  40. 35 0
      themes/MetroMumbleLight/svg/filter_off.svg
  41. 22 0
      themes/MetroMumbleLight/svg/filter_on.svg
  42. 11 0
      themes/MetroMumbleLight/svg/handle_horizontal.svg
  43. 11 0
      themes/MetroMumbleLight/svg/handle_vertical.svg
  44. 13 0
      themes/MetroMumbleLight/svg/information_icon.svg
  45. 38 0
      themes/MetroMumbleLight/svg/layout_classic.svg
  46. 50 0
      themes/MetroMumbleLight/svg/layout_custom.svg
  47. 38 0
      themes/MetroMumbleLight/svg/layout_hybrid.svg
  48. 40 0
      themes/MetroMumbleLight/svg/layout_stacked.svg
  49. 12 0
      themes/MetroMumbleLight/svg/media-record.svg
  50. 37 0
      themes/MetroMumbleLight/svg/mumble.svg
  51. 13 0
      themes/MetroMumbleLight/svg/muted_local.svg
  52. 15 0
      themes/MetroMumbleLight/svg/muted_self.svg
  53. 15 0
      themes/MetroMumbleLight/svg/muted_server.svg
  54. 15 0
      themes/MetroMumbleLight/svg/muted_suppressed.svg
  55. 29 0
      themes/MetroMumbleLight/svg/priority_speaker.svg
  56. 14 0
      themes/MetroMumbleLight/svg/self_comment.svg
  57. 3 0
      themes/MetroMumbleLight/svg/source-code.svg
  58. 13 0
      themes/MetroMumbleLight/svg/talking_alt.svg
  59. 14 0
      themes/MetroMumbleLight/svg/talking_off.svg
  60. 14 0
      themes/MetroMumbleLight/svg/talking_on.svg
  61. 13 0
      themes/MetroMumbleLight/svg/talking_whisper.svg
  62. 13 0
      themes/MetroMumbleLight/svg/toolbar-comment.svg
  63. 93 0
      webpack.config.js

+ 54 - 0
.gitignore

@@ -0,0 +1,54 @@
+dist
+
+# Created by https://www.gitignore.io/api/node
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules
+jspm_packages
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+

+ 91 - 0
README.md

@@ -0,0 +1,91 @@
+# mumble-web
+
+mumble-web is an HTML5 [Mumble] client for use in modern browsers.
+
+A live demo is running [here](https://voice.johni0702.de/?address=voice.johni0702.de&port=443/demo).
+
+The Mumble protocol uses TCP for control and UDP for voice.
+Running in a browser, both are unavailable to this client.
+Instead Websockets are used for all communications.
+
+libopus and libsamplerate, compiled to JS via emscripten, are used for audio decoding.
+Therefore, at the moment only the Opus codec is supported.
+
+Quite a few features, most noticeably voice activity detection and all
+administrative functionallity, are still missing.
+
+### Installing
+
+#### Download
+mumble-web can either be installed directly from npm with `npm install -g mumble-web`
+or from git:
+
+```
+git clone https://github.com/johni0702/mumble-web
+cd mumble-web
+npm install
+npm run build
+```
+
+The npm version is prebuilt and ready to use whereas the git version allows you
+to e.g. customize the theme before building it.
+
+Either way you will end up with a `dist` folder that contains the static page.
+
+#### Setup
+At the time of writing this there do not seem to be any Mumble servers
+which natively support Websockets. To use this client with any standard mumble
+server, websockify must be set up (preferably on the same machine that the
+Mumble server is running on).
+
+You can install websockify via `npm install -g websockify` or via your package
+manager `apt install websockify`.
+
+There are two basic ways you can use websockify with mumble-web:
+- Standalone, use websockify for both, websockets and serving static files
+- Proxied, let your favorite web server serve static files and proxy websocket connections to websockify
+
+##### Standalone
+This is the simplest but at the same time least flexible configuration.
+```
+websockify --cert=mycert.crt --key=mykey.key --ssl-only --ssl-target --web=path/to/dist 443 mumbleserver:64738
+```
+
+##### Proxied
+This configuration allows you to run websockify on a machine that already has
+another webserver running.
+```
+websockify --ssl-target 64737 mumbleserver:64738
+```
+
+A sample configuration for nginx that allows access to mumble-web at 
+`https://voice.example.com/` and connecting at `wss://voice.example.com/demo`
+(similar to the demo server) looks like this:
+```
+server {
+        listen 443 ssl;
+        server_name voice.example.com;
+        ssl_certificate /etc/letsencrypt/live/voice.example.com/fullchain.pem;
+        ssl_certificate_key /etc/letsencrypt/live/voice.example.com/privkey.pem;
+
+        location / {
+                root /path/to/dist;
+        }
+        location /mumble {
+                proxy_pass http://websockify:64737;
+                proxy_http_version 1.1;
+                proxy_set_header Upgrade $http_upgrade;
+                proxy_set_header Connection $connection_upgrade;
+        }
+}
+
+map $http_upgrade $connection_upgrade {
+        default upgrade;
+        '' close;
+}
+```
+
+### License
+ISC
+
+[Mumble]: https://wiki.mumble.info/wiki/Main_Page

BIN
app/favicon/android-chrome-192x192.png


BIN
app/favicon/android-chrome-512x512.png


BIN
app/favicon/apple-touch-icon.png


+ 9 - 0
app/favicon/browserconfig.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<browserconfig>
+  <msapplication>
+    <tile>
+      <square150x150logo src="#require('./mstile-150x150.png')"/>
+      <TileColor>#da532c</TileColor>
+    </tile>
+  </msapplication>
+</browserconfig>

BIN
app/favicon/favicon-16x16.png


BIN
app/favicon/favicon-32x32.png


BIN
app/favicon/favicon.ico


+ 17 - 0
app/favicon/manifest.json

@@ -0,0 +1,17 @@
+{
+	"name": "Mumble",
+	"icons": [
+		{
+			"src": "#require('./android-chrome-192x192.png')",
+			"sizes": "192x192",
+			"type": "image\/png"
+		},
+		{
+			"src": "#require('./android-chrome-512x512.png')",
+			"sizes": "512x512",
+			"type": "image\/png"
+		}
+	],
+	"theme_color": "#ffffff",
+	"display": "standalone"
+}

BIN
app/favicon/mstile-144x144.png


BIN
app/favicon/mstile-150x150.png


BIN
app/favicon/mstile-310x150.png


BIN
app/favicon/mstile-310x310.png


BIN
app/favicon/mstile-70x70.png


+ 44 - 0
app/favicon/safari-pinned-tab.svg

@@ -0,0 +1,44 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
+ width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
+ preserveAspectRatio="xMidYMid meet">
+<metadata>
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+</metadata>
+<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
+fill="#000000" stroke="none">
+<path d="M3245 6924 c-230 -22 -403 -51 -577 -94 -1229 -307 -2191 -1269
+-2498 -2498 -30 -123 -60 -282 -82 -442 -17 -128 -17 -652 0 -780 76 -553 226
+-984 498 -1422 510 -824 1365 -1403 2314 -1567 235 -41 302 -46 600 -46 298 0
+365 5 600 46 949 164 1804 743 2314 1567 272 438 422 869 498 1422 17 128 17
+652 0 780 -88 645 -296 1171 -654 1652 -564 758 -1367 1229 -2323 1364 -105
+14 -594 27 -690 18z m559 -75 c553 -44 1107 -241 1585 -566 185 -126 309 -229
+487 -407 281 -282 462 -531 638 -882 255 -509 369 -1057 344 -1657 -29 -692
+-275 -1352 -719 -1923 -106 -137 -392 -426 -526 -532 -515 -406 -1066 -639
+-1718 -724 -134 -17 -656 -17 -790 0 -652 85 -1203 318 -1718 724 -134 106
+-420 395 -526 532 -444 571 -690 1231 -719 1923 -21 502 54 959 229 1400 122
+308 301 614 511 877 105 130 374 399 504 504 524 420 1161 678 1810 732 224
+18 368 18 608 -1z"/>
+<path d="M4199 6540 c-103 -18 -191 -76 -229 -151 -39 -75 -42 -136 -39 -874
+2 -701 2 -711 -19 -776 -39 -118 -103 -189 -210 -230 -80 -31 -265 -38 -347
+-14 -177 51 -255 131 -288 295 -13 64 -15 180 -10 810 6 803 9 755 -49 820
+-76 84 -161 110 -351 110 -167 0 -235 -10 -366 -52 -350 -112 -616 -367 -711
+-683 -51 -169 -60 -312 -60 -992 l0 -542 -83 -39 c-252 -118 -482 -353 -631
+-645 -228 -447 -268 -1030 -105 -1522 137 -410 404 -754 704 -905 135 -68 229
+-91 375 -91 184 0 257 34 277 129 9 40 11 3221 3 3822 -5 385 -1 446 41 607
+25 93 77 196 131 258 49 56 145 104 222 112 l58 6 -3 -634 c-4 -721 -7 -697
+78 -868 113 -229 305 -340 643 -371 188 -18 526 -8 645 18 173 39 278 88 376
+179 96 89 157 199 195 353 18 70 19 115 15 699 l-3 624 69 -5 c76 -6 157 -37
+210 -82 68 -58 129 -179 158 -315 35 -167 37 -312 30 -2171 -3 -1004 -7 -1897
+-8 -1985 -1 -186 11 -246 67 -311 l34 -40 -63 -47 c-35 -25 -104 -70 -152 -99
+l-88 -53 -317 -3 -317 -3 -12 23 c-35 69 -138 141 -264 184 -74 25 -93 27
+-245 28 -183 1 -245 -10 -356 -64 -296 -144 -264 -436 62 -551 74 -26 210 -49
+290 -49 89 0 220 25 301 58 80 32 100 45 159 102 l43 41 313 -1 c337 0 378 4
+476 54 122 62 480 320 502 361 9 17 35 30 99 50 434 134 750 509 885 1050 78
+314 85 646 21 970 -35 173 -75 289 -160 460 -147 296 -337 496 -596 630 -58
+30 -112 61 -119 70 -17 20 -17 43 -1 460 15 397 10 685 -14 825 -43 239 -118
+414 -244 568 -110 134 -428 303 -691 367 -112 27 -261 38 -331 25z"/>
+</g>
+</svg>

+ 221 - 0
app/index.html

@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <!-- Favicon as generated by realfavicongenerator.net (slightly modified for webpack) -->
+    <link rel="apple-touch-icon" sizes="180x180" href="favicon/apple-touch-icon.png">
+    <link rel="icon" type="image/png" href="favicon/favicon-32x32.png" sizes="32x32">
+    <link rel="icon" type="image/png" href="favicon/favicon-16x16.png" sizes="16x16">
+    <link rel="manifest" href="favicon/manifest.json">
+    <link rel="mask-icon" href="favicon/safari-pinned-tab.svg" color="#5bbad5">
+    <link rel="shortcut icon" href="favicon/favicon.ico">
+    <meta name="apple-mobile-web-app-title" content="Mumble">
+    <meta name="application-name" content="Mumble">
+    <meta name="msapplication-config" content="${require('./favicon/browserconfig.xml')}">
+    <meta name="theme-color" content="#ffffff">
+
+    <link rel="stylesheet" type="text/css" href="/loading.css">
+  </head>
+  <body>
+    <div class="loading-container" data-bind="css: { loaded: true }">
+      <div class="loading-circle" data-bind="css: { loaded: true }"></div>
+    </div>
+    <div id="container" style="display: none" data-bind="visible: true">
+      <!-- ko with: connectDialog -->
+        <div class="connect-dialog" data-bind="visible: visible">
+          <div class="dialog-header">
+            Connect to Server
+          </div>
+          <form data-bind="submit: connect">
+            <table>
+                <tr>
+                  <td>Address</td>
+                  <td><input id="address" type="text" data-bind="value: address"></td>
+                </tr>
+                <tr>
+                  <td>Port</td>
+                  <td><input id="port" type="text" data-bind="value: port"></td>
+                </tr>
+                <tr>
+                  <td>Token</td>
+                  <td><input id="token" type="text" data-bind="value: token"></td>
+                </tr>
+                <tr>
+                  <td>Username</td>
+                  <td><input id="username" type="text" data-bind="value: username"></td>
+                </tr>
+            </table>
+            <div class="dialog-footer">
+              <input class="dialog-close" type="button" data-bind="click: hide" value="Cancel">
+              <input class="dialog-submit" type="submit" value="Connect">
+            </div>
+          </form>
+        </div>
+      <!-- /ko -->
+      <script type="text/html" id="user-tag">
+        <span class="user-tag" data-bind="text: name"></span>
+      </script>
+      <script type="text/html" id="channel-tag">
+        <span class="channel-tag" data-bind="text: name"></span>
+      </script>
+      <div class="toolbar">
+        <img class="handle-horizontal" src="/svg/handle_horizontal.svg">
+        <img class="handle-vertical" src="/svg/handle_horizontal.svg">
+        <img class="tb-connect" data-bind="click: connectDialog.show"
+                      rel="connect" src="/svg/applications-internet.svg">
+        <img class="tb-information" data-bind="click: connectionInfo.show"
+                      rel="information" src="/svg/information_icon.svg">
+        <div class="divider"></div>
+        <img class="tb-mute" data-bind="visible: !thisUser() || !thisUser().selfMute(),
+                              click: function () { requestMute(thisUser) }"
+                      rel="mute" src="/svg/audio-input-microphone.svg">
+        <img class="tb-unmute tb-active" data-bind="visible: thisUser() && thisUser().selfMute(),
+                              click: function () { requestUnmute(thisUser) }"
+                      rel="unmute" src="/svg/audio-input-microphone-muted.svg">
+        <img class="tb-deaf" data-bind="visible: !thisUser() || !thisUser().selfDeaf(),
+                              click: function () { requestDeaf(thisUser) }"
+                      rel="deaf" src="/svg/audio-output.svg">
+        <img class="tb-undeaf tb-active" data-bind="visible: thisUser() && thisUser().selfDeaf(),
+                              click: function () { requestUndeaf(thisUser) }"
+                      rel="undeaf" src="/svg/audio-output-deafened.svg">
+        <img class="tb-record" data-bind="click: function(){}"
+                      rel="record" src="/svg/media-record.svg">
+        <div class="divider"></div>
+        <img class="tb-comment" data-bind="click: commentDialog.show"
+                      rel="comment" src="/svg/toolbar-comment.svg">
+        <div class="divider"></div>
+        <img class="tb-settings" data-bind="click: settingsDialog.show"
+                      rel="settings" src="/svg/config_basic.svg">
+        <div class="divider"></div>
+        <img class="tb-sourcecode" data-bind="click: openSourceCode"
+                      rel="Source Code" src="/svg/source-code.svg">
+      </div>
+      <div class="chat">
+        <script type="text/html" id="log-generic">
+          <span data-bind="text: value"></span>
+        </script>
+        <script type="text/html" id="log-welcome-message">
+          Welcome message: <span data-bind="html: message"></span>
+        </script>
+        <script type="text/html" id="log-chat-message">
+          <span data-bind="visible: channel">
+            (Channel)
+          </span>
+          <span data-bind="template: { name: 'user-tag', data: user }"></span>:
+          <span class="message-content" data-bind="html: message"></span>
+        </script>
+        <script type="text/html" id="log-chat-message-self">
+          To
+          <span data-bind="template: { if: $data.channel, name: 'channel-tag', data: $data.channel }">
+          </span><span data-bind="template: { if: $data.user, name: 'user-tag', data: $data.user }">
+          </span>:
+          <span class="message-content" data-bind="html: message"></span>
+        </script>
+        <script type="text/html" id="log-disconnect">
+        </script>
+        <div class="log" data-bind="foreach: {
+          data: log,
+          afterRender: function (e) {
+            [].forEach.call(e[1].getElementsByTagName('a'), function(e){e.target = '_blank'})
+          }
+        }">
+          <div class="log-entry">
+            <span class="log-timestamp" data-bind="text: $root.getTimeString()"></span>
+            <!-- ko template: { data: $data, name: function(l) { return 'log-' + l.type; } } -->
+            <!-- /ko -->
+          </div>
+        </div>
+        <form data-bind="submit: submitMessageBox">
+          <input id="message-box" type="text" data-bind="
+              attr: { placeholder: messageBoxHint }, textInput: messageBox">
+        </form>
+      </div>
+      <script type="text/html" id="channel">
+        <div class="channel" data-bind="
+            click: $root.select, 
+            event: {
+              dblclick: $root.requestMove.bind($root, $root.thisUser())
+            },
+            css: {
+              selected: $root.selected() === $data,
+              currentChannel: users.indexOf($root.thisUser()) !== -1
+            }">
+          <div class="channel-status">
+            <img class="channel-description" data-bind="visible: description"
+                alt="description" src="/svg/comment.svg">
+          </div>
+          <div data-bind="if: description">
+            <div class="channel-description tooltip" data-bind="html: description"></div>
+          </div>
+          <img class="channel-icon" src="/svg/channel.svg"
+            data-bind="visible: !linked() && $root.thisUser().channel() !== $data">
+          <img class="channel-icon-active" src="/svg/channel_active.svg"
+            data-bind="visible: $root.thisUser().channel() === $data">
+          <img class="channel-icon-linked" src="/svg/channel_linked.svg"
+            data-bind="visible: linked() && $root.thisUser().channel() !== $data">
+          <div class="channel-name" data-bind="text: name"></div>
+        </div>
+        <!-- ko if: expanded -->
+        <!-- ko foreach: users -->
+        <div class="user-wrapper">
+          <div class="user-tree"></div>
+          <div class="user" data-bind="
+                click: $root.select,
+                css: {
+                  thisClient: $root.thisUser() === $data,
+                  selected: $root.selected() === $data
+                }">
+            <div class="user-status" data-bind="attr: { title: state }">
+              <img class="user-comment" data-bind="visible: comment"
+                  alt="comment" src="/svg/comment.svg">
+              <img class="user-server-mute" data-bind="visible: mute"
+                  alt="server mute" src="/svg/muted_server.svg">
+              <img class="user-suppress-mute" data-bind="visible: suppress"
+                  alt="suppressed" src="/svg/muted_suppressed.svg">
+              <img class="user-self-mute" data-bind="visible: selfMute" 
+                  alt="self mute" src="/svg/muted_self.svg">
+              <img class="user-server-deaf" data-bind="visible: deaf"
+                  alt="server deaf" src="/svg/deafened_server.svg">
+              <img class="user-self-deaf" data-bind="visible: selfDeaf"
+                  alt="self deaf" src="/svg/deafened_self.svg">
+              <img class="user-authenticated" data-bind="visible: uid"
+                  alt="authenticated" src="/svg/authenticated.svg">
+            </div>
+            <div data-bind="if: comment">
+              <div class="user-comment tooltip" data-bind="html: comment"></div>
+            </div>
+            <img class="user-talk-off" data-bind="visible: talking() == 'off'"
+                alt="talk off" src="/svg/talking_off.svg">
+            <img class="user-talk-on" data-bind="visible: talking() == 'on'"
+                alt="talk on" src="/svg/talking_on.svg">
+            <img class="user-talk-whisper" data-bind="visible: talking() == 'whisper'"
+                alt="whisper" src="/svg/talking_whisper.svg">
+            <img class="user-talk-shout" data-bind="visible: talking() == 'shout'"
+                alt="shout" src="/svg/talking_alt.svg">
+            <div class="user-name" data-bind="text: name"></div>
+          </div>
+        </div>
+        <!-- /ko -->
+        <!-- ko foreach: channels -->
+        <div class="channel-wrapper">
+          <!-- ko ifnot: users().length || channels().length -->
+          <div class="channel-tree"></div>
+          <!-- /ko -->
+          <div class="branch" data-bind="if: users().length || channels().length">
+            <img class="branch-open" src="/svg/branch_open.svg"
+                data-bind="click: expanded.bind($data, false), visible: expanded()">
+            <img class="branch-closed" src="/svg/branch_closed.svg"
+                data-bind="click: expanded.bind($data, true), visible: !expanded()">
+          </div>
+          <div class="channel-sub" data-bind="template: {name: 'channel', data: $data}"></div>
+        </div>
+        <!-- /ko -->
+        <!-- /ko -->
+      </script>
+      <div class="channel-root-container" data-bind="if: root">
+        <div class="channel-root" data-bind="template: {name: 'channel', data: root}"></div>
+      </div>
+    </div>
+  </body>
+  <link rel="stylesheet" type="text/css" href="/main.css">
+  <script src="index.js"></script>
+</html>

+ 512 - 0
app/index.js

@@ -0,0 +1,512 @@
+import url from 'url'
+import mumbleConnect from 'mumble-client-websocket'
+import CodecsBrowser from 'mumble-client-codecs-browser'
+import BufferQueueNode from 'web-audio-buffer-queue'
+import MicrophoneStream from 'microphone-stream'
+import audioContext from 'audio-context'
+import chunker from 'stream-chunker'
+import Resampler from 'libsamplerate.js'
+import getUserMedia from 'getusermedia'
+import ko from 'knockout'
+import _dompurify from 'dompurify'
+
+const dompurify = _dompurify(window)
+
+function sanitize (html) {
+  return dompurify.sanitize(html, {
+    ALLOWED_TAGS: ['br', 'b', 'i', 'u', 'a', 'span', 'p']
+  })
+}
+
+// GUI
+
+function ConnectDialog () {
+  var self = this
+  self.address = ko.observable('')
+  self.port = ko.observable('443')
+  self.token = ko.observable('')
+  self.username = ko.observable('')
+  self.visible = ko.observable(true)
+  self.show = self.visible.bind(self.visible, true)
+  self.hide = self.visible.bind(self.visible, false)
+  self.connect = function () {
+    self.hide()
+    ui.connect(self.username(), self.address(), self.port(), self.token())
+  }
+}
+
+function ConnectionInfo () {
+  var self = this
+  self.visible = ko.observable(false)
+  self.show = function () {
+    self.visible(true)
+  }
+}
+
+function CommentDialog () {
+  var self = this
+  self.visible = ko.observable(false)
+  self.show = function () {
+    self.visible(true)
+  }
+}
+
+function SettingsDialog () {
+  var self = this
+  self.visible = ko.observable(false)
+  self.show = function () {
+    self.visible(true)
+  }
+}
+
+class GlobalBindings {
+  constructor () {
+    this.client = null
+    this.connectDialog = new ConnectDialog()
+    this.connectionInfo = new ConnectionInfo()
+    this.commentDialog = new CommentDialog()
+    this.settingsDialog = new SettingsDialog()
+    this.log = ko.observableArray()
+    this.thisUser = ko.observable()
+    this.root = ko.observable()
+    this.messageBox = ko.observable('')
+    this.selected = ko.observable()
+
+    this.select = element => {
+      this.selected(element)
+    }
+
+    this.getTimeString = () => {
+      return '[' + new Date().toLocaleTimeString('en-US') + ']'
+    }
+
+    this.connect = (username, host, port, token) => {
+      this.resetClient()
+
+      log('Connecting to server ', host)
+
+      // TODO: token
+      mumbleConnect(`wss://${host}:${port}`, {
+        username: username,
+        codecs: CodecsBrowser
+      }).done(client => {
+        log('Connected!')
+
+        this.client = client
+
+        // Prepare for connection errors
+        client.on('error', function (err) {
+          log('Connection error:', err)
+          this.resetClient()
+        })
+
+        // Register all channels, recursively
+        const registerChannel = channel => {
+          this._newChannel(channel)
+          channel.children.forEach(registerChannel)
+        }
+        registerChannel(client.root)
+
+        // Register all users
+        client.users.forEach(user => this._newUser(user))
+
+        // Register future channels
+        client.on('newChannel', channel => this._newChannel(channel))
+        // Register future users
+        client.on('newUser', user => this._newUser(user))
+
+        // Handle messages
+        client.on('message', (sender, message, users, channels, trees) => {
+          ui.log.push({
+            type: 'chat-message',
+            user: sender.__ui,
+            channel: channels.length > 0,
+            message: sanitize(message)
+          })
+        })
+
+        // Set own user and root channel
+        this.thisUser(client.self.__ui)
+        this.root(client.root.__ui)
+        // Upate linked channels
+        this._updateLinks()
+        // Log welcome message
+        if (client.welcomeMessage) {
+          this.log.push({
+            type: 'welcome-message',
+            message: sanitize(client.welcomeMessage)
+          })
+        }
+      }, err => {
+        log('Connection error:', err)
+      })
+    }
+
+    this._newUser = user => {
+      const simpleProperties = {
+        uniqueId: 'uid',
+        username: 'name',
+        mute: 'mute',
+        deaf: 'deaf',
+        suppress: 'suppress',
+        selfMute: 'selfMute',
+        selfDeaf: 'selfDeaf',
+        comment: 'comment'
+      }
+      var ui = user.__ui = {
+        model: user,
+        talking: ko.observable('off'),
+        channel: ko.observable()
+      }
+      Object.entries(simpleProperties).forEach(key => {
+        ui[key[1]] = ko.observable(user[key[0]])
+      })
+      ui.state = ko.pureComputed(userToState, ui)
+      if (user.channel) {
+        ui.channel(user.channel.__ui)
+        ui.channel().users.push(ui)
+        ui.channel().users.sort(compareUsers)
+      }
+
+      user.on('update', (actor, properties) => {
+        Object.entries(simpleProperties).forEach(key => {
+          if (properties[key[0]] !== undefined) {
+            ui[key[1]](properties[key[0]])
+          }
+        })
+        if (properties.channel !== undefined) {
+          if (ui.channel()) {
+            ui.channel().users.remove(ui)
+          }
+          ui.channel(properties.channel.__ui)
+          ui.channel().users.push(ui)
+          ui.channel().users.sort(compareUsers)
+          this._updateLinks()
+        }
+      }).on('remove', () => {
+        if (ui.channel()) {
+          ui.channel().users.remove(ui)
+        }
+      }).on('voice', stream => {
+        console.log(`User ${user.username} started takling`)
+        var userNode = new BufferQueueNode({
+          audioContext: audioContext
+        })
+        userNode.connect(audioContext.destination)
+
+        var resampler = new Resampler({
+          unsafe: true,
+          type: Resampler.Type.ZERO_ORDER_HOLD,
+          ratio: audioContext.sampleRate / 48000
+        })
+        resampler.pipe(userNode)
+
+        stream.on('data', data => {
+          if (data.target === 'normal') {
+            ui.talking('on')
+          } else if (data.target === 'shout') {
+            ui.talking('shout')
+          } else if (data.target === 'whisper') {
+            ui.talking('whisper')
+          }
+          resampler.write(Buffer.from(data.pcm.buffer))
+        }).on('end', () => {
+          console.log(`User ${user.username} stopped takling`)
+          ui.talking('off')
+          resampler.end()
+        })
+      })
+    }
+
+    this._newChannel = channel => {
+      const simpleProperties = {
+        position: 'position',
+        name: 'name',
+        description: 'description'
+      }
+      var ui = channel.__ui = {
+        model: channel,
+        expanded: ko.observable(true),
+        parent: ko.observable(),
+        channels: ko.observableArray(),
+        users: ko.observableArray(),
+        linked: ko.observable(false)
+      }
+      Object.entries(simpleProperties).forEach(key => {
+        ui[key[1]] = ko.observable(channel[key[0]])
+      })
+      if (channel.parent) {
+        ui.parent(channel.parent.__ui)
+        ui.parent().channels.push(ui)
+        ui.parent().channels.sort(compareChannels)
+      }
+      this._updateLinks()
+
+      channel.on('update', properties => {
+        Object.entries(simpleProperties).forEach(key => {
+          if (properties[key[0]] !== undefined) {
+            ui[key[1]](properties[key[0]])
+          }
+        })
+        if (properties.parent !== undefined) {
+          if (ui.parent()) {
+            ui.parent().channel.remove(ui)
+          }
+          ui.parent(properties.parent.__ui)
+          ui.parent().channels.push(ui)
+          ui.parent().channels.sort(compareChannels)
+        }
+        if (properties.links !== undefined) {
+          this._updateLinks()
+        }
+      }).on('remove', () => {
+        if (ui.parent()) {
+          ui.parent().channels.remove(ui)
+        }
+        this._updateLinks()
+      })
+    }
+
+    this.resetClient = () => {
+      if (this.client) {
+        this.client.disconnect()
+      }
+      this.client = null
+      this.thisUser(null).root(null).selected(null)
+    }
+
+    this.connected = () => this.thisUser() != null
+
+    this.messageBoxHint = ko.pureComputed(() => {
+      if (!this.thisUser()) {
+        return '' // Not yet connected
+      }
+      var target = this.selected()
+      if (!target) {
+        target = this.thisUser()
+      }
+      if (target === this.thisUser()) {
+        target = target.channel()
+      }
+      if (target.users) { // Channel
+        return "Type message to channel '" + target.name() + "' here"
+      } else { // User
+        return "Type message to user '" + target.name() + "' here"
+      }
+    })
+
+    this.submitMessageBox = () => {
+      this.sendMessage(this.selected(), this.messageBox())
+      this.messageBox('')
+    }
+
+    this.sendMessage = (target, message) => {
+      if (this.connected()) {
+        // If no target is selected, choose our own user
+        if (!target) {
+          target = this.thisUser()
+        }
+        // If target is our own user, send to our channel
+        if (target === this.thisUser()) {
+          target = target.channel()
+        }
+        // Send message
+        target.model.sendMessage(message)
+        if (target.users) { // Channel
+          this.log.push({
+            type: 'chat-message-self',
+            message: sanitize(message),
+            channel: target
+          })
+        } else { // User
+          this.log.push({
+            type: 'chat-message-self',
+            message: sanitize(message),
+            user: target
+          })
+        }
+      }
+    }
+
+    this.requestMove = (user, channel) => {
+      if (this.connected()) {
+        user.model.setChannel(channel.model)
+      }
+    }
+
+    this.requestMute = user => {
+      if (this.connected()) {
+        if (user === this.thisUser) {
+          this.client.setSelfMute(true)
+        } else {
+          user.model.setMute(true)
+        }
+      }
+    }
+
+    this.requestDeaf = user => {
+      if (this.connected()) {
+        if (user === this.thisUser) {
+          this.client.setSelfDeaf(true)
+        } else {
+          user.model.setDeaf(true)
+        }
+      }
+    }
+
+    this.requestUnmute = user => {
+      if (this.connected()) {
+        if (user === this.thisUser) {
+          this.client.setSelfMute(false)
+        } else {
+          user.model.setMute(false)
+        }
+      }
+    }
+
+    this.requestUndeaf = user => {
+      if (this.connected()) {
+        if (user === this.thisUser) {
+          this.client.setSelfDeaf(false)
+        } else {
+          user.model.setDeaf(false)
+        }
+      }
+    }
+
+    this._updateLinks = () => {
+      if (!this.thisUser()) {
+        return
+      }
+
+      var allChannels = getAllChannels(this.root(), [])
+      var ownChannel = this.thisUser().channel().model
+      var allLinked = findLinks(ownChannel, [])
+      allChannels.forEach(channel => {
+        channel.linked(allLinked.indexOf(channel.model) !== -1)
+      })
+
+      function findLinks (channel, knownLinks) {
+        knownLinks.push(channel)
+        channel.links.forEach(next => {
+          if (next && knownLinks.indexOf(next) === -1) {
+            findLinks(next, knownLinks)
+          }
+        })
+        allChannels.map(c => c.model).forEach(next => {
+          if (next && knownLinks.indexOf(next) === -1 && next.links.indexOf(channel) !== -1) {
+            findLinks(next, knownLinks)
+          }
+        })
+        return knownLinks
+      }
+
+      function getAllChannels (channel, channels) {
+        channels.push(channel)
+        channel.channels().forEach(next => getAllChannels(next, channels))
+        return channels
+      }
+    }
+
+    this.openSourceCode = () => {
+      var homepage = require('../package.json').homepage
+      window.open(homepage, '_blank').focus()
+    }
+  }
+}
+var ui = new GlobalBindings()
+
+// Used only for debugging
+window.mumbleUi = ui
+
+window.onload = function () {
+  var queryParams = url.parse(document.location.href, true).query
+  if (queryParams.address) {
+    ui.connectDialog.address(queryParams.address)
+  }
+  if (queryParams.port) {
+    ui.connectDialog.port(queryParams.port)
+  }
+  if (queryParams.token) {
+    ui.connectDialog.token(queryParams.token)
+  }
+  if (queryParams.username) {
+    ui.connectDialog.username(queryParams.username)
+  }
+  ko.applyBindings(ui)
+}
+
+function log () {
+  console.log.apply(console, arguments)
+  var args = []
+  for (var i = 0; i < arguments.length; i++) {
+    args.push(arguments[i])
+  }
+  ui.log.push({
+    type: 'generic',
+    value: args.join(' ')
+  })
+}
+
+function compareChannels (c1, c2) {
+  if (c1.position() === c2.position()) {
+    return c1.name() === c2.name() ? 0 : c1.name() < c2.name() ? -1 : 1
+  }
+  return c1.position() - c2.position()
+}
+
+function compareUsers (u1, u2) {
+  return u1.name() === u2.name() ? 0 : u1.name() < u2.name() ? -1 : 1
+}
+
+function userToState () {
+  var flags = []
+  // TODO: Friend
+  if (this.uid()) {
+    flags.push('Authenticated')
+  }
+  // TODO: Priority Speaker, Recording
+  if (this.mute()) {
+    flags.push('Muted (server)')
+  }
+  if (this.deaf()) {
+    flags.push('Deafened (server)')
+  }
+  // TODO: Local Ignore (Text messages), Local Mute
+  if (this.selfMute()) {
+    flags.push('Muted (self)')
+  }
+  if (this.selfDeaf()) {
+    flags.push('Deafened (self)')
+  }
+  return flags.join(', ')
+}
+
+// Audio input
+
+var resampler = new Resampler({
+  unsafe: true,
+  type: Resampler.Type.SINC_FASTEST,
+  ratio: 48000 / audioContext.sampleRate
+})
+
+var voiceStream
+resampler.pipe(chunker(4 * 480)).on('data', function (data) {
+  if (!voiceStream && ui.client) {
+    voiceStream = ui.client.createVoiceStream()
+  }
+  if (voiceStream) {
+    voiceStream.write(new Float32Array(data.buffer, data.byteOffset, data.byteLength / 4))
+  }
+})
+
+getUserMedia({ audio: true }, function (err, userMedia) {
+  if (err) {
+    log('Cannot initialize user media. Microphone will not work:', err)
+  } else {
+    var micStream = new MicrophoneStream(userMedia, { objectMode: true })
+    micStream.on('data', function (data) {
+      resampler.write(Buffer.from(data.getChannelData(0).buffer))
+    })
+  }
+})

+ 48 - 0
package.json

@@ -0,0 +1,48 @@
+{
+  "name": "mumble-web",
+  "version": "0.0.1",
+  "description": "An HTML5 Mumble client.",
+  "scripts": {
+    "build": "webpack",
+    "prepublish": "rm -r dist && npm run build",
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "Jonas Herzig <me@johni0702.de>",
+  "license": "ISC",
+  "repository": "johni0702/mumble-web",
+  "homepage": "https://github.com/johni0702/mumble-web",
+  "files": [
+    "dist"
+  ],
+  "devDependencies": {
+    "audio-buffer-utils": "^3.1.2",
+    "audio-context": "^0.1.0",
+    "babel-core": "^6.18.2",
+    "babel-loader": "^6.2.8",
+    "babel-plugin-transform-runtime": "^6.15.0",
+    "babel-preset-es2015": "^6.14.0",
+    "babel-runtime": "^6.18.0",
+    "brfs": "^1.4.3",
+    "css-loader": "^0.26.0",
+    "dompurify": "^0.8.3",
+    "duplex-maker": "^1.0.0",
+    "extract-loader": "^0.1.0",
+    "file-loader": "^0.9.0",
+    "getusermedia": "^2.0.0",
+    "html-loader": "^0.4.4",
+    "json-loader": "^0.5.4",
+    "knockout": "^3.4.0",
+    "lodash.assign": "^4.2.0",
+    "microphone-stream": "^3.0.5",
+    "raw-loader": "^0.5.1",
+    "regexp-replace-loader": "0.0.1",
+    "stream-chunker": "^1.2.8",
+    "transform-loader": "^0.2.3",
+    "webpack": "^1.13.3",
+    "webworkify-webpack-dropin": "^1.1.9",
+    "libsamplerate.js": "^1.0.0",
+    "mumble-client-codecs-browser": "^1.0.1",
+    "mumble-client-websocket": "^1.0.0",
+    "web-audio-buffer-queue": "^1.0.0"
+  }
+}

+ 33 - 0
themes/MetroMumbleLight/loading.css

@@ -0,0 +1,33 @@
+.loading-container {
+  position: absolute;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #eee;
+  z-index: 1000;
+}
+
+.loading-circle {
+  box-sizing: border-box;
+  width: 80px;
+  height: 80px;
+  position: absolute;
+  top: calc(50% - 40px);
+  left: calc(50% - 40px);
+  border-radius: 100%;
+  border: 10px solid #ddd;
+  border-top-color: #999;
+  animation: spin 1s infinite linear;
+}
+
+@keyframes spin {
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.loaded {
+  top: -100%;
+  transition: top 1s;
+  transition-delay: 2s;
+}

+ 252 - 0
themes/MetroMumbleLight/main.css

@@ -0,0 +1,252 @@
+html, body {
+  background-color: #eee;
+  margin: 0;
+  overflow: hidden;
+  height: 100%
+}
+#container {
+  height: 98%;
+  margin: 0 1% 0 1%;
+}
+#container::before {
+  display: block;
+  content: "";
+  height: 1%;
+}
+.channel-root-container {
+  text-size: 16px;
+  margin-left: 2px;
+  background-color: white;
+  border: 1px solid lightgray;
+  float: left;
+  width: calc(60% - 6px);
+  height: calc(100% - 38px);
+  border-radius: 3px;
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.chat {
+  margin-right: 2px;
+  float: left;
+  width: 40%;
+  height: calc(100% - 38px);
+}
+.log {
+  background-color: white;
+  height: calc(100% - 42px);
+  padding: 5px;
+  border: 1px lightgray solid;
+  border-radius: 3px;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.branch img {
+  height: 19px;
+}
+.branch {
+  float: left;
+  padding-top: 3px;
+  padding-bottom: 3px;
+  background-color: white;
+  margin-right:
+}
+.channel-sub {
+  margin-left: 9px;
+  border-left: 1px transparent solid;
+  padding-left: 9px;
+}
+.channel-wrapper:nth-last-child(n + 2) > .branch:not(:empty) + .channel-sub {
+  border-left: 1px lightgray solid;
+}
+.channel-tree,
+.user-wrapper {
+  margin-left: 9px;
+}
+.channel-tree,
+.user-tree {
+  float: left;
+}
+.channel-tree::before,
+.user-tree::before {
+  content: "";
+  display: block;
+  position: relative;
+  width: 9px;
+  border-left: 1px lightgray solid;
+  border-bottom: 1px lightgray solid;
+  height: 14px;
+}
+.channel-wrapper:nth-last-child(n + 2) > .channel-tree:after,
+.user-wrapper:nth-last-child(n + 2) .user-tree:after {
+  content: "";
+  display: block;
+  position: relative;
+  width: 0px;
+  border-left: 1px lightgray solid;
+  height: 14px;
+}
+.user {
+  margin-left: 9px;
+}
+.user-status, .channel-status {
+  float: right;
+}
+.user,.channel{
+  height: 23px;
+  padding: 2px;
+  border: 1px solid transparent;
+}
+.selected {
+  background-color: lightblue !important;
+  border: 1px solid gray;
+  border-radius: 3px;
+}
+.user:hover,.channel:hover {
+  background-color: lightgray;
+}
+.thisClient {
+  font-weight: bold
+}
+.currentChannel {
+  font-weight: bold
+}
+.user-status img, .channel-status img {
+  margin-top: 2px;
+  width: 19px;
+  height: 19px
+}
+.channel img, .user img {
+  width: auto;
+  height: 19px;
+}
+.channel-name, .user-name {
+  display: inline;
+}
+.channel:hover .tooltip, .user:hover .tooltip {
+  visibility: visible;
+  height: auto;
+  transition-delay: 1s;
+}
+.tooltip {
+  visibility: hidden;
+  height: 0px;
+  background: white;
+  border: 1px solid gray;
+  margin-top: 16px;
+  margin-left: 30px;
+  padding: 10px;
+  position: absolute;
+  z-index: 100;
+}
+.toolbar {
+  height: 36px;
+}
+.toolbar img {
+  height: 28px;
+  width: 28px;
+  padding: 2px;
+  border: 1px solid transparent;
+  border-radius: 3px;
+}
+.toolbar img:hover {
+  border: 1px solid #bbb;
+  background-color: #ddd;
+}
+.toolbar .tb-active {
+  border: 1px solid #bbb;
+  background-color: white;
+}
+.divider {
+  display: inline-block;
+  height: 32px;
+  border-left: 1px lightgray solid;
+}
+.handle-horizontal {
+  width: auto !important;
+  border: none !important;
+  background-color: #eee !important;
+}
+.handle-vertical {
+  display: none;
+}
+.channel-icon .channel-icon-active {
+  display: none;
+}
+.channel-tag {
+  font-weight: bold;
+  color: orange;
+}
+.user-tag {
+  font-weight: bold;
+  color: green;
+}
+#message-box {
+  width: 100%;
+  border: none;
+  background: none;
+  margin: 5px 0 5px 0;
+  padding: 0;
+  height: 20px;
+}
+form {
+  margin: 0;
+  padding: 0;
+}
+.message-content p {
+  margin: 0;
+}
+.tb-information, .tb-record, .tb-comment, .tb-settings{
+  filter: grayscale(100%);
+}
+.dialog-header {
+  height: 20px;
+  width: calc(100% - 10px);
+  padding: 5px;
+  text-align: center;
+  color: white;
+  background-color: gray;
+  border-bottom: 1px solid darkgray;
+}
+.dialog-footer {
+  margin: 10px;
+  margin-bottom: 0px;
+}
+.dialog-close {
+  float: left;
+}
+.dialog-submit {
+  float: right;
+}
+.dialog-close, .dialog-submit {
+  width: 45%;
+  font-size: 15px;
+  border: 1px gray solid;
+  border-radius: 3px;
+  background-color: white;
+  color: black;
+  padding: 1px;
+}
+.connect-dialog table {
+  text-align: center;
+  width: 100%
+}
+.connect-dialog {
+  position: absolute;
+  width: 300px;
+  height: 197px;
+  top: calc(50% - 100px);
+  left: calc(50% - 150px);
+  background-color: #eee;
+  border: 1px gray solid;
+  box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.25);
+  z-index: 20;
+}
+.connect-dialog input[type=text] {
+  font-size: 15px;
+  border: 1px gray solid;
+  border-radius: 3px;
+  background-color: white;
+  color: black;
+  padding: 2px;
+  width: calc(100% - 8px);
+}

+ 23 - 0
themes/MetroMumbleLight/svg/applications-internet.svg

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
+<circle opacity="0.9" fill="#498BEA" cx="251" cy="251" r="220.5"/>
+<polyline fill="none" points="99.791,300.202 99.796,300.204 99.791,300.202 "/>
+<polyline fill="none" points="99.778,300.195 99.791,300.202 99.778,300.195 "/>
+<path fill="none" d="M97.411,298.878c0,0,1.015,0.564,2.368,1.316C98.08,299.25,97.411,298.878,97.411,298.878"/>
+<path fill="none" d="M106.531,303.949c0,0-0.416-0.231-1.069-0.595C106.213,303.773,106.531,303.949,106.531,303.949"/>
+<path fill="#23F989" d="M337.612,59.919c-4.905,0-9.316,1.517-12.945,5.058c-7.931,27.762,9.146,74.055,25.5,96.048
+	c6.699,9.009,12.578,12.377,17.915,12.377c7.906,0,14.623-7.388,21.066-14.776c6.442-7.388,12.609-14.776,19.408-14.776
+	c1.818,0,3.679,0.527,5.605,1.724c53.736,33.392-18.666,159.777-27.039,210.195c-3.151,18.973-2.259,33.045,7.249,33.045
+	c4.623,0,11.283-3.326,20.507-11.033c6.21-5.189,11.409-10.881,15.782-16.978c4.759-7.773,9.025-15.872,12.763-24.266
+	c11.227-29.939,11.15-64.966,14.293-96.686c0.981-9.898,0.979-19.504,0.091-28.832C445.025,144.13,400.642,88.453,340.794,60.12
+	C339.713,59.987,338.653,59.919,337.612,59.919L337.612,59.919z M209.648,56.667c-7.021,0-14.122,0.964-20.635,2.356
+	c-19.353,4.136-44.914,12.647-67.527,25.105c-23.729,18.412-43.419,41.78-57.523,68.549c-18.871,54.658-21.116,115.784,37.89,148.67
+	c-0.712-0.396-1.421-0.79-2.056-1.143c0.594,0.33,1.313,0.73,2.172,1.208l0,0l0,0c39.173,21.779,26.567,85.227,38.65,129.369
+	c32.037,19.636,69.719,30.954,110.049,30.954c0.739,0,1.471-0.004,2.208-0.011c16.799-6.085,29.972-15.224,33.896-26.794
+	c10.072-29.697-91.125-84.76-109.682-98.713c-49.417-37.156-74.483-69.395-2.836-108.562c19.88-10.867,75.456-15.07,62.608-50.012
+	c-9.18-24.969-65.033-47.174-31.991-73.63c9.854-7.89,52.435-8.663,43.061-27.409C240.32,61.379,225.173,56.667,209.648,56.667
+	L209.648,56.667z"/>
+</svg>

+ 16 - 0
themes/MetroMumbleLight/svg/audio-input-microphone-muted.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="141.732px" height="141.732px" viewBox="0 0 141.732 141.732" enable-background="new 0 0 141.732 141.732"
+	 xml:space="preserve">
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M70.866,8.202c-12.067,0-21.85,9.783-21.85,21.85v29.385
+	l43.7-23.825v-5.56C92.716,17.985,82.933,8.202,70.866,8.202z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M65.466,121.756L65.466,121.756z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M76.266,121.756L76.266,121.756z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M76.266,121.756c18.165-2.619,32.122-18.25,32.122-37.138
+	l-7.779,0.23c0,16.427-13.316,29.743-29.743,29.743c-12.851,0-23.799-8.149-27.952-19.563v-0.001l7.998-4.36v0.001
+	c3.411,7.628,11.062,12.94,19.954,12.94c12.067,0,21.85-9.783,21.85-21.85V67.875l43.827-23.896l-6.693-12.273L5.188,99.673
+	l6.694,12.273l24.217-13.203v0.001c4.925,12.122,16.007,21.084,29.367,23.012v7.934H41.263c-3.032,0-5.49,2.458-5.49,5.49v-0.941
+	c0,3.035,2.458,5.493,5.49,5.493h59.206c3.032,0,5.49-2.458,5.49-5.493v0.941c0-3.032-2.458-5.49-5.49-5.49H76.266V121.756z"/>
+</svg>

+ 16 - 0
themes/MetroMumbleLight/svg/audio-input-microphone.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="141.732px" height="141.732px" viewBox="0 0 141.732 141.732" enable-background="new 0 0 141.732 141.732"
+	 xml:space="preserve">
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M65.466,121.756L65.466,121.756z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M76.266,121.756L76.266,121.756z"/>
+<path opacity="0.9" fill="#34A853" enable-background="new    " d="M48.816,81.758c0,13.483,9.3,21.85,22.05,21.85
+	c12.067,0,21.85-9.783,21.85-21.85V67.875V35.612v-5.56c0-12.067-9.783-21.85-21.85-21.85s-22.05,9.783-22.05,21.85v37.689
+	C48.816,67.741,48.816,81.758,48.816,81.758z"/>
+<path opacity="0.9" fill="#34A853" enable-background="new    " d="M65.466,121.756v7.934H41.263c-3.032,0-5.49,2.458-5.49,5.49
+	v-0.941c0,3.035,2.458,5.493,5.49,5.493h59.206c3.032,0,5.49-2.458,5.49-5.493v0.941c0-3.032-2.458-5.49-5.49-5.49H76.266v-7.934
+	c18.165-2.619,32.122-18.135,32.122-37.023h-7.779c0,16.427-13.316,29.858-29.743,29.858c-16.387,0-29.67-13.431-29.67-29.858h-7.76
+	c0,18.888,13.923,34.404,32.044,37.023"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/audio-output-deafened.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g opacity="0.75">
+	<path fill="#FF3E3E" d="M168.46,169.386c0-12.6-10.309-22.909-22.909-22.909h-10.19c-12.6,0-22.909,10.309-22.909,22.909v21.048
+		v53.296l56.008-28.068V169.386z"/>
+</g>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M391.982,103.627l-198.147,99.316l-0.001-33.063
+	c0-12.6,9.309-27.338,20.687-32.751l156.772-74.583c11.379-5.413,20.687,0.079,20.687,12.203L391.982,103.627z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M193.835,297.054v44.058c0,12.6,9.309,27.338,20.687,32.751
+	l156.771,74.583c11.379,5.413,20.687-0.467,20.687-13.067l0.002-237.018l73.56-35.201l-19.709-39.323L46.46,324.009l19.709,39.323
+	l46.282-24.613v4.721c0,12.6,10.309,22.909,22.909,22.909h10.19c12.6,0,22.909-10.309,22.909-22.909v-32.799L193.835,297.054z"/>
+</svg>

+ 30 - 0
themes/MetroMumbleLight/svg/audio-output.svg

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g opacity="0.9">
+	<g>
+		<g>
+			<path fill="#13A354" d="M170.907,136.328c-12.249,5.827-22.271,21.695-22.271,35.259l-0.001,168.823
+				c0,13.565,10.022,29.431,22.271,35.259l153.775,73.163c12.249,5.827,22.271-0.502,22.271-14.067l0.002-357.53
+				c0-13.565-10.022-19.895-22.271-14.067L170.907,136.328z"/>
+		</g>
+	</g>
+</g>
+<g opacity="0.9">
+	<g>
+		<g>
+			<g>
+				<path fill="#13A354" d="M67.18,171.09c0-13.565,11.098-24.663,24.663-24.663h6.734c13.565,0,24.663,11.098,24.663,24.663V340.91
+					c0,13.565-11.098,24.663-24.663,24.663h-6.734c-13.565,0-24.663-11.098-24.663-24.663C67.18,340.91,67.18,171.09,67.18,171.09z"
+					/>
+			</g>
+		</g>
+	</g>
+</g>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M424.835,406.492L403.143,384.8
+	c71.02-71.02,71.019-186.579,0.001-257.599l21.693-21.693C507.818,188.49,507.818,323.511,424.835,406.492z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M382.838,362.074l-21.693-21.693
+	c46.527-46.527,46.527-122.233,0.001-168.764l21.693-21.693C441.327,208.415,441.327,303.586,382.838,362.074z"/>
+</svg>

+ 7 - 0
themes/MetroMumbleLight/svg/authenticated.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
+<polygon fill="#FFB000" points="183.5,304.5 399.492,171.635 426.925,207.307 165.648,408.365 53.075,261.981 88.747,234.549 "/>
+</svg>

+ 7 - 0
themes/MetroMumbleLight/svg/branch_closed.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
+<polyline fill="#7F7F7F" points="10,4 22,16 10,28 "/>
+</svg>

+ 7 - 0
themes/MetroMumbleLight/svg/branch_open.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="32px" height="32px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
+<polyline fill="#7F7F7F" points="18.5,7.5 18.5,24.5 1.5,24.5 "/>
+</svg>

+ 6 - 0
themes/MetroMumbleLight/svg/channel.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="2px" height="30px" xml:space="preserve">
+</svg>

+ 6 - 0
themes/MetroMumbleLight/svg/channel_active.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="2px" height="30px" xml:space="preserve">
+</svg>

+ 23 - 0
themes/MetroMumbleLight/svg/channel_linked.svg

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="501px" height="500px" viewBox="0 0 501 500" enable-background="new 0 0 501 500" xml:space="preserve">
+<g>
+	<path fill="#00B3DD" d="M454.834,306.256l-56.578,56.578l-39.73-39.73l56.578-56.578c25.283-25.283,16.478-75.227-10.938-102.642
+		c-27.415-27.415-77.359-36.221-102.642-10.938l-56.578,56.578l-39.73-39.729l56.578-56.578
+		c45.486-45.486,129.69-35.294,179.012,14.028S500.32,260.77,454.834,306.256z"/>
+	<path fill="#00B3DD" d="M357.822,403.269l-57.616,57.616c-45.486,45.486-129.69,35.294-179.011-14.028
+		S61.68,313.332,107.166,267.846l57.616-57.617l39.73,39.73l-57.616,57.616c-25.284,25.284-16.478,75.227,10.938,102.642
+		c27.415,27.415,77.359,36.221,102.642,10.938l57.616-57.616L357.822,403.269z"/>
+	<g>
+		<g>
+			<g>
+				<path fill="#00B3DD" d="M199.269,358.123c-7.077-7.077-5.983-19.752,2.431-28.166L323.54,208.119
+					c8.414-8.414,21.089-9.507,28.166-2.431l10.661,10.661c7.077,7.077,5.983,19.752-2.431,28.166L238.097,366.353
+					c-8.414,8.414-21.089,9.508-28.166,2.431L199.269,358.123z"/>
+			</g>
+		</g>
+	</g>
+</g>
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/comment.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g id="Layer_2" display="none">
+	<rect x="-109.5" y="-86.5" display="inline" stroke="#000000" stroke-miterlimit="10" width="721" height="687"/>
+</g>
+<path fill="#FFB000" d="M430.81,103.5H81.19c-15.31,0-27.69,12.38-27.69,27.69v264.56c0,15.3,12.38,27.69,27.69,27.69h55.37v83.06
+	l124.6-83.06h169.65c15.31,0,27.69-12.39,27.69-27.69V131.19C458.5,115.88,446.12,103.5,430.81,103.5z"/>
+<line fill="none" x1="349.5" y1="241.48" x2="349.5" y2="288.23"/>
+<line fill="none" x1="162.5" y1="288.23" x2="162.5" y2="241.48"/>
+</svg>

+ 9 - 0
themes/MetroMumbleLight/svg/comment_seen.svg

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.5" fill="#999999" enable-background="new    " d="M430.812,103.5H81.188c-15.305,0-27.688,12.383-27.688,27.688
+	V395.75c0,15.304,12.383,27.688,27.688,27.688h55.375V506.5l124.594-83.063h169.656c15.304,0,27.688-12.383,27.688-27.688V131.188
+	C458.499,115.883,446.116,103.5,430.812,103.5z"/>
+</svg>

+ 24 - 0
themes/MetroMumbleLight/svg/config_basic.svg

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
+<path fill="#44A3F2" d="M21.521,10.146c-0.41-0.059-0.846-0.428-0.973-0.82l-0.609-1.481c-0.191-0.365-0.146-0.935,0.1-1.264
+	l0.99-1.318c0.246-0.33,0.227-0.854-0.047-1.162l-1.084-1.086c-0.309-0.272-0.832-0.293-1.164-0.045l-1.316,0.988
+	c-0.33,0.248-0.898,0.293-1.264,0.101l-1.48-0.609c-0.395-0.126-0.764-0.562-0.82-0.971L13.62,0.85
+	c-0.057-0.409-0.441-0.778-0.85-0.822c0,0-0.255-0.026-0.77-0.026c-0.514,0-0.769,0.026-0.769,0.026
+	c-0.41,0.044-0.794,0.413-0.852,0.822l-0.233,1.629c-0.058,0.409-0.427,0.845-0.82,0.971l-1.48,0.609
+	C7.48,4.25,6.912,4.206,6.582,3.958L5.264,2.969C4.934,2.721,4.41,2.741,4.101,3.014L3.017,4.1C2.745,4.409,2.723,4.932,2.971,5.262
+	L3.959,6.58c0.249,0.33,0.293,0.899,0.102,1.264L3.45,9.326c-0.125,0.393-0.562,0.762-0.971,0.82L0.85,10.377
+	c-0.408,0.059-0.777,0.442-0.82,0.853c0,0-0.027,0.255-0.027,0.77s0.027,0.77,0.027,0.77c0.043,0.411,0.412,0.793,0.82,0.852
+	l1.629,0.232c0.408,0.059,0.846,0.428,0.971,0.82l0.611,1.48c0.191,0.365,0.146,0.936-0.102,1.264l-0.988,1.318
+	c-0.248,0.33-0.308,0.779-0.132,0.994c0.175,0.217,0.677,0.752,0.678,0.754c0.001,0.002,0.171,0.156,0.375,0.344
+	c0.204,0.188,1.042,0.449,1.372,0.203l1.317-0.99c0.33-0.246,0.898-0.293,1.264-0.1l1.48,0.609c0.394,0.125,0.763,0.562,0.82,0.971
+	l0.233,1.629c0.058,0.408,0.441,0.779,0.852,0.822c0,0,0.255,0.027,0.769,0.027c0.515,0,0.77-0.027,0.77-0.027
+	c0.409-0.043,0.793-0.414,0.85-0.822l0.234-1.629c0.057-0.408,0.426-0.846,0.82-0.971l1.48-0.611
+	c0.365-0.191,0.934-0.146,1.264,0.102l1.318,0.99c0.332,0.246,0.854,0.227,1.164-0.047l1.082-1.084
+	c0.273-0.311,0.293-0.834,0.047-1.164l-0.99-1.318c-0.246-0.328-0.291-0.898-0.1-1.264l0.609-1.48
+	c0.127-0.393,0.562-0.762,0.973-0.82l1.627-0.232c0.41-0.059,0.779-0.441,0.822-0.852c0,0,0.027-0.255,0.027-0.77
+	c0-0.515-0.027-0.77-0.027-0.77c-0.043-0.41-0.412-0.794-0.822-0.853C23.147,10.377,21.521,10.146,21.521,10.146z M12,15
+	c-1.657,0-3-1.344-3-3c0-1.657,1.343-3,3-3s3,1.344,3,3S13.656,15,12,15z"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/deafened_self.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g opacity="0.75">
+	<path fill="#FF3E3E" d="M168.46,169.386c0-12.6-10.309-22.909-22.909-22.909h-10.19c-12.6,0-22.909,10.309-22.909,22.909v21.048
+		v53.296l56.008-28.068V169.386z"/>
+</g>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M391.982,103.627l-198.147,99.316l-0.001-33.063
+	c0-12.6,9.309-27.338,20.687-32.751l156.772-74.583c11.379-5.413,20.687,0.079,20.687,12.203L391.982,103.627z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M193.835,297.054v44.058c0,12.6,9.309,27.338,20.687,32.751
+	l156.771,74.583c11.379,5.413,20.687-0.467,20.687-13.067l0.002-237.018l73.56-35.201l-19.709-39.323L46.46,324.009l19.709,39.323
+	l46.282-24.613v4.721c0,12.6,10.309,22.909,22.909,22.909h10.19c12.6,0,22.909-10.309,22.909-22.909v-32.799L193.835,297.054z"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/deafened_server.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g>
+	<path fill="#00B4DF" d="M168.46,169.386c0-12.6-10.309-22.909-22.909-22.909h-10.19c-12.6,0-22.909,10.309-22.909,22.909v21.048
+		v53.296l56.008-28.068V169.386z"/>
+</g>
+<path fill="#00B4DF" d="M391.982,103.627l-198.147,99.316l-0.001-33.063c0-12.6,9.309-27.338,20.687-32.751l156.772-74.583
+	c11.379-5.413,20.687,0.079,20.687,12.203L391.982,103.627z"/>
+<path fill="#00B4DF" d="M193.835,297.054v44.058c0,12.6,9.309,27.338,20.687,32.751l156.771,74.583
+	c11.379,5.413,20.687-0.467,20.687-13.067l0.002-237.018l73.56-35.201l-19.709-39.323L46.46,324.009l19.709,39.323l46.282-24.613
+	v4.721c0,12.6,10.309,22.909,22.909,22.909h10.19c12.6,0,22.909-10.309,22.909-22.909v-32.799L193.835,297.054z"/>
+</svg>

+ 16 - 0
themes/MetroMumbleLight/svg/default_avatar.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
+<circle opacity="0.75" enable-background="new    " cx="25" cy="25" r="24.829"/>
+<g>
+	<g>
+		<g>
+			<path fill="#D8D8D8" d="M17.283,22.192c-1.848-1.92-2.98-4.529-2.98-7.4c0-5.915,4.791-10.706,10.697-10.706
+				s10.697,4.792,10.697,10.706c0,2.871-1.132,5.48-2.98,7.4c5.724,2.056,9.655,6.304,9.655,11.213
+				c0,6.911-7.78,12.509-17.373,12.509S7.627,40.316,7.627,33.406C7.627,28.496,11.558,24.248,17.283,22.192z"/>
+		</g>
+	</g>
+</g>
+</svg>

+ 35 - 0
themes/MetroMumbleLight/svg/filter.svg

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1"
+	 id="Layer_1" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" inkscape:version="0.46" sodipodi:version="0.32" inkscape:output_extension="org.inkscape.output.svg.inkscape"
+	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="744px" height="750px"
+	 viewBox="0 0 744 750" enable-background="new 0 0 744 750" xml:space="preserve">
+<defs>
+	
+	
+		<inkscape:perspective  id="perspective16505" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_z="744.09448 : 526.18109 : 1" sodipodi:type="inkscape:persp3d" inkscape:vp_y="0 : 1000 : 0" inkscape:persp3d-origin="372.04724 : 350.78739 : 1">
+		</inkscape:perspective>
+</defs>
+<sodipodi:namedview  showguides="true" inkscape:cx="-823.66963" inkscape:cy="621.5403" pagecolor="#ffffff" inkscape:zoom="0.24748737" bordercolor="#666666" showgrid="false" id="base" borderopacity="1.0" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2">
+	<sodipodi:guide  orientation="0,1" position="-922.85714,940" id="guide3157"></sodipodi:guide>
+	<sodipodi:guide  orientation="0,1" position="-911.42857,125.71429" id="guide3159"></sodipodi:guide>
+	<sodipodi:guide  orientation="1,0" position="-28.571429,20" id="guide3163"></sodipodi:guide>
+	<sodipodi:guide  orientation="1,0" position="782.85714,11.428571" id="guide3165"></sodipodi:guide>
+	<sodipodi:guide  orientation="0,1" position="330,501.42857" id="guide3171"></sodipodi:guide>
+	<sodipodi:guide  orientation="0,1" position="492.85714,770" id="guide3173"></sodipodi:guide>
+</sodipodi:namedview>
+<g id="layer1" inkscape:label="Ebene 1" inkscape:groupmode="layer" opacity="0.9">
+	<g>
+		<g id="g7561_6_">
+			
+				<g id="path3346_8_" sodipodi:cy="342.36218" sodipodi:rx="341.42856" sodipodi:ry="58.57143" sodipodi:cx="387.14285" sodipodi:type="arc">
+				<path fill="#13A354" d="M71.165,150.852c-7.199-7.898-4.924-17.488,5.055-21.312c0,0,110.908-49.949,294.095-49.951
+					s294.137,49.946,294.137,49.946c9.979,3.823,12.198,13.362,4.931,21.197L457.103,390.096
+					c-7.267,7.835-13.212,22.989-13.212,33.675v234.403c0,10.686-8.67,18.304-19.267,16.927l-117.683-49.767
+					c-8.64-6.287-15.71-20.176-15.71-30.862v-172.09c0-10.686-5.89-25.892-13.089-33.789L71.165,150.852z"/>
+			</g>
+		</g>
+	</g>
+</g>
+</svg>

+ 35 - 0
themes/MetroMumbleLight/svg/filter_off.svg

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1"
+	 id="Layer_1" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:svg="http://www.w3.org/2000/svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" sodipodi:version="0.32" inkscape:version="0.46"
+	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="744px" height="750px"
+	 viewBox="0 0 744 750" enable-background="new 0 0 744 750" xml:space="preserve">
+<defs>
+	
+	
+		<inkscape:perspective  id="perspective16505" inkscape:vp_x="0 : 526.18109 : 1" inkscape:vp_z="744.09448 : 526.18109 : 1" inkscape:vp_y="0 : 1000 : 0" sodipodi:type="inkscape:persp3d" inkscape:persp3d-origin="372.04724 : 350.78739 : 1">
+		</inkscape:perspective>
+</defs>
+<sodipodi:namedview  id="base" borderopacity="1.0" inkscape:zoom="0.24748737" bordercolor="#666666" inkscape:cx="-823.66963" showgrid="false" inkscape:cy="621.5403" pagecolor="#ffffff" showguides="true" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:guide-bbox="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2">
+	<sodipodi:guide  id="guide3157" orientation="0,1" position="-922.85714,940"></sodipodi:guide>
+	<sodipodi:guide  id="guide3159" orientation="0,1" position="-911.42857,125.71429"></sodipodi:guide>
+	<sodipodi:guide  id="guide3163" orientation="1,0" position="-28.571429,20"></sodipodi:guide>
+	<sodipodi:guide  id="guide3165" orientation="1,0" position="782.85714,11.428571"></sodipodi:guide>
+	<sodipodi:guide  id="guide3171" orientation="0,1" position="330,501.42857"></sodipodi:guide>
+	<sodipodi:guide  id="guide3173" orientation="0,1" position="492.85714,770"></sodipodi:guide>
+</sodipodi:namedview>
+<g id="layer1" inkscape:label="Ebene 1" inkscape:groupmode="layer" opacity="0.9">
+	<g>
+		<g id="g7561_6_">
+			
+				<g id="path3346_8_" sodipodi:type="arc" sodipodi:cx="387.14285" sodipodi:cy="342.36218" sodipodi:ry="58.57143" sodipodi:rx="341.42856">
+				<path fill="#13A354" d="M20.9,129.076c-8.449-9.27-5.779-20.525,5.933-25.013c0,0,130.17-58.624,345.172-58.626
+					s345.222,58.62,345.222,58.62c11.712,4.487,14.317,15.683,5.787,24.878L473.867,409.871
+					c-8.529,9.196-15.507,26.982-15.507,39.524v275.113c0,12.542-10.176,21.483-22.613,19.867l-138.122-58.41
+					c-10.141-7.379-18.438-23.68-18.438-36.222V447.764c0-12.542-6.913-30.389-15.362-39.657L20.9,129.076z"/>
+			</g>
+		</g>
+	</g>
+</g>
+</svg>

+ 22 - 0
themes/MetroMumbleLight/svg/filter_on.svg

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1"
+	 id="Layer_1" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:svg="http://www.w3.org/2000/svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" sodipodi:version="0.32" inkscape:version="0.46"
+	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="744px" height="750px"
+	 viewBox="0 0 744 750" enable-background="new 0 0 744 750" xml:space="preserve">
+<g id="layer1" inkscape:label="Ebene 1" inkscape:groupmode="layer">
+	<g>
+		<g id="g7561_6_">
+			
+				<g id="path3346_8_" sodipodi:type="arc" sodipodi:cx="387.14285" sodipodi:cy="342.36218" sodipodi:ry="58.57143" sodipodi:rx="341.42856">
+				<path fill="#FFB000" d="M491.85,389.59l-17.98,20.28c-8.53,9.2-15.51,26.98-15.51,39.52v275.12c0,12.54-10.18,21.48-22.61,19.86
+					l-138.12-58.41c-10.15-7.37-18.44-23.68-18.44-36.22V447.76c0-12.54-6.92-30.39-15.36-39.65L20.9,129.08
+					c-8.45-9.27-5.78-20.53,5.93-25.02c0,0,130.17-58.62,345.18-58.62c13.38,0,26.43,0.23,39.14,0.65
+					c-33.99,38.09-54.65,88.34-54.65,143.41C356.5,280.19,412.53,357.8,491.85,389.59z"/>
+			</g>
+		</g>
+	</g>
+</g>
+<polygon fill="#13A354" points="535.655,196.29 720.52,82.572 744,113.104 520.376,285.188 424.025,159.899 454.556,136.42 "/>
+</svg>

+ 11 - 0
themes/MetroMumbleLight/svg/handle_horizontal.svg

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="200px" height="500px" viewBox="0 0 200 500" enable-background="new 0 0 200 500" xml:space="preserve">
+<g>
+	<rect x="55" y="206" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+	<rect x="55" y="65" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+	<rect x="55" y="345" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+</g>
+</svg>

+ 11 - 0
themes/MetroMumbleLight/svg/handle_vertical.svg

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="200px" viewBox="0 0 500 200" enable-background="new 0 0 500 200" xml:space="preserve">
+<g>
+	<rect x="204" y="55" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+	<rect x="345" y="55" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+	<rect x="65" y="55" opacity="0.75" fill="#7F7F7F" enable-background="new    " width="90" height="90"/>
+</g>
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/information_icon.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
+<path fill="#FFB000" d="M337.29,101.836c0,46.914-37.998,84.902-84.901,84.902s-84.901-37.986-84.901-84.902
+	c0-46.903,37.998-84.89,84.901-84.89S337.29,54.933,337.29,101.836z"/>
+<g enable-background="new    ">
+	<path fill="#FFB000" d="M226.993,482.412c-28.762,0-52.295-13.074-52.295-41.836v-91.919c0-28.763-13.849-83.48-30.347-99.142
+		c-16.497-15.661-6.216-15.463,22.418-18.175l38.792-0.537c35.622,0,70.72,0.468,93.525,7.067s31.463,22.459,31.463,35.245
+		c0,12.785,0,46.779,0,75.542v91.919c0,28.763-23.533,41.836-52.295,41.836H226.993z"/>
+</g>
+</svg>

+ 38 - 0
themes/MetroMumbleLight/svg/layout_classic.svg

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<g id="svg2383" xmlns:svg="http://www.w3.org/2000/svg" display="none">
+	<g id="layer3" display="inline">
+	</g>
+	<g id="layer1" display="inline">
+		<path id="path2454" fill="#AFDDE9" stroke="#AFDDE9" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M13.627,45.318L3.218,45.27V27.908V10.545h14.364h14.364V28v17.455l-3.955-0.044C25.816,45.386,19.352,45.345,13.627,45.318
+			L13.627,45.318z"/>
+		<path id="path2456" fill="#37C8AB" stroke="#37C8AB" stroke-width="0.2275" stroke-linecap="round" stroke-linejoin="round" d="
+			M33.128,30.091V10.546h14.181H61.49v19.545v19.545H47.309H33.128V30.091z"/>
+		<path id="path2458" fill="#3771C8" stroke="#3771C8" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M3.218,47.971v-1.666l6.03,0.12c3.316,0.066,9.78,0.12,14.364,0.12h8.334v1.545v1.545H17.582H3.218V47.971z"/>
+	</g>
+	<g id="layer2" display="inline">
+		<text transform="matrix(1 0 0 1 9.4546 49.2727)" font-family="'ArialMT'" font-size="3.5">Chatbar</text>
+		<text transform="matrix(0 -1 1 0 51.7437 43.0049)" font-family="'ArialMT'" font-size="12">Tree</text>
+		
+			<rect id="rect2393" x="2.545" y="9.818" fill="none" stroke="#000000" stroke-width="1.247" stroke-linecap="round" stroke-linejoin="round" width="59.636" height="40.545"/>
+		<path id="path2403" fill="none" stroke="#000000" d="M32.545,50.182V9.818"/>
+		<path id="path2405" fill="none" stroke="#000000" d="M2.545,45.818l30,0.182"/>
+		<text transform="matrix(0 -1 1 0 20.5618 37.8232)" font-family="'ArialMT'" font-size="12">Log</text>
+	</g>
+</g>
+<g id="Layer_2">
+	<rect x="0.62" y="12.388" opacity="0.25" fill="#7F7F7F" enable-background="new    " width="62.764" height="39.228"/>
+	<g opacity="0.75">
+		<g>
+			<rect x="3.902" y="15.957" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="18.026" height="28.689"/>
+		</g>
+		<rect x="22.987" y="15.698" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="37.026" height="32.606"/>
+	</g>
+	<rect x="3.904" y="45.668" fill="#7F7F7F" enable-background="new    " width="18.026" height="2.582"/>
+</g>
+</svg>

+ 50 - 0
themes/MetroMumbleLight/svg/layout_custom.svg

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<g id="svg2383" xmlns:svg="http://www.w3.org/2000/svg" display="none">
+	<g id="layer3" display="inline">
+	</g>
+	<g id="layer1" display="inline">
+		<path id="path2454" fill="#AFDDE9" stroke="#AFDDE9" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M13.627,45.318L3.218,45.27V27.908V10.545h14.364h14.364V28v17.455l-3.955-0.044C25.816,45.386,19.352,45.345,13.627,45.318
+			L13.627,45.318z"/>
+		<path id="path2456" fill="#37C8AB" stroke="#37C8AB" stroke-width="0.2275" stroke-linecap="round" stroke-linejoin="round" d="
+			M33.128,30.091V10.546h14.181H61.49v19.545v19.545H47.309H33.128V30.091z"/>
+		<path id="path2458" fill="#3771C8" stroke="#3771C8" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M3.218,47.971v-1.666l6.03,0.12c3.316,0.066,9.78,0.12,14.364,0.12h8.334v1.545v1.545H17.582H3.218V47.971z"/>
+	</g>
+	<g id="layer2" display="inline">
+		<text transform="matrix(1 0 0 1 9.4546 49.2727)" font-family="'ArialMT'" font-size="3.5">Chatbar</text>
+		<text transform="matrix(0 -1 1 0 51.7437 43.0049)" font-family="'ArialMT'" font-size="12">Tree</text>
+		
+			<rect id="rect2393" x="2.545" y="9.818" fill="none" stroke="#000000" stroke-width="1.247" stroke-linecap="round" stroke-linejoin="round" width="59.636" height="40.545"/>
+		<path id="path2403" fill="none" stroke="#000000" d="M32.545,50.182V9.818"/>
+		<path id="path2405" fill="none" stroke="#000000" d="M2.545,45.818l30,0.182"/>
+		<text transform="matrix(0 -1 1 0 20.5618 37.8232)" font-family="'ArialMT'" font-size="12">Log</text>
+	</g>
+</g>
+<g id="Layer_2">
+	<rect x="0.62" y="12.388" opacity="0.25" fill="#7F7F7F" enable-background="new    " width="62.764" height="39.228"/>
+	<g opacity="0.75">
+		<g>
+			<rect x="3.902" y="15.646" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="18.026" height="32.606"/>
+		</g>
+		<g>
+			<rect x="22.987" y="15.698" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="18.026" height="32.606"/>
+		</g>
+		<g>
+			<rect x="42.072" y="15.698" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="18.026" height="32.606"/>
+		</g>
+	</g>
+	<g>
+		<path fill="#7F7F7F" d="M29.018,36.595c-0.569-1.467-0.407-3.278,0.469-4.587c0.973-1.454,2.812-2.231,3.519-3.877
+			c0.671-1.561-0.141-3.255-1.896-3.395c-1.869-0.149-3.775,0.776-5.146,1.981c0-1.43,0-2.86,0-4.289
+			c0-0.828,2.161-1.249,2.83-1.401c1.766-0.4,3.704-0.416,5.45,0.095c3.157,0.924,4.598,4.253,3.425,7.296
+			c-0.665,1.725-2.135,2.803-3.467,3.989c-1.159,1.033-2.168,2.652-1.187,4.19C31.687,36.599,30.34,36.64,29.018,36.595z
+			 M31.237,43.253c-1.435,0-2.827-0.992-2.827-2.524c0-1.535,1.396-2.492,2.827-2.492c1.432,0,2.782,0.97,2.782,2.491
+			C34.019,42.273,32.7,43.253,31.237,43.253z"/>
+	</g>
+</g>
+</svg>

+ 38 - 0
themes/MetroMumbleLight/svg/layout_hybrid.svg

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<g id="svg2383" xmlns:svg="http://www.w3.org/2000/svg" display="none">
+	<g id="layer3" display="inline">
+	</g>
+	<g id="layer1" display="inline">
+		<path id="path2454" fill="#AFDDE9" stroke="#AFDDE9" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M13.627,45.318L3.218,45.27V27.908V10.545h14.364h14.364V28v17.455l-3.955-0.044C25.816,45.386,19.352,45.345,13.627,45.318
+			L13.627,45.318z"/>
+		<path id="path2456" fill="#37C8AB" stroke="#37C8AB" stroke-width="0.2275" stroke-linecap="round" stroke-linejoin="round" d="
+			M33.128,30.091V10.546h14.181H61.49v19.545v19.545H47.309H33.128V30.091z"/>
+		<path id="path2458" fill="#3771C8" stroke="#3771C8" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M3.218,47.971v-1.666l6.03,0.12c3.316,0.066,9.78,0.12,14.364,0.12h8.334v1.545v1.545H17.582H3.218V47.971z"/>
+	</g>
+	<g id="layer2" display="inline">
+		<text transform="matrix(1 0 0 1 9.4546 49.2727)" font-family="'ArialMT'" font-size="3.5">Chatbar</text>
+		<text transform="matrix(0 -1 1 0 51.7437 43.0049)" font-family="'ArialMT'" font-size="12">Tree</text>
+		
+			<rect id="rect2393" x="2.545" y="9.818" fill="none" stroke="#000000" stroke-width="1.247" stroke-linecap="round" stroke-linejoin="round" width="59.636" height="40.545"/>
+		<path id="path2403" fill="none" stroke="#000000" d="M32.545,50.182V9.818"/>
+		<path id="path2405" fill="none" stroke="#000000" d="M2.545,45.818l30,0.182"/>
+		<text transform="matrix(0 -1 1 0 20.5618 37.8232)" font-family="'ArialMT'" font-size="12">Log</text>
+	</g>
+</g>
+<g id="Layer_2">
+	<rect x="0.62" y="12.388" opacity="0.25" fill="#7F7F7F" enable-background="new    " width="62.764" height="39.228"/>
+	<g opacity="0.75">
+		<g>
+			<rect x="3.902" y="15.646" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="18.026" height="29.085"/>
+		</g>
+		<rect x="22.987" y="15.698" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="37.026" height="29.002"/>
+	</g>
+	<rect x="3.904" y="45.668" fill="#7F7F7F" enable-background="new    " width="56.026" height="2.582"/>
+</g>
+</svg>

+ 40 - 0
themes/MetroMumbleLight/svg/layout_stacked.svg

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
+<g id="svg2383" xmlns:svg="http://www.w3.org/2000/svg" display="none">
+	<g id="layer3" display="inline">
+	</g>
+	<g id="layer1" display="inline">
+		<path id="path2454" fill="#AFDDE9" stroke="#AFDDE9" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M13.627,45.318L3.218,45.27V27.908V10.545h14.364h14.364V28v17.455l-3.955-0.044C25.816,45.386,19.352,45.345,13.627,45.318
+			L13.627,45.318z"/>
+		<path id="path2456" fill="#37C8AB" stroke="#37C8AB" stroke-width="0.2275" stroke-linecap="round" stroke-linejoin="round" d="
+			M33.128,30.091V10.546h14.181H61.49v19.545v19.545H47.309H33.128V30.091z"/>
+		<path id="path2458" fill="#3771C8" stroke="#3771C8" stroke-width="0.227" stroke-linecap="round" stroke-linejoin="round" d="
+			M3.218,47.971v-1.666l6.03,0.12c3.316,0.066,9.78,0.12,14.364,0.12h8.334v1.545v1.545H17.582H3.218V47.971z"/>
+	</g>
+	<g id="layer2" display="inline">
+		<text transform="matrix(1 0 0 1 9.4546 49.2727)" font-family="'ArialMT'" font-size="3.5">Chatbar</text>
+		<text transform="matrix(0 -1 1 0 51.7437 43.0049)" font-family="'ArialMT'" font-size="12">Tree</text>
+		
+			<rect id="rect2393" x="2.545" y="9.818" fill="none" stroke="#000000" stroke-width="1.247" stroke-linecap="round" stroke-linejoin="round" width="59.636" height="40.545"/>
+		<path id="path2403" fill="none" stroke="#000000" d="M32.545,50.182V9.818"/>
+		<path id="path2405" fill="none" stroke="#000000" d="M2.545,45.818l30,0.182"/>
+		<text transform="matrix(0 -1 1 0 20.5618 37.8232)" font-family="'ArialMT'" font-size="12">Log</text>
+	</g>
+</g>
+<g id="Layer_2">
+	<g>
+		<rect x="12.392" y="6.535" opacity="0.25" fill="#7F7F7F" enable-background="new    " width="39.228" height="50.931"/>
+		<g opacity="0.75">
+			<g>
+				<rect x="15.65" y="38.99" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="32.606" height="11.526"/>
+			</g>
+			<rect x="15.702" y="9.905" opacity="0.5" fill="#7F7F7F" enable-background="new    " width="32.523" height="28.026"/>
+		</g>
+		<rect x="15.667" y="51.594" fill="#7F7F7F" enable-background="new    " width="32.609" height="2.581"/>
+	</g>
+</g>
+</svg>

+ 12 - 0
themes/MetroMumbleLight/svg/media-record.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
+<path opacity="0.85" fill="#EA4335" enable-background="new    " d="M366.566,249.441c0.229,64.494-51.64,116.898-115.929,117.123
+	c-64.571,0.227-117.042-51.708-117.203-116.005c-0.162-64.701,51.523-116.88,116.016-117.124
+	C314.081,133.191,366.336,184.951,366.566,249.441z"/>
+<path opacity="0.85" fill="#EA4335" enable-background="new    " d="M250,70.443c-99.165,0-179.557,80.392-179.557,179.557
+	S150.835,429.557,250,429.557S429.557,349.165,429.557,250S349.165,70.443,250,70.443z M250,399.837
+	c-83.303,0-150.82-67.518-150.82-150.82S166.697,98.196,250,98.196s150.82,67.528,150.82,150.82S333.303,399.837,250,399.837z"/>
+</svg>

+ 37 - 0
themes/MetroMumbleLight/svg/mumble.svg

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1"
+	 id="svg2" xmlns:cc="http://creativecommons.org/ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" sodipodi:docname="mumble.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" inkscape:version="0.47pre1" sodipodi:version="0.32"
+	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="400px" height="400px"
+	 viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
+<g>
+	
+		<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="200" y1="6.758" x2="200" y2="395.242" gradientTransform="matrix(1 0 0 -1 0 401)">
+		<stop  offset="0" style="stop-color:#E0E0E1"/>
+		<stop  offset="1" style="stop-color:#FFFFFF"/>
+	</linearGradient>
+	<circle fill="url(#SVGID_1_)" stroke="#333333" stroke-width="4" stroke-miterlimit="10" cx="200" cy="200" r="194.242"/>
+</g>
+<linearGradient id="rect908-1-6_1_" gradientUnits="userSpaceOnUse" x1="200" y1="372.2291" x2="200" y2="27.7709">
+	<stop  offset="0" style="stop-color:#0D0D0D"/>
+	<stop  offset="1" style="stop-color:#4D4D4D"/>
+</linearGradient>
+<path id="rect908-1-6_2_" fill="url(#rect908-1-6_1_)" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="
+	M231.94,351.901c0.096-0.007,0.192-0.01,0.289-0.01h34.684c0,0,1.992-0.171,4.429-1.344c3.097-1.491,6.403-3.682,9.484-5.708
+	c3.431-2.257,6.633-4.662,10.006-7.172c0.484-0.36,0.925-0.727,1.326-1.093c-14.387,1.894-8.444-31.131-8.444-39.595
+	c0-32.397,0-64.794,0-97.191c0-30.201,0-60.403,0-90.604c0-21.108,0.309-55.955-30.833-53.681c0,12.738,0,25.477,0,38.215
+	c0,12.375,1.881,26.286-0.65,38.45c-5.397,25.934-27.61,31.294-50.703,31.057c-21.564-0.221-43.319-0.073-53.304-23.237
+	c-5.145-11.934-3.016-26.852-3.022-39.528c-0.007-15.02,0.104-30.039,0.03-45.059c-37.888-0.431-29.234,56.503-29.234,79.971
+	c0,45.081,0,90.162,0,135.243c0,16.776,0,33.551,0,50.327c0,13.156,1.133,16.682-14.462,16.773
+	c-29.951,0.176-52.396-31.962-60.156-57.258c-10.082-32.862-5.323-72.112,16.304-99.488c8.131-10.292,18.818-18.762,31.335-22.987
+	c0-16.889,0-33.779,0-50.668c0-15.811-0.956-32.214,6.622-46.67c10.526-20.08,33.343-32.533,55.814-31.986
+	c8.67-0.348,17.368,0.967,21.664,9.655c-0.163,17.965-0.142,35.931-0.134,53.897c0.006,12.412-3.546,31.71,3.145,42.911
+	c6.826,11.429,26.005,13.771,37.473,8.644c16.104-7.199,13.163-25.026,13.205-39.572c0.057-19.791,0.004-39.582-0.073-59.372
+	c-0.13-33.482,56.22-9.509,68.359,3.228c22.719,23.84,15.714,62.504,15.714,92.5c0,6.628-3.031,14.901,3.654,17.579
+	c5.4,2.163,10.46,5.131,15.064,8.68c11.022,8.495,19.36,20.152,25.017,32.788c20.518,45.825,7.596,124.753-50.139,136.449
+	c0.124,1.355-0.492,2.727-1.736,3.532c0,0-10.182,8.197-15.687,11.719c-5.179,3.08-8.109,5.592-12.606,7.565
+	c-1.804,0.791-4.836,1.674-5.676,1.674h-36.471l-1.258-0.203c-3.855,6.902-14.998,11.892-28.147,11.896
+	c-16.35,0.004-29.609-7.704-29.617-17.216c0-0.005,0-0.01,0-0.015c-0.007-9.512,13.241-17.227,29.59-17.231
+	c13.979-0.004,25.699,5.631,28.809,13.21L231.94,351.901z"/>
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/muted_local.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.9" fill="#9B59B6" d="M256,55.05c-41.43,0-75.02,33.59-75.02,75.02v100.89l150.04-81.8v-19.09
+	C331.02,88.64,297.43,55.05,256,55.05z"/>
+<path opacity="0.9" fill="#9B59B6" d="M274.54,444.93c62.37-8.99,110.29-62.66,110.29-127.51l-26.71,0.79
+	c0,56.4-45.72,102.12-102.12,102.12c-44.12,0-81.71-27.98-95.97-67.17l-0.001-0.002l27.46-14.971l0.001,0.003
+	c11.71,26.19,37.98,44.43,68.51,44.43c41.43,0,75.02-33.59,75.02-75.02l0.001-47.667L481.5,177.89l-22.98-42.14L30.5,369.11
+	l22.98,42.14l83.149-45.333l0.001,0.003c16.91,41.62,54.96,72.39,100.83,79.01v27.24h-73.4c-10.41,0-18.85,8.44-18.85,18.85v-2.93
+	c0,10.42,8.44,18.86,18.85,18.86h183.88c10.41,0,18.85-8.44,18.85-18.86v2.93c0-10.41-8.44-18.85-18.85-18.85h-73.4V444.93z"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/muted_self.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M256,55.05c-41.43,0-75.02,33.59-75.02,75.02v100.89
+	l150.04-81.8v-19.09C331.02,88.64,297.43,55.05,256,55.05z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M237.46,444.93L237.46,444.93z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M274.54,444.93L274.54,444.93z"/>
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M274.54,444.93c62.37-8.99,110.29-62.66,110.29-127.51
+	l-26.71,0.79c0,56.4-45.72,102.12-102.12,102.12c-44.12,0-81.71-27.98-95.97-67.17l-0.001-0.002l27.46-14.971l0.001,0.003
+	c11.71,26.19,37.98,44.43,68.51,44.43c41.43,0,75.02-33.59,75.02-75.02l0.001-47.667L481.5,177.89l-22.98-42.14L30.5,369.11
+	l22.98,42.14l83.149-45.333l0.001,0.003c16.91,41.62,54.96,72.39,100.83,79.01v27.24h-73.4c-10.41,0-18.85,8.44-18.85,18.85v-2.93
+	c0,10.42,8.44,18.86,18.85,18.86h183.88c10.41,0,18.85-8.44,18.85-18.86v2.93c0-10.41-8.44-18.85-18.85-18.85h-73.4V444.93z"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/muted_server.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path fill="#00B4DF" d="M256,55.05c-41.43,0-75.02,33.59-75.02,75.02v100.89l150.04-81.8v-19.09
+	C331.02,88.64,297.43,55.05,256,55.05z"/>
+<path fill="#FFD700" d="M237.46,444.93L237.46,444.93z"/>
+<path fill="#FFD700" d="M274.54,444.93L274.54,444.93z"/>
+<path fill="#00B4DF" d="M274.54,444.93c62.37-8.99,110.29-62.66,110.29-127.51l-26.71,0.79c0,56.4-45.72,102.12-102.12,102.12
+	c-44.12,0-81.71-27.98-95.97-67.17l-0.001-0.002l27.46-14.971l0.001,0.003c11.71,26.19,37.98,44.43,68.51,44.43
+	c41.43,0,75.02-33.59,75.02-75.02l0.001-47.667L481.5,177.89l-22.98-42.14L30.5,369.11l22.98,42.14l83.149-45.333l0.001,0.003
+	c16.91,41.62,54.96,72.39,100.83,79.01v27.24h-73.4c-10.41,0-18.85,8.44-18.85,18.85v-2.93c0,10.42,8.44,18.86,18.85,18.86h183.88
+	c10.41,0,18.85-8.44,18.85-18.86v2.93c0-10.41-8.44-18.85-18.85-18.85h-73.4V444.93z"/>
+</svg>

+ 15 - 0
themes/MetroMumbleLight/svg/muted_suppressed.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M256,55.05c-41.43,0-75.02,33.59-75.02,75.02v100.89l150.04-81.8
+	v-19.09C331.02,88.64,297.43,55.05,256,55.05z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M237.46,444.93L237.46,444.93z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M274.54,444.93L274.54,444.93z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M274.54,444.93c62.37-8.99,110.29-62.66,110.29-127.51
+	l-26.71,0.79c0,56.4-45.72,102.12-102.12,102.12c-44.12,0-81.71-27.98-95.97-67.17l-0.001-0.002l27.46-14.971l0.001,0.003
+	c11.71,26.19,37.98,44.43,68.51,44.43c41.43,0,75.02-33.59,75.02-75.02l0.001-47.667L481.5,177.89l-22.98-42.14L30.5,369.11
+	l22.98,42.14l83.149-45.333l0.001,0.003c16.91,41.62,54.96,72.39,100.83,79.01v27.24h-73.4c-10.41,0-18.85,8.44-18.85,18.85v-2.93
+	c0,10.42,8.44,18.86,18.85,18.86h183.88c10.41,0,18.85-8.44,18.85-18.86v2.93c0-10.41-8.44-18.85-18.85-18.85h-73.4V444.93z"/>
+</svg>

+ 29 - 0
themes/MetroMumbleLight/svg/priority_speaker.svg

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="141.732px" height="141.732px" viewBox="0 0 141.732 141.732" enable-background="new 0 0 141.732 141.732"
+	 xml:space="preserve">
+<g>
+</g>
+<g>
+	<g>
+		<g>
+			<g>
+				<path fill="#00B4DF" d="M112.346,99.875c-7.758,5.068-25.279-11.092-34.262-14.148c-2.521-0.859-7.765-1.967-10.414-2.253
+					c-0.914-0.092-1.985-0.175-3.176-0.24c1.357,7.368,3.611,30.804,10.304,37.844c3.72,3.913-4.367,9.768-9.759,9.768h-6.491
+					c-5.392,0-9.759-4.376-9.759-9.768c0,0,0.913-32.014-6.638-38.02c-5.799-4.612-22.186,1.404-29.593,1.605
+					c-3.163,0.086-5.753-2.589-5.753-5.753l0-39.615c0-3.164,2.589-5.785,5.753-5.753c13.78,0.14,41.344,1.72,55.112,1.119
+					c2.663-0.116,7.912-1.348,10.414-2.253c8.928-3.222,26.52-19.241,34.262-14.148C109.415,16.333,109.313,101.856,112.346,99.875z
+					"/>
+			</g>
+		</g>
+	</g>
+</g>
+<g>
+	<path fill="#00B4DF" d="M124.029,86.874c-2.418-2.561-3.747-5.338-2.953-6.173c0,0,0,0,0.656-0.798
+		c10.009-12.188,9.711-30.3-0.894-42.135c-0.388-0.433-0.388-0.433-0.388-0.433c-0.45-0.462,1.161-2.935,3.58-5.496
+		c2.418-2.561,5.091-3.936,5.939-3.057c0,0,0,0,0.718,0.83c14.473,16.73,14.723,41.587,0.75,58.599
+		c-0.939,1.144-0.939,1.144-0.939,1.144C129.358,90.551,126.448,89.435,124.029,86.874z"/>
+</g>
+</svg>

+ 14 - 0
themes/MetroMumbleLight/svg/self_comment.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g id="Layer_2" display="none">
+	<rect x="-109.5" y="-86.5" display="inline" stroke="#000000" stroke-miterlimit="10" width="721" height="687"/>
+</g>
+<path opacity="0.9" fill="#9B59B6" d="M439.473,83.515H72.528c-16.069,0-29.062,12.993-29.062,29.062v277.67
+	c0,16.058,12.993,29.062,29.062,29.062h58.114v87.176l130.774-87.176h178.057c16.069,0,29.062-13.004,29.062-29.062v-277.67
+	C468.535,96.508,455.541,83.515,439.473,83.515z"/>
+<line fill="none" x1="349.5" y1="241.48" x2="349.5" y2="288.23"/>
+<line fill="none" x1="162.5" y1="288.23" x2="162.5" y2="241.48"/>
+</svg>

+ 3 - 0
themes/MetroMumbleLight/svg/source-code.svg

@@ -0,0 +1,3 @@
+<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg">
+  <path d="M512 0C229.25 0 0 229.25 0 512c0 226.25 146.688 418.125 350.156 485.812 25.594 4.688 34.938-11.125 34.938-24.625 0-12.188-0.469-52.562-0.719-95.312C242 908.812 211.906 817.5 211.906 817.5c-23.312-59.125-56.844-74.875-56.844-74.875-46.531-31.75 3.53-31.125 3.53-31.125 51.406 3.562 78.47 52.75 78.47 52.75 45.688 78.25 119.875 55.625 149 42.5 4.654-33 17.904-55.625 32.5-68.375C304.906 725.438 185.344 681.5 185.344 485.312c0-55.938 19.969-101.562 52.656-137.406-5.219-13-22.844-65.094 5.062-135.562 0 0 42.938-13.75 140.812 52.5 40.812-11.406 84.594-17.031 128.125-17.219 43.5 0.188 87.312 5.875 128.188 17.281 97.688-66.312 140.688-52.5 140.688-52.5 28 70.531 10.375 122.562 5.125 135.5 32.812 35.844 52.625 81.469 52.625 137.406 0 196.688-119.75 240-233.812 252.688 18.438 15.875 34.75 47 34.75 94.75 0 68.438-0.688 123.625-0.688 140.5 0 13.625 9.312 29.562 35.25 24.562C877.438 930 1024 738.125 1024 512 1024 229.25 794.75 0 512 0z" />
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/talking_alt.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path fill="#00B4DF" d="M256.104,59.479c63.393,0,114.783,51.39,114.783,114.783s-51.39,114.783-114.783,114.783
+	s-114.783-51.39-114.783-114.783S192.711,59.479,256.104,59.479z M256.104,239.852c102.91,0,186.335,60.066,186.335,134.161
+	s-83.425,134.161-186.335,134.161S69.769,448.108,69.769,374.013S153.194,239.852,256.104,239.852z"/>
+<path fill="#00B4DF" d="M439.061,251.956l-33.312-22.57c39.665-56.785,25.166-137.337-26.215-173.23l22.57-32.313
+	C487.432,83.446,499.041,166.086,439.061,251.956z"/>
+<path fill="#00B4DF" d="M111.561,23.827l22.593,32.297c-51.367,35.93-68.125,116.506-28.431,173.255L73.426,251.97
+	C12.513,164.889,24.48,84.74,111.561,23.827z"/>
+</svg>

+ 14 - 0
themes/MetroMumbleLight/svg/talking_off.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.75" fill="#FF3E3E" enable-background="new    " d="M256.104,59.479c63.393,0,114.783,51.39,114.783,114.783
+	s-51.39,114.783-114.783,114.783s-114.783-51.39-114.783-114.783S192.711,59.479,256.104,59.479z M256.104,239.852
+	c102.91,0,186.335,60.066,186.335,134.161s-83.425,134.161-186.335,134.161S69.769,448.108,69.769,374.013
+	S153.194,239.852,256.104,239.852z"/>
+<path opacity="0.01" fill="#FF3E3E" enable-background="new    " d="M439.061,251.956l-33.312-22.57
+	c39.665-56.785,25.166-137.337-26.215-173.23l22.57-32.313C487.432,83.446,499.041,166.086,439.061,251.956z"/>
+<path opacity="0.01" fill="#FF3E3E" enable-background="new    " d="M111.561,23.827l22.593,32.297
+	c-51.367,35.93-68.125,116.506-28.431,173.255L73.426,251.97C12.513,164.889,24.48,84.74,111.561,23.827z"/>
+</svg>

+ 14 - 0
themes/MetroMumbleLight/svg/talking_on.svg

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M256.104,59.479c63.393,0,114.783,51.39,114.783,114.783
+	s-51.39,114.783-114.783,114.783s-114.783-51.39-114.783-114.783S192.711,59.479,256.104,59.479z M256.104,239.852
+	c102.91,0,186.335,60.066,186.335,134.161s-83.425,134.161-186.335,134.161S69.769,448.108,69.769,374.013
+	S153.194,239.852,256.104,239.852z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M439.061,251.956l-33.312-22.57
+	c39.665-56.785,25.166-137.337-26.215-173.23l22.57-32.313C487.432,83.446,499.041,166.086,439.061,251.956z"/>
+<path opacity="0.9" fill="#13A354" enable-background="new    " d="M111.561,23.827l22.593,32.297
+	c-51.367,35.93-68.125,116.506-28.431,173.255L73.426,251.97C12.513,164.889,24.48,84.74,111.561,23.827z"/>
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/talking_whisper.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<path opacity="0.9" fill="#9B59B6" d="M256.104,59.479c63.393,0,114.783,51.39,114.783,114.783s-51.39,114.783-114.783,114.783
+	s-114.783-51.39-114.783-114.783S192.711,59.479,256.104,59.479z M256.104,239.852c102.91,0,186.335,60.066,186.335,134.161
+	s-83.425,134.161-186.335,134.161S69.769,448.108,69.769,374.013S153.194,239.852,256.104,239.852z"/>
+<path opacity="0.9" fill="#9B59B6" d="M439.061,251.956l-33.312-22.57c39.665-56.785,25.166-137.337-26.215-173.23l22.57-32.313
+	C487.432,83.446,499.041,166.086,439.061,251.956z"/>
+<path opacity="0.9" fill="#9B59B6" d="M111.561,23.827l22.593,32.297c-51.367,35.93-68.125,116.506-28.431,173.255L73.426,251.97
+	C12.513,164.889,24.48,84.74,111.561,23.827z"/>
+</svg>

+ 13 - 0
themes/MetroMumbleLight/svg/toolbar-comment.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+<g id="Layer_2" display="none">
+	<rect x="-109.5" y="-86.5" display="inline" stroke="#000000" stroke-miterlimit="10" width="721" height="687"/>
+</g>
+<path fill="#FFB000" d="M430.81,103.5H81.19c-15.31,0-27.69,12.38-27.69,27.69v264.56c0,15.3,12.38,27.69,27.69,27.69h55.37v83.06
+	l124.6-83.06h169.65c15.31,0,27.69-12.39,27.69-27.69V131.19C458.5,115.88,446.12,103.5,430.81,103.5z"/>
+<line fill="none" x1="349.5" y1="241.48" x2="349.5" y2="288.23"/>
+<line fill="none" x1="162.5" y1="288.23" x2="162.5" y2="241.48"/>
+</svg>

+ 93 - 0
webpack.config.js

@@ -0,0 +1,93 @@
+var theme = 'MetroMumbleLight'
+
+var path = require('path')
+
+module.exports = {
+  entry: [
+    './app/index.js',
+    './app/index.html'
+  ],
+  output: {
+    filename: 'index.js',
+    path: './dist'
+  },
+  module: {
+    postLoaders: [
+      {
+        include: /mumble-streams\/lib\/data.js/,
+        loader: 'transform-loader?brfs'
+      }
+    ],
+    loaders: [
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel-loader',
+        query: {
+          presets: ['es2015'],
+          plugins: ['transform-runtime']
+        }
+      },
+      {
+        test: /\.html$/,
+        loaders: [
+          'file-loader?name=[name].[ext]',
+          'extract-loader',
+          'html-loader?' + JSON.stringify({
+            attrs: ['img:src', 'link:href'],
+            interpolate: 'require',
+            root: theme
+          })
+        ]
+      },
+      {
+        test: /\.css$/,
+        loaders: [
+          'file-loader',
+          'extract-loader',
+          'css-loader'
+        ]
+      },
+      {
+        test: /manifest\.json$|\.xml$/,
+        loaders: [
+          'file-loader',
+          'extract-loader',
+          'regexp-replace-loader?' + JSON.stringify({
+            match: {
+              pattern: "#require\\('([^']*)'\\)",
+              flags: 'g'
+            },
+            replaceWith: '"+require("$1")+"'
+          }),
+          'raw-loader'
+        ]
+      },
+      {
+        test: /\.json$/,
+        exclude: /manifest\.json$/,
+        loader: 'json-loader'
+      },
+      {
+        test: /\.(svg|png|ico)$/,
+        loader: 'file-loader'
+      }
+    ]
+  },
+  resolve: {
+    alias: {
+      webworkify: 'webworkify-webpack-dropin'
+    },
+    root: [
+      path.resolve('./themes/')
+    ]
+  },
+  includes: {
+    pattern: function (filepath) {
+      return {
+        re: /#require\((.+)\)/,
+        index: 1
+      }
+    }
+  }
+}