From 5734a1d33c00cae1a58d5b2daec6dd45f02fa535 Mon Sep 17 00:00:00 2001 From: V Date: Thu, 16 Oct 2025 10:52:52 +0200 Subject: [PATCH] libvesktop: native dbus module for autostart & app badge (#1180) Both setAppBadge and autoStart at system boot now use dbus calls. This means that autoStart will work in Flatpak --- README.md | 13 +- package.json | 2 + packages/libvesktop/.gitignore | 1 + packages/libvesktop/Dockerfile | 19 + packages/libvesktop/binding.gyp | 19 + packages/libvesktop/build.sh | 17 + packages/libvesktop/index.d.ts | 3 + packages/libvesktop/package.json | 14 + packages/libvesktop/pnpm-lock.yaml | 730 ++++++++++++++++++ .../libvesktop/prebuilds/vesktop-arm64.node | Bin 0 -> 55832 bytes .../libvesktop/prebuilds/vesktop-x64.node | Bin 0 -> 62824 bytes packages/libvesktop/src/libvesktop.cc | 269 +++++++ packages/libvesktop/test.js | 22 + pnpm-lock.yaml | 3 + scripts/build/build.mts | 24 + src/main/appBadge.ts | 6 +- src/main/autoStart.ts | 69 +- src/main/constants.ts | 10 +- src/main/dbus.ts | 40 + src/main/ipc.ts | 3 +- src/main/mainWindow.ts | 3 +- src/main/utils/desktopFileEscape.ts | 56 ++ src/main/utils/vencordLoader.ts | 3 +- src/main/vencordFilesDir.ts | 13 + .../components/settings/AutoStartToggle.tsx | 30 +- src/shared/settings.d.ts | 2 + static/views/about.html | 11 +- static/views/updater.html | 123 --- 28 files changed, 1338 insertions(+), 167 deletions(-) create mode 100644 packages/libvesktop/.gitignore create mode 100644 packages/libvesktop/Dockerfile create mode 100644 packages/libvesktop/binding.gyp create mode 100755 packages/libvesktop/build.sh create mode 100644 packages/libvesktop/index.d.ts create mode 100644 packages/libvesktop/package.json create mode 100644 packages/libvesktop/pnpm-lock.yaml create mode 100755 packages/libvesktop/prebuilds/vesktop-arm64.node create mode 100755 packages/libvesktop/prebuilds/vesktop-x64.node create mode 100644 packages/libvesktop/src/libvesktop.cc create mode 100644 packages/libvesktop/test.js create mode 100644 src/main/dbus.ts create mode 100644 src/main/utils/desktopFileEscape.ts create mode 100644 src/main/vencordFilesDir.ts delete mode 100644 static/views/updater.html diff --git a/README.md b/README.md index 967d1c2..5da8894 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Vesktop is a custom Discord desktop app ## Installing -Visit https://vesktop.vencord.dev/install +Visit https://vesktop.dev/install ## Building from Source @@ -47,3 +47,14 @@ pnpm package --linux pacman # Or package to a directory only pnpm package:dir ``` + +## Building LibVesktop from Source + +This is a small C++ helper library Vesktop uses on Linux to emit D-Bus events. By default, prebuilt binaries for x64 and arm64 are used. + +If you want to build it from source: +1. Install build dependencies: + - Debian/Ubuntu: `apt install build-essential python3 curl pkg-config libglib2.0-dev` + - Fedora: `dnf install @c-development @development-tools python3 curl pkgconf-pkg-config glib2-devel` +2. Run `pnpm buildLibVesktop` +3. From now on, building Vesktop will use your own build \ No newline at end of file diff --git a/package.json b/package.json index 02f41d3..e3ef779 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "scripts": { "build": "tsx scripts/build/build.mts", "build:dev": "pnpm build --dev", + "buildLibVesktop": "pnpm -C packages/libvesktop install && pnpm -C packages/libvesktop run build", "package": "pnpm build && electron-builder", "package:dir": "pnpm build && electron-builder --dir", "lint": "eslint", @@ -49,6 +50,7 @@ "eslint-plugin-simple-header": "^1.2.2", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unused-imports": "^4.2.0", + "libvesktop": "link:packages/libvesktop", "prettier": "^3.6.2", "source-map-support": "^0.5.21", "tsx": "^4.20.6", diff --git a/packages/libvesktop/.gitignore b/packages/libvesktop/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/packages/libvesktop/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/packages/libvesktop/Dockerfile b/packages/libvesktop/Dockerfile new file mode 100644 index 0000000..864ff26 --- /dev/null +++ b/packages/libvesktop/Dockerfile @@ -0,0 +1,19 @@ +# Dockerfile for building both x64 and arm64 on an old distro for maximum compatibility. + +# ubuntu20 is dead but debian11 is still supported for now +FROM debian:11 +ENV DEBIAN_FRONTEND=noninteractive + +RUN dpkg --add-architecture arm64 + +RUN apt-get update && apt-get install -y \ + build-essential python3 curl pkg-config \ + g++-aarch64-linux-gnu libglib2.0-dev:amd64 libglib2.0-dev:arm64 \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get update && apt-get install -y nodejs \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /src diff --git a/packages/libvesktop/binding.gyp b/packages/libvesktop/binding.gyp new file mode 100644 index 0000000..685aadf --- /dev/null +++ b/packages/libvesktop/binding.gyp @@ -0,0 +1,19 @@ +{ + "targets": [ + { + "target_name": "libvesktop", + "sources": [ "src/libvesktop.cc" ], + "include_dirs": [ + "=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@npmcli/agent@3.0.0': + resolution: {integrity: sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==} + engines: {node: ^18.17.0 || >=20.5.0} + + '@npmcli/fs@4.0.0': + resolution: {integrity: sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==} + engines: {node: ^18.17.0 || >=20.5.0} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + cacache@19.0.1: + resolution: {integrity: sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + exponential-backoff@3.1.2: + resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + make-fetch-happen@14.0.3: + resolution: {integrity: sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass-fetch@4.0.1: + resolution: {integrity: sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + node-addon-api@8.5.0: + resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + engines: {node: ^18 || ^20 || >= 21} + + node-gyp@11.4.2: + resolution: {integrity: sha512-3gD+6zsrLQH7DyYOUIutaauuXrcyxeTPyQuZQCQoNPZMHMMS5m4y0xclNpvYzoK3VNzuyxT6eF4mkIL4WSZ1eQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + p-map@7.0.3: + resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + engines: {node: '>=18'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + proc-log@5.0.0: + resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + ssri@12.0.0: + resolution: {integrity: sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + unique-filename@4.0.0: + resolution: {integrity: sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==} + engines: {node: ^18.17.0 || >=20.5.0} + + unique-slug@5.0.0: + resolution: {integrity: sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==} + engines: {node: ^18.17.0 || >=20.5.0} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + +snapshots: + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.2 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@npmcli/agent@3.0.0': + dependencies: + agent-base: 7.1.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 10.4.3 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + '@npmcli/fs@4.0.0': + dependencies: + semver: 7.7.2 + + '@pkgjs/parseargs@0.11.0': + optional: true + + abbrev@3.0.1: {} + + agent-base@7.1.4: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + balanced-match@1.0.2: {} + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + cacache@19.0.1: + dependencies: + '@npmcli/fs': 4.0.0 + fs-minipass: 3.0.3 + glob: 10.4.5 + lru-cache: 10.4.3 + minipass: 7.1.2 + minipass-collect: 2.0.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + p-map: 7.0.3 + ssri: 12.0.0 + tar: 7.5.1 + unique-filename: 4.0.0 + + chownr@3.0.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + eastasianwidth@0.2.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + env-paths@2.2.1: {} + + err-code@2.0.3: {} + + exponential-backoff@3.1.2: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fs-minipass@3.0.3: + dependencies: + minipass: 7.1.2 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + graceful-fs@4.2.11: {} + + http-cache-semantics@4.2.0: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + optional: true + + imurmurhash@0.1.4: {} + + ip-address@10.0.1: {} + + is-fullwidth-code-point@3.0.0: {} + + isexe@2.0.0: {} + + isexe@3.1.1: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + lru-cache@10.4.3: {} + + make-fetch-happen@14.0.3: + dependencies: + '@npmcli/agent': 3.0.0 + cacache: 19.0.1 + http-cache-semantics: 4.2.0 + minipass: 7.1.2 + minipass-fetch: 4.0.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 1.0.0 + proc-log: 5.0.0 + promise-retry: 2.0.1 + ssri: 12.0.0 + transitivePeerDependencies: + - supports-color + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass-collect@2.0.1: + dependencies: + minipass: 7.1.2 + + minipass-fetch@4.0.1: + dependencies: + minipass: 7.1.2 + minipass-sized: 1.0.3 + minizlib: 3.1.0 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@7.1.2: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.2 + + ms@2.1.3: {} + + negotiator@1.0.0: {} + + node-addon-api@8.5.0: {} + + node-gyp@11.4.2: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.2 + graceful-fs: 4.2.11 + make-fetch-happen: 14.0.3 + nopt: 8.1.0 + proc-log: 5.0.0 + semver: 7.7.2 + tar: 7.5.1 + tinyglobby: 0.2.15 + which: 5.0.0 + transitivePeerDependencies: + - supports-color + + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + + p-map@7.0.3: {} + + package-json-from-dist@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + picomatch@4.0.3: {} + + proc-log@5.0.0: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + retry@0.12.0: {} + + safer-buffer@2.1.2: + optional: true + + semver@7.7.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + smart-buffer@4.2.0: {} + + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.0.1 + smart-buffer: 4.2.0 + + ssri@12.0.0: + dependencies: + minipass: 7.1.2 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + + tar@7.5.1: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.1.0 + yallist: 5.0.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + unique-filename@4.0.0: + dependencies: + unique-slug: 5.0.0 + + unique-slug@5.0.0: + dependencies: + imurmurhash: 0.1.4 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + which@5.0.0: + dependencies: + isexe: 3.1.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.1.2 + + yallist@4.0.0: {} + + yallist@5.0.0: {} diff --git a/packages/libvesktop/prebuilds/vesktop-arm64.node b/packages/libvesktop/prebuilds/vesktop-arm64.node new file mode 100755 index 0000000000000000000000000000000000000000..ba301872cd1ca6d4e673f9973435c9e1b09d3219 GIT binary patch literal 55832 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

7D| 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 yKX^tH +#include +#include +#include +#include +#include +#include +#include + +template +struct GObjectDeleter +{ + void operator()(T *obj) const + { + if (obj) + g_object_unref(obj); + } +}; + +template +using GObjectPtr = std::unique_ptr>; + +struct GVariantDeleter +{ + void operator()(GVariant *variant) const + { + if (variant) + g_variant_unref(variant); + } +}; + +using GVariantPtr = std::unique_ptr; + +struct GErrorDeleter +{ + void operator()(GError *error) const + { + if (error) + g_error_free(error); + } +}; + +using GErrorPtr = std::unique_ptr; + +bool update_launcher_count(int count) +{ + GError *error = nullptr; + + const char *chromeDesktop = std::getenv("CHROME_DESKTOP"); + std::string desktop_id = std::string("application://") + (chromeDesktop ? chromeDesktop : "vesktop.desktop"); + + GObjectPtr bus(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error)); + if (!bus) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::update_launcher_count] Failed to connect to session bus: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return false; + } + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&builder, "{sv}", "count", g_variant_new_int64(count)); + g_variant_builder_add(&builder, "{sv}", "count-visible", g_variant_new_boolean(count != 0)); + + gboolean result = g_dbus_connection_emit_signal( + bus.get(), + nullptr, + "/", + "com.canonical.Unity.LauncherEntry", + "Update", + g_variant_new("(sa{sv})", desktop_id.c_str(), &builder), + &error); + + if (!result || error) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::update_launcher_count] Failed to emit Update signal: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return false; + } + + return true; +} + +std::optional get_accent_color() +{ + GError *error = nullptr; + + GObjectPtr bus(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error)); + if (!bus) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::get_accent_color] Failed to connect to session bus: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return std::nullopt; + } + + GVariantPtr reply(g_dbus_connection_call_sync( + bus.get(), + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Settings", + "Read", + g_variant_new("(ss)", "org.freedesktop.appearance", "accent-color"), + nullptr, + G_DBUS_CALL_FLAGS_NONE, + 5000, + nullptr, + &error)); + + if (!reply) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::get_accent_color] Failed to call Read: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return std::nullopt; + } + + GVariant *inner_raw = nullptr; + g_variant_get(reply.get(), "(v)", &inner_raw); + if (!inner_raw) + { + std::cerr << "[libvesktop::get_accent_color] Inner variant is null" << std::endl; + return std::nullopt; + } + + GVariantPtr inner(inner_raw); + + // Unwrap nested variants + while (g_variant_is_of_type(inner.get(), G_VARIANT_TYPE_VARIANT)) + { + GVariant *next = g_variant_get_variant(inner.get()); + inner.reset(next); + } + + if (!g_variant_is_of_type(inner.get(), G_VARIANT_TYPE_TUPLE) || + g_variant_n_children(inner.get()) < 3) + { + std::cerr << "[libvesktop::get_accent_color] Inner variant is not a tuple of 3 doubles" << std::endl; + return std::nullopt; + } + + double r = 0.0, g = 0.0, b = 0.0; + g_variant_get(inner.get(), "(ddd)", &r, &g, &b); + + bool discard = false; + auto toInt = [&discard](double v) -> int + { + if (!std::isfinite(v) || v < 0.0 || v > 1.0) + { + discard = true; + return 0; + } + + return static_cast(std::round(v * 255.0)); + }; + + int32_t rgb = (toInt(r) << 16) | (toInt(g) << 8) | toInt(b); + if (discard) + return std::nullopt; + + return rgb; +} + +bool request_background(bool autostart, const std::vector &commandline) +{ + GError *error = nullptr; + + GObjectPtr bus(g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error)); + if (!bus) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::request_background] Failed to connect to session bus: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return false; + } + + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + g_variant_builder_add(&builder, "{sv}", "autostart", g_variant_new_boolean(autostart)); + + if (!commandline.empty()) + { + GVariantBuilder cmd_builder; + g_variant_builder_init(&cmd_builder, G_VARIANT_TYPE("as")); + for (const auto &s : commandline) + g_variant_builder_add(&cmd_builder, "s", s.c_str()); + g_variant_builder_add(&builder, "{sv}", "commandline", g_variant_builder_end(&cmd_builder)); + } + + GVariantPtr reply(g_dbus_connection_call_sync( + bus.get(), + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Background", + "RequestBackground", + g_variant_new("(sa{sv})", "", &builder), + nullptr, + G_DBUS_CALL_FLAGS_NONE, + 5000, + nullptr, + &error)); + + if (!reply) + { + GErrorPtr error_ptr(error); + std::cerr << "[libvesktop::request_background] Failed to call RequestBackground: " + << (error_ptr ? error_ptr->message : "unknown error") << std::endl; + return false; + } + + return true; +} + +Napi::Value updateUnityLauncherCount(Napi::CallbackInfo const &info) +{ + if (info.Length() < 1 || !info[0].IsNumber()) + { + Napi::TypeError::New(info.Env(), "Expected (number)").ThrowAsJavaScriptException(); + return info.Env().Undefined(); + } + + int count = info[0].As().Int32Value(); + bool success = update_launcher_count(count); + return Napi::Boolean::New(info.Env(), success); +} + +Napi::Value getAccentColor(const Napi::CallbackInfo &info) +{ + auto color = get_accent_color(); + if (color) + return Napi::Number::New(info.Env(), *color); + return info.Env().Null(); +} + +Napi::Value RequestBackground(const Napi::CallbackInfo &info) +{ + Napi::Env env = info.Env(); + + if (info.Length() < 2 || !info[0].IsBoolean() || !info[1].IsArray()) + { + Napi::TypeError::New(env, "Expected (boolean, string[])").ThrowAsJavaScriptException(); + return env.Null(); + } + + bool autostart = info[0].As(); + Napi::Array arr = info[1].As(); + std::vector commandline; + for (uint32_t i = 0; i < arr.Length(); i++) + { + Napi::Value v = arr.Get(i); + if (v.IsString()) + commandline.push_back(v.As().Utf8Value()); + } + + bool ok = request_background(autostart, commandline); + return Napi::Boolean::New(env, ok); +} + +Napi::Object Init(Napi::Env env, Napi::Object exports) +{ + exports.Set("updateUnityLauncherCount", Napi::Function::New(env, updateUnityLauncherCount)); + exports.Set("getAccentColor", Napi::Function::New(env, getAccentColor)); + exports.Set("requestBackground", Napi::Function::New(env, RequestBackground)); + return exports; +} + +NODE_API_MODULE(libvesktop, Init) diff --git a/packages/libvesktop/test.js b/packages/libvesktop/test.js new file mode 100644 index 0000000..c2c12e6 --- /dev/null +++ b/packages/libvesktop/test.js @@ -0,0 +1,22 @@ +/** + * @type {typeof import(".")} + */ +const libVesktop = require("."); +const test = require("node:test"); +const assert = require("node:assert/strict"); + +test("getAccentColor should return a number", () => { + const color = libVesktop.getAccentColor(); + assert.strictEqual(typeof color, "number"); +}); + +test("updateUnityLauncherCount should return true (success)", () => { + assert.strictEqual(libVesktop.updateUnityLauncherCount(5), true); + assert.strictEqual(libVesktop.updateUnityLauncherCount(0), true); + assert.strictEqual(libVesktop.updateUnityLauncherCount(10), true); +}); + +test("requestBackground should return true (success)", () => { + assert.strictEqual(libVesktop.requestBackground(true, ["bash"]), true); + assert.strictEqual(libVesktop.requestBackground(false, []), true); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09cf8d2..73270b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: eslint-plugin-unused-imports: specifier: ^4.2.0 version: 4.2.0(@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0) + libvesktop: + specifier: link:packages/libvesktop + version: link:packages/libvesktop prettier: specifier: ^3.6.2 version: 3.6.2 diff --git a/scripts/build/build.mts b/scripts/build/build.mts index ee3f7ca..0f62ac6 100644 --- a/scripts/build/build.mts +++ b/scripts/build/build.mts @@ -25,6 +25,9 @@ const NodeCommonOpts: BuildOptions = { platform: "node", external: ["electron"], target: ["esnext"], + loader: { + ".node": "file" + }, define: { IS_DEV: JSON.stringify(isDev) } @@ -50,8 +53,29 @@ async function copyVenmic() { ]).catch(() => console.warn("Failed to copy venmic. Building without venmic support")); } +async function copyLibVesktop() { + if (process.platform !== "linux") return; + + try { + await copyFile( + "./packages/libvesktop/build/Release/vesktop.node", + `./static/dist/libvesktop-${process.arch}.node` + ); + console.log("Using local libvesktop build"); + } catch { + console.log( + "Using prebuilt libvesktop binaries. Run `pnpm buildLibVesktop` and build again to build from source - see README.md for more details" + ); + return Promise.all([ + copyFile("./packages/libvesktop/prebuilds/vesktop-x64.node", "./static/dist/libvesktop-x64.node"), + copyFile("./packages/libvesktop/prebuilds/vesktop-arm64.node", "./static/dist/libvesktop-arm64.node") + ]).catch(() => console.warn("Failed to copy libvesktop. Building without libvesktop support")); + } +} + await Promise.all([ copyVenmic(), + copyLibVesktop(), createContext({ ...NodeCommonOpts, entryPoints: ["src/main/index.ts"], diff --git a/src/main/appBadge.ts b/src/main/appBadge.ts index 969caf3..a6230f7 100644 --- a/src/main/appBadge.ts +++ b/src/main/appBadge.ts @@ -8,7 +8,9 @@ import { app, NativeImage, nativeImage } from "electron"; import { join } from "path"; import { BADGE_DIR } from "shared/paths"; +import { updateUnityLauncherCount } from "./dbus"; import { AppEvents } from "./events"; +import { mainWin } from "./mainWindow"; const imgCache = new Map(); function loadBadge(index: number) { @@ -33,7 +35,7 @@ export function setBadgeCount(count: number) { switch (process.platform) { case "linux": if (count === -1) count = 0; - app.setBadgeCount(count); + updateUnityLauncherCount(count); break; case "darwin": if (count === 0) { @@ -48,8 +50,6 @@ export function setBadgeCount(count: number) { lastIndex = index; - // circular import shenanigans - const { mainWin } = require("./mainWindow") as typeof import("./mainWindow"); mainWin.setOverlayIcon(index === null ? null : loadBadge(index), description); break; } diff --git a/src/main/autoStart.ts b/src/main/autoStart.ts index 1f4a955..cfb43e8 100644 --- a/src/main/autoStart.ts +++ b/src/main/autoStart.ts @@ -5,30 +5,32 @@ */ import { app } from "electron"; -import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from "fs"; +import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs"; import { join } from "path"; import { stripIndent } from "shared/utils/text"; +import { IS_FLATPAK } from "./constants"; +import { requestBackground } from "./dbus"; +import { Settings, State } from "./settings"; +import { escapeDesktopFileArgument } from "./utils/desktopFileEscape"; + interface AutoStart { isEnabled(): boolean; enable(): void; disable(): void; } -function makeAutoStartLinux(): AutoStart { +function getEscapedCommandLine() { + const args = process.argv.map(escapeDesktopFileArgument); + if (Settings.store.autoStartMinimized) args.push("--start-minimized"); + return args; +} + +function makeAutoStartLinuxDesktop(): AutoStart { const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config"); const dir = join(configDir, "autostart"); const file = join(dir, "vesktop.desktop"); - // IM STUPID - const legacyName = join(dir, "vencord.desktop"); - if (existsSync(legacyName)) renameSync(legacyName, file); - - // "Quoting must be done by enclosing the argument between double quotes and escaping the double quote character, - // backtick character ("`"), dollar sign ("$") and backslash character ("\") by preceding it with an additional backslash character" - // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables - const commandLine = process.argv.map(arg => '"' + arg.replace(/["$`\\]/g, "\\$&") + '"').join(" "); - return { isEnabled: () => existsSync(file), enable() { @@ -37,7 +39,7 @@ function makeAutoStartLinux(): AutoStart { Type=Application Name=Vesktop Comment=Vesktop autostart script - Exec=${commandLine} + Exec=${getEscapedCommandLine().join(" ")} StartupNotify=false Terminal=false Icon=vesktop @@ -50,10 +52,49 @@ function makeAutoStartLinux(): AutoStart { }; } +function makeAutoStartLinuxPortal() { + return { + isEnabled: () => State.store.linuxAutoStartEnabled === true, + enable() { + const success = requestBackground(true, getEscapedCommandLine()); + if (success) { + State.store.linuxAutoStartEnabled = true; + } + return success; + }, + disable() { + const success = requestBackground(false, []); + if (success) { + State.store.linuxAutoStartEnabled = false; + } + return success; + } + }; +} + const autoStartWindowsMac: AutoStart = { isEnabled: () => app.getLoginItemSettings().openAtLogin, - enable: () => app.setLoginItemSettings({ openAtLogin: true }), + enable: () => + app.setLoginItemSettings({ + openAtLogin: true, + args: Settings.store.autoStartMinimized ? ["--start-minimized"] : [] + }), disable: () => app.setLoginItemSettings({ openAtLogin: false }) }; -export const autoStart = process.platform === "linux" ? makeAutoStartLinux() : autoStartWindowsMac; +// The portal call uses the app id by default, which is org.chromium.Chromium, even in packaged Vesktop. +// This leads to an autostart entry named "Chromium" instead of "Vesktop". +// Thus, only use the portal inside Flatpak, where the app is actually correct. +// Maybe there is a way to fix it outside of flatpak, but I couldn't figure it out. +export const autoStart = + process.platform !== "linux" + ? autoStartWindowsMac + : IS_FLATPAK + ? makeAutoStartLinuxPortal() + : makeAutoStartLinuxDesktop(); + +Settings.addChangeListener("autoStartMinimized", () => { + if (!autoStart.isEnabled()) return; + + autoStart.enable(); +}); diff --git a/src/main/constants.ts b/src/main/constants.ts index dcfc8fc..10b6f66 100644 --- a/src/main/constants.ts +++ b/src/main/constants.ts @@ -20,7 +20,7 @@ export const DATA_DIR = mkdirSync(DATA_DIR, { recursive: true }); -const SESSION_DATA_DIR = join(DATA_DIR, "sessionData"); +export const SESSION_DATA_DIR = join(DATA_DIR, "sessionData"); app.setPath("sessionData", SESSION_DATA_DIR); export const VENCORD_SETTINGS_DIR = join(DATA_DIR, "settings"); @@ -28,12 +28,6 @@ export const VENCORD_QUICKCSS_FILE = join(VENCORD_SETTINGS_DIR, "quickCss.css"); export const VENCORD_SETTINGS_FILE = join(VENCORD_SETTINGS_DIR, "settings.json"); export const VENCORD_THEMES_DIR = join(DATA_DIR, "themes"); -// needs to be inline require because of circular dependency -// as otherwise "DATA_DIR" (which is used by ./settings) will be uninitialised -export const VENCORD_FILES_DIR = - (require("./settings") as typeof import("./settings")).State.store.vencordDir || - join(SESSION_DATA_DIR, "vencordFiles"); - export const USER_AGENT = `Vesktop/${app.getVersion()} (https://github.com/Vencord/Vesktop)`; // dimensions shamelessly stolen from Discord Desktop :3 @@ -57,3 +51,5 @@ export const enum MessageBoxChoice { Default, Cancel } + +export const IS_FLATPAK = process.env.FLATPAK_ID !== undefined; diff --git a/src/main/dbus.ts b/src/main/dbus.ts new file mode 100644 index 0000000..05b2578 --- /dev/null +++ b/src/main/dbus.ts @@ -0,0 +1,40 @@ +/* + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2025 Vendicated and Vesktop contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { app } from "electron"; +import { join } from "path"; +import { STATIC_DIR } from "shared/paths"; + +let libVesktop: typeof import("libvesktop") | null = null; + +function loadLibVesktop() { + try { + if (!libVesktop) { + libVesktop = require(join(STATIC_DIR, `dist/libvesktop-${process.arch}.node`)); + } + } catch (e) { + console.error("Failed to load libvesktop:", e); + } + + return libVesktop; +} + +export function getAccentColor() { + return loadLibVesktop()?.getAccentColor() ?? null; +} + +export function updateUnityLauncherCount(count: number) { + const libVesktop = loadLibVesktop(); + if (!libVesktop) { + return app.setBadgeCount(count); + } + + return libVesktop.updateUnityLauncherCount(count); +} + +export function requestBackground(autoStart: boolean, commandLine: string[]) { + return loadLibVesktop()?.requestBackground(autoStart, commandLine) ?? false; +} diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 94eb671..a17bc9c 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -28,13 +28,14 @@ import { debounce } from "shared/utils/debounce"; import { IpcEvents } from "../shared/IpcEvents"; import { setBadgeCount } from "./appBadge"; import { autoStart } from "./autoStart"; -import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants"; +import { VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants"; import { mainWin } from "./mainWindow"; import { Settings, State } from "./settings"; import { handle, handleSync } from "./utils/ipcWrappers"; import { PopoutWindows } from "./utils/popout"; import { isDeckGameMode, showGamePage } from "./utils/steamOS"; import { isValidVencordInstall } from "./utils/vencordLoader"; +import { VENCORD_FILES_DIR } from "./vencordFilesDir"; handleSync(IpcEvents.GET_VENCORD_PRELOAD_FILE, () => join(VENCORD_FILES_DIR, "vencordDesktopPreload.js")); handleSync(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, () => diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts index 063ab29..a514917 100644 --- a/src/main/mainWindow.ts +++ b/src/main/mainWindow.ts @@ -22,7 +22,7 @@ import type { SettingsStore } from "shared/utils/SettingsStore"; import { createAboutWindow } from "./about"; import { initArRPC } from "./arrpc"; -import { BrowserUserAgent, DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH, VENCORD_FILES_DIR } from "./constants"; +import { BrowserUserAgent, DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH } from "./constants"; import { AppEvents } from "./events"; import { darwinURL } from "./index"; import { sendRendererCommand } from "./ipcCommands"; @@ -33,6 +33,7 @@ import { clearData } from "./utils/clearData"; import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally"; import { applyDeckKeyboardFix, askToApplySteamLayout, isDeckGameMode } from "./utils/steamOS"; import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader"; +import { VENCORD_FILES_DIR } from "./vencordFilesDir"; let isQuitting = false; diff --git a/src/main/utils/desktopFileEscape.ts b/src/main/utils/desktopFileEscape.ts new file mode 100644 index 0000000..d41265b --- /dev/null +++ b/src/main/utils/desktopFileEscape.ts @@ -0,0 +1,56 @@ +/* + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2025 Vendicated and Vesktop contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +// https://specifications.freedesktop.org/desktop-entry-spec/latest/exec-variables.html + +// "If an argument contains a reserved character the argument must be quoted." +const desktopFileReservedChars = new Set([ + " ", + "\t", + "\n", + '"', + "'", + "\\", + ">", + "<", + "~", + "|", + "&", + ";", + "$", + "*", + "?", + "#", + "(", + ")", + "`" +]); + +export function escapeDesktopFileArgument(arg: string) { + let needsQuoting = false; + let out = ""; + + for (const c of arg) { + if (desktopFileReservedChars.has(c)) { + // "Quoting must be done by enclosing the argument between double quotes" + needsQuoting = true; + // "and escaping the double quote character, backtick character ("`"), dollar sign ("$") + // and backslash character ("\") by preceding it with an additional backslash character" + if (c === '"' || c === "`" || c === "$" || c === "\\") { + out += "\\"; + } + } + + // "Literal percentage characters must be escaped as %%" + if (c === "%") { + out += "%%"; + } else { + out += c; + } + } + + return needsQuoting ? `"${out}"` : out; +} diff --git a/src/main/utils/vencordLoader.ts b/src/main/utils/vencordLoader.ts index 85b6112..25748b3 100644 --- a/src/main/utils/vencordLoader.ts +++ b/src/main/utils/vencordLoader.ts @@ -6,9 +6,10 @@ import { mkdirSync } from "fs"; import { access, constants as FsConstants, writeFile } from "fs/promises"; +import { VENCORD_FILES_DIR } from "main/vencordFilesDir"; import { join } from "path"; -import { USER_AGENT, VENCORD_FILES_DIR } from "../constants"; +import { USER_AGENT } from "../constants"; import { downloadFile, fetchie } from "./http"; const API_BASE = "https://api.github.com"; diff --git a/src/main/vencordFilesDir.ts b/src/main/vencordFilesDir.ts new file mode 100644 index 0000000..8ef9ab8 --- /dev/null +++ b/src/main/vencordFilesDir.ts @@ -0,0 +1,13 @@ +/* + * Vesktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2025 Vendicated and Vesktop contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { join } from "path"; + +import { SESSION_DATA_DIR } from "./constants"; +import { State } from "./settings"; + +// this is in a separate file to avoid circular dependencies +export const VENCORD_FILES_DIR = State.store.vencordDir || join(SESSION_DATA_DIR, "vencordFiles"); diff --git a/src/renderer/components/settings/AutoStartToggle.tsx b/src/renderer/components/settings/AutoStartToggle.tsx index 1563ca3..d99f2cd 100644 --- a/src/renderer/components/settings/AutoStartToggle.tsx +++ b/src/renderer/components/settings/AutoStartToggle.tsx @@ -9,18 +9,28 @@ import { useState } from "@vencord/types/webpack/common"; import { SettingsComponent } from "./Settings"; import { VesktopSettingsSwitch } from "./VesktopSettingsSwitch"; -export const AutoStartToggle: SettingsComponent = () => { +export const AutoStartToggle: SettingsComponent = ({ settings }) => { const [autoStartEnabled, setAutoStartEnabled] = useState(VesktopNative.autostart.isEnabled()); return ( - { - await VesktopNative.autostart[v ? "enable" : "disable"](); - setAutoStartEnabled(v); - }} - /> + <> + { + await VesktopNative.autostart[v ? "enable" : "disable"](); + setAutoStartEnabled(v); + }} + /> + + (settings.autoStartMinimized = v)} + disabled={!autoStartEnabled} + /> + ); }; diff --git a/src/shared/settings.d.ts b/src/shared/settings.d.ts index 21c140a..5d3263c 100644 --- a/src/shared/settings.d.ts +++ b/src/shared/settings.d.ts @@ -11,6 +11,7 @@ export interface Settings { transparencyOption?: "none" | "mica" | "tabbed" | "acrylic"; tray?: boolean; minimizeToTray?: boolean; + autoStartMinimized?: boolean; openLinksWithElectron?: boolean; staticTitle?: boolean; enableMenu?: boolean; @@ -54,6 +55,7 @@ export interface State { firstLaunch?: boolean; steamOSLayoutVersion?: number; + linuxAutoStartEnabled?: boolean; vencordDir?: string; } diff --git a/static/views/about.html b/static/views/about.html index 38ea463..933e31a 100644 --- a/static/views/about.html +++ b/static/views/about.html @@ -28,10 +28,10 @@

Links

@@ -104,4 +103,4 @@ } walk(document.body); - + \ No newline at end of file diff --git a/static/views/updater.html b/static/views/updater.html deleted file mode 100644 index 7eaba43..0000000 --- a/static/views/updater.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - -
-
-

Update Available

-

There's a new update for Vesktop! Update now to get new fixes and features!

-

- Current: -
- Latest: -

- -

Changelog

-

Loading...

-
- -
- - -
- - -
-
-
- - - - -