diff --git a/github b/github index 605c418..2d7be74 160000 --- a/github +++ b/github @@ -1 +1 @@ -Subproject commit 605c418ac7e5b158426cee96712e7bbc2033e0b6 +Subproject commit 2d7be74482f4bec8f06810b3cd8406785ebfcfa1 diff --git a/modules/renderer/ExternalModalHandler.ts b/modules/renderer/ExternalModalHandler.ts index 3a60a15..9e8d998 100644 --- a/modules/renderer/ExternalModalHandler.ts +++ b/modules/renderer/ExternalModalHandler.ts @@ -22,7 +22,7 @@ class ExternalModalController extends AbstractExternalModalController { } this.window = new remote.BrowserWindow({ - parent: remote.getCurrentWindow(), + /* parent: remote.getCurrentWindow(), */ /* do not link them together */ autoHideMenuBar: true, webPreferences: { diff --git a/modules/renderer/IconHelper.ts b/modules/renderer/IconHelper.ts index cdd704e..6a54e6c 100644 --- a/modules/renderer/IconHelper.ts +++ b/modules/renderer/IconHelper.ts @@ -1,35 +1,26 @@ import * as electron from "electron"; import * as loader from "tc-loader"; import {Stage} from "tc-loader"; -import NativeImage = electron.NativeImage; -let _div: JQuery; -let _icon_mash_url: string; -let _icon_mask_img: NativeImage; -let _cache_klass_map: {[key: string]: NativeImage}; +import { + spriteUrl as kClientSpriteUrl, + spriteWidth as kClientSpriteWidth, + spriteHeight as kClientSpriteHeight, + spriteEntries as kClientSpriteEntries +} from "svg-sprites/client-icons"; +import {NativeImage} from "electron"; -export function class_to_image(klass: string) : NativeImage { - if(!klass || !_icon_mask_img || !_cache_klass_map) - return undefined; +let nativeSprite: NativeImage; - if(_cache_klass_map[klass]) - return _cache_klass_map[klass]; +export function clientIconClassToImage(klass: string) : NativeImage { + const sprite = kClientSpriteEntries.find(e => e.className === klass); + if(!sprite) return undefined; - _div[0].classList.value = 'icon ' + klass; - const data = window.getComputedStyle(_div[0]); - - const offset_x = parseInt(data.backgroundPositionX.split(",")[0]); - const offset_y = parseInt(data.backgroundPositionY.split(",")[0]); - - //http://localhost/home/TeaSpeak/Web-Client/web/environment/development/img/client_icon_sprite.svg - //const hight = element.css('height'); - //const width = element.css('width'); - console.log("Offset: x: %o y: %o;", offset_x, offset_y); - return _cache_klass_map[klass] = _icon_mask_img.crop({ - height: 16, - width: 16, - x: offset_x == 0 ? 0 : -offset_x, - y: offset_y == 0 ? 0 : -offset_y + return nativeSprite.crop({ + height: sprite.height, + width: sprite.width, + x: sprite.xOffset, + y: sprite.yOffset }); } @@ -37,33 +28,22 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, { priority: 100, name: "native icon sprite loader", function: async () => { - if(!_div) { - _div = $(document.createElement("div")); - _div.css('display', 'none'); - _div.appendTo(document.body); - } - const image = new Image(); - image.src = 'img/client_icon_sprite.svg'; + image.src = kClientSpriteUrl; await new Promise((resolve, reject) => { image.onload = resolve; - image.onerror = reject; + image.onerror = () => reject("failed to load client icon sprite"); }); - /* TODO: Get a size! */ const canvas = document.createElement("canvas"); - canvas.width = 1024; - canvas.height = 1024; + canvas.width = kClientSpriteWidth; + canvas.height = kClientSpriteHeight; canvas.getContext("2d").drawImage(image, 0, 0); - _cache_klass_map = {}; - _icon_mash_url = canvas.toDataURL(); - _icon_mask_img = electron.remote.nativeImage.createFromDataURL(_icon_mash_url); + nativeSprite = electron.remote.nativeImage.createFromDataURL( canvas.toDataURL()); } }) export function finalize() { - _icon_mask_img = undefined; - _icon_mash_url = undefined; - _cache_klass_map = undefined; + nativeSprite = undefined; } \ No newline at end of file diff --git a/modules/renderer/MenuBarHandler.ts b/modules/renderer/MenuBarHandler.ts index 29be765..f7e58ac 100644 --- a/modules/renderer/MenuBarHandler.ts +++ b/modules/renderer/MenuBarHandler.ts @@ -1,4 +1,4 @@ -import {class_to_image} from "./IconHelper"; +import {clientIconClassToImage} from "./IconHelper"; import * as electron from "electron"; import * as mbar from "tc-shared/ui/frames/MenuBar"; import {Arguments, process_args} from "../shared/process-arguments"; @@ -73,7 +73,7 @@ namespace native { icon(klass?: string | Promise | LocalIcon): string { if(typeof(klass) === "string") { - const buffer = class_to_image(klass); + const buffer = clientIconClassToImage(klass); if(buffer) this._icon_data = buffer.toDataURL(); } diff --git a/modules/renderer/PersistentLocalStorage.ts b/modules/renderer/PersistentLocalStorage.ts index 8f05184..48c9948 100644 --- a/modules/renderer/PersistentLocalStorage.ts +++ b/modules/renderer/PersistentLocalStorage.ts @@ -60,7 +60,6 @@ export async function initialize() { }); (_new_storage as any)["length"] = Object.keys(_local_storage).length; }; - Object.assign(window.localStorage, _new_storage); /* try to save everything all 60 seconds */ @@ -93,6 +92,7 @@ export async function delete_key(key: string) { await fs.remove(setting_path); /* could be async because we're not carrying about data */ } -window.addEventListener("beforeunload", event => { +window.addEventListener("beforeunload", () => { + console.log("Save local storage"); save_all_sync(); }); \ No newline at end of file diff --git a/modules/renderer/RequireProxy.ts b/modules/renderer/RequireProxy.ts index abf0ce7..76d83e5 100644 --- a/modules/renderer/RequireProxy.ts +++ b/modules/renderer/RequireProxy.ts @@ -94,6 +94,41 @@ overrides.push({ } }); +function resolveModuleMapping(context: string, resource: string) { + if(context.endsWith("/")) + context = context.substring(0, context.length - 1); + + const loader = require("tc-loader"); + + const mapping = loader.module_mapping().find(e => e.application === "client-app"); //FIXME: Variable name! + if(!mapping) throw "missing mapping"; + + const entries = mapping.modules.filter(e => e.context === context); + if(!entries.length) { + debugger; + throw "unknown target path"; + } + + const entry = entries.find(e => path.basename(e.resource, path.extname(e.resource)) === resource); + if(!entry) { + if(resource.indexOf(".") === -1 && !resource.endsWith("/")) + return resolveModuleMapping(context + "/" + resource, "index"); + + throw "unknown import (" + context + "/" + resource + ")"; + } + + return entry.id; +} + +overrides.push({ + name: "svg sprites", + test: /^svg-sprites\/.*/, + callback: request => { + const entryId = resolveModuleMapping("svg-sprites", request.substring("svg-sprites/".length)); + return window["shared-require"](entryId); + } +}); + overrides.push({ name: "shared loader", test: /^tc-shared\/.*/, @@ -101,25 +136,8 @@ overrides.push({ if(request.endsWith("/")) return require(request + "index"); - const webpack_path = path.dirname("shared/js/" + request.substr(10)); //FIXME: Get the prefix from a variable! - const loader = require("tc-loader"); - - const mapping = loader.module_mapping().find(e => e.application === "client-app"); //FIXME: Variable name! - if(!mapping) throw "missing mapping"; - - const entries = mapping.modules.filter(e => e.context.startsWith(webpack_path)); - if(!entries.length) throw "unknown target path"; - - const basename = path.basename(request, path.extname(request)); - const entry = entries.find(e => path.basename(e.resource, path.extname(e.resource)) === basename); - if(!entry) { - if(basename.indexOf(".") === -1 && !request.endsWith("/")) - return require(request + "/index"); - - debugger; - throw "unknown import (" + request + ")"; - } - - return window["shared-require"](entry.id); + let contextPath = path.dirname(request.substr(10)); + const entryId = resolveModuleMapping("shared/js/" + (contextPath === "." ? "" : contextPath), path.basename(request, path.extname(request))); + return window["shared-require"](entryId); } }); \ No newline at end of file diff --git a/modules/renderer/audio/sounds.ts b/modules/renderer/audio/sounds.ts index 09d5c20..e188043 100644 --- a/modules/renderer/audio/sounds.ts +++ b/modules/renderer/audio/sounds.ts @@ -9,7 +9,7 @@ export async function play_sound(file: SoundFile) : Promise { pathname = pathname.substr(1); const path = paths.join(pathname, file.path); - console.log(path); + console.log("replaying %s (volume: %f)", file.path, file.volume); naudio.sounds.playback_sound({ callback: (result, message) => { if(result == naudio.sounds.PlaybackResult.SUCCEEDED) @@ -18,7 +18,7 @@ export async function play_sound(file: SoundFile) : Promise { reject(naudio.sounds.PlaybackResult[result].toLowerCase() + ": " + message); }, file: path, - volume: file.volume + volume: file.volume || 1 }); }); } \ No newline at end of file diff --git a/modules/renderer/context-menu.ts b/modules/renderer/context-menu.ts index 7904b88..4e3f803 100644 --- a/modules/renderer/context-menu.ts +++ b/modules/renderer/context-menu.ts @@ -1,4 +1,4 @@ -import {class_to_image} from "./IconHelper"; +import {clientIconClassToImage} from "./IconHelper"; import * as contextmenu from "tc-shared/ui/elements/ContextMenu"; import * as electron from "electron"; const remote = electron.remote; @@ -56,7 +56,7 @@ class ElectronContextMenu implements contextmenu.ContextMenuProvider { label: (typeof entry.name === "function" ? (entry.name as (() => string))() : entry.name) as string, type: "normal", click: click_callback, - icon: class_to_image(entry.icon_class), + icon: clientIconClassToImage(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); @@ -77,7 +77,7 @@ class ElectronContextMenu implements contextmenu.ContextMenuProvider { type: "checkbox", checked: !!entry.checkbox_checked, click: click_callback, - icon: class_to_image(entry.icon_class), + icon: clientIconClassToImage(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); @@ -95,7 +95,7 @@ class ElectronContextMenu implements contextmenu.ContextMenuProvider { type: "submenu", submenu: sub_menu, click: click_callback, - icon: class_to_image(entry.icon_class), + icon: clientIconClassToImage(entry.icon_class), visible: entry.visible, enabled: !entry.disabled }); diff --git a/native/ppt/CMakeLists.txt b/native/ppt/CMakeLists.txt index f054b7f..ba6ba79 100644 --- a/native/ppt/CMakeLists.txt +++ b/native/ppt/CMakeLists.txt @@ -10,7 +10,12 @@ else() endif() add_nodejs_module(${MODULE_NAME} binding.cc ${SOURCE_FILES}) +if (WIN32) + target_compile_definitions(${MODULE_NAME} PUBLIC /O2) +endif() + add_executable(Hook-Test ${SOURCE_FILES} test/HookTest.cpp) + if(NOT MSVC) target_link_libraries(${MODULE_NAME} X11) target_link_libraries(Hook-Test X11 pthread) diff --git a/native/serverconnection/CMakeLists.txt b/native/serverconnection/CMakeLists.txt index 511532a..38abb18 100644 --- a/native/serverconnection/CMakeLists.txt +++ b/native/serverconnection/CMakeLists.txt @@ -173,6 +173,9 @@ endif() add_definitions(-DNO_OPEN_SSL) target_link_libraries(${MODULE_NAME} ${REQUIRED_LIBRARIES}) target_compile_definitions(${MODULE_NAME} PUBLIC -DNODEJS_API) +if (WIN32) + target_compile_definitions(${MODULE_NAME} PUBLIC /O2) +endif() add_executable(Audio-Test ${SOURCE_FILES} test/audio/main.cpp) target_link_libraries(Audio-Test ${REQUIRED_LIBRARIES}) diff --git a/native/serverconnection/src/audio/AudioInput.cpp b/native/serverconnection/src/audio/AudioInput.cpp index 9a6d166..21afc86 100644 --- a/native/serverconnection/src/audio/AudioInput.cpp +++ b/native/serverconnection/src/audio/AudioInput.cpp @@ -299,7 +299,7 @@ void AudioInput::consume(const void *input, size_t frameCount, size_t channels) frameCount = (size_t) result; input = this->resample_buffer; - audio::apply_gain(input, this->_channel_count, frameCount); + audio::apply_gain(this->resample_buffer, this->_channel_count, frameCount, this->_volume); } else if(this->_volume != 1) { const auto byte_size = frameCount * this->_channel_count * sizeof(float); if(this->resample_buffer_size < byte_size) { @@ -311,8 +311,7 @@ void AudioInput::consume(const void *input, size_t frameCount, size_t channels) memcpy(this->resample_buffer, input, byte_size); input = this->resample_buffer; - - audio::apply_gain(input, this->_channel_count, frameCount); + audio::apply_gain(this->resample_buffer, this->_channel_count, frameCount, this->_volume); } auto begin = chrono::system_clock::now(); diff --git a/package.json b/package.json index e596db4..243f079 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "start-n": "electron . -t --disable-hardware-acceleration --no-single-instance -u=https://clientapi.teaspeak.de/ -d", "start-nd": "electron . -t --disable-hardware-acceleration --no-single-instance -u=http://clientapi.teaspeak.dev/ -d", "start-01": "electron . --updater-channel=test -u=http://dev.clientapi.teaspeak.de/ -d --updater-ui-loader_type=0 --updater-local-version=1.0.1", + "start-devel-download": "electron . --disable-hardware-acceleration --gdb --debug --updater-ui-loader_type=2 --updater-ui-ignore-version -t -u http://localhost:8081/", "start-s": "electron . --disable-hardware-acceleration --gdb --debug --updater-ui-loader_type=3 --updater-ui-ignore-version -t -u http://localhost:8081/", "dtest": "electron . dtest", "compile-sass": "sass --update .:.", diff --git a/tsconfig.json b/tsconfig.json index b5985f0..beb5318 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,8 @@ "baseUrl": ".", "paths": { "tc-shared/*": ["imports/shared-app/*"], - "tc-loader": ["imports/loader"] + "tc-loader": ["imports/loader"], + "svg-sprites/*": ["imports/svg-sprites/*"] } }, "exclude": [