mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-03-26 03:07:30 +08:00
Compare commits
15 Commits
v1.2.1
...
25e9958a69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25e9958a69 | ||
|
|
410ea8b96b | ||
|
|
e656664cad | ||
|
|
0e6cee0961 | ||
|
|
42506b8c1d | ||
|
|
e35365d162 | ||
|
|
bf1c0f796d | ||
|
|
547532b28c | ||
|
|
a91e23abf6 | ||
|
|
2b324f636b | ||
|
|
103b8372e4 | ||
|
|
f7f1724bf1 | ||
|
|
5d70e11f17 | ||
|
|
fb7ae90d46 | ||
|
|
957792a7a0 |
118
.github/workflows/build.yml
vendored
118
.github/workflows/build.yml
vendored
@@ -15,82 +15,28 @@ env:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# Linux amd64
|
build-linux:
|
||||||
build-linux-amd64:
|
name: Build Linux (${{ matrix.arch }})
|
||||||
name: Build on Ubuntu 22.04 amd64
|
runs-on: ${{ matrix.runner }}
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
container:
|
|
||||||
image: crossdesk/ubuntu20.04:latest
|
|
||||||
options: --user root
|
|
||||||
steps:
|
|
||||||
- name: Extract version number
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
VERSION="${GITHUB_REF##*/}"
|
|
||||||
VERSION_NUM="${VERSION#v}"
|
|
||||||
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Set legal Debian version
|
|
||||||
shell: bash
|
|
||||||
id: set_deb_version
|
|
||||||
run: |
|
|
||||||
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
|
||||||
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
|
|
||||||
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
|
|
||||||
LEGAL_VERSION="v0.0.0-${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
|
||||||
else
|
|
||||||
LEGAL_VERSION="v${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
|
||||||
fi
|
|
||||||
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
|
|
||||||
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Build CrossDesk
|
|
||||||
env:
|
|
||||||
CUDA_PATH: /usr/local/cuda
|
|
||||||
XMAKE_GLOBALDIR: /data
|
|
||||||
run: |
|
|
||||||
ls -la $XMAKE_GLOBALDIR
|
|
||||||
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --USE_CUDA=true --root -y
|
|
||||||
xmake b -vy --root crossdesk
|
|
||||||
|
|
||||||
- name: Decode and save certificate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p certs
|
|
||||||
echo "${{ secrets.CROSSDESK_CERT_BASE64 }}" | base64 --decode > certs/crossdesk.cn_root.crt
|
|
||||||
|
|
||||||
- name: Package
|
|
||||||
run: |
|
|
||||||
chmod +x ./scripts/linux/pkg_amd64.sh
|
|
||||||
./scripts/linux/pkg_amd64.sh ${LEGAL_VERSION}
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: crossdesk-linux-amd64-${{ env.LEGAL_VERSION }}
|
|
||||||
path: ${{ github.workspace }}/crossdesk-linux-amd64-${{ env.LEGAL_VERSION }}.deb
|
|
||||||
|
|
||||||
# Linux arm64
|
|
||||||
build-linux-arm64:
|
|
||||||
name: Build on Ubuntu 22.04 arm64
|
|
||||||
runs-on: ubuntu-22.04-arm
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- arch: amd64
|
||||||
|
runner: ubuntu-22.04
|
||||||
|
image: crossdesk/ubuntu20.04:latest
|
||||||
|
package_script: ./scripts/linux/pkg_amd64.sh
|
||||||
|
|
||||||
- arch: arm64
|
- arch: arm64
|
||||||
|
runner: ubuntu-22.04-arm
|
||||||
image: crossdesk/ubuntu20.04-arm64v8:latest
|
image: crossdesk/ubuntu20.04-arm64v8:latest
|
||||||
package_script: ./scripts/linux/pkg_arm64.sh
|
package_script: ./scripts/linux/pkg_arm64.sh
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: ${{ matrix.image }}
|
image: ${{ matrix.image }}
|
||||||
options: --user root
|
options: --user root
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Extract version number
|
- name: Extract version number
|
||||||
id: version
|
|
||||||
run: |
|
run: |
|
||||||
VERSION="${GITHUB_REF##*/}"
|
VERSION="${GITHUB_REF##*/}"
|
||||||
VERSION_NUM="${VERSION#v}"
|
VERSION_NUM="${VERSION#v}"
|
||||||
@@ -98,15 +44,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Set legal Debian version
|
- name: Set legal Debian version
|
||||||
shell: bash
|
shell: bash
|
||||||
id: set_deb_version
|
|
||||||
run: |
|
run: |
|
||||||
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
|
||||||
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
|
BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)
|
||||||
|
|
||||||
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
|
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
|
||||||
LEGAL_VERSION="v0.0.0-${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
LEGAL_VERSION="v0.0.0-${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
||||||
else
|
else
|
||||||
LEGAL_VERSION="v${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
LEGAL_VERSION="v${VERSION_NUM}-${BUILD_DATE}-${SHORT_SHA}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
|
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
|
||||||
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_ENV
|
echo "BUILD_DATE=${BUILD_DATE}" >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -123,12 +70,6 @@ jobs:
|
|||||||
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --USE_CUDA=true --root -y
|
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --USE_CUDA=true --root -y
|
||||||
xmake b -vy --root crossdesk
|
xmake b -vy --root crossdesk
|
||||||
|
|
||||||
- name: Decode and save certificate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p certs
|
|
||||||
echo "${{ secrets.CROSSDESK_CERT_BASE64 }}" | base64 --decode > certs/crossdesk.cn_root.crt
|
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
chmod +x ${{ matrix.package_script }}
|
chmod +x ${{ matrix.package_script }}
|
||||||
@@ -192,12 +133,6 @@ jobs:
|
|||||||
xmake f --CROSSDESK_VERSION=${VERSION_NUM} --USE_CUDA=true -y
|
xmake f --CROSSDESK_VERSION=${VERSION_NUM} --USE_CUDA=true -y
|
||||||
xmake b -vy crossdesk
|
xmake b -vy crossdesk
|
||||||
|
|
||||||
- name: Decode and save certificate
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p certs
|
|
||||||
echo "${{ secrets.CROSSDESK_CERT_BASE64 }}" | base64 --decode > certs/crossdesk.cn_root.crt
|
|
||||||
|
|
||||||
- name: Package CrossDesk app
|
- name: Package CrossDesk app
|
||||||
run: |
|
run: |
|
||||||
chmod +x ${{ matrix.package_script }}
|
chmod +x ${{ matrix.package_script }}
|
||||||
@@ -301,29 +236,37 @@ jobs:
|
|||||||
xmake f --CROSSDESK_VERSION=${{ env.VERSION_NUM }} --USE_CUDA=true -y
|
xmake f --CROSSDESK_VERSION=${{ env.VERSION_NUM }} --USE_CUDA=true -y
|
||||||
xmake b -vy crossdesk
|
xmake b -vy crossdesk
|
||||||
|
|
||||||
- name: Decode and save certificate
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
New-Item -ItemType Directory -Force -Path certs
|
|
||||||
[System.IO.File]::WriteAllBytes('certs\crossdesk.cn_root.crt', [Convert]::FromBase64String('${{ secrets.CROSSDESK_CERT_BASE64 }}'))
|
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
cd "${{ github.workspace }}\scripts\windows"
|
cd "${{ github.workspace }}\scripts\windows"
|
||||||
makensis /DVERSION=$env:VERSION_NUM nsis_script.nsi
|
makensis /DVERSION=$env:VERSION_NUM nsis_script.nsi
|
||||||
|
|
||||||
|
- name: Package Portable
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$portableDir = "${{ github.workspace }}\portable"
|
||||||
|
New-Item -ItemType Directory -Force -Path $portableDir
|
||||||
|
Copy-Item "${{ github.workspace }}\build\windows\x64\release\crossdesk.exe" "$portableDir\CrossDesk.exe"
|
||||||
|
Compress-Archive -Path "$portableDir\*" -DestinationPath "${{ github.workspace }}\crossdesk-win-x64-portable-${{ env.VERSION_NUM }}.zip"
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: crossdesk-win-x64-${{ env.VERSION_NUM }}
|
name: crossdesk-win-x64-${{ env.VERSION_NUM }}
|
||||||
path: ${{ github.workspace }}/scripts/windows/crossdesk-win-x64-${{ env.VERSION_NUM }}.exe
|
path: ${{ github.workspace }}/scripts/windows/crossdesk-win-x64-${{ env.VERSION_NUM }}.exe
|
||||||
|
|
||||||
|
- name: Upload portable artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: crossdesk-win-x64-portable-${{ env.VERSION_NUM }}
|
||||||
|
path: ${{ github.workspace }}/crossdesk-win-x64-portable-${{ env.VERSION_NUM }}.zip
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Publish Release
|
name: Publish Release
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
needs:
|
needs:
|
||||||
[build-linux-amd64, build-linux-arm64, build-macos, build-windows-x64]
|
[build-linux, build-macos, build-windows-x64]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -359,6 +302,7 @@ jobs:
|
|||||||
cp artifacts/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
|
cp artifacts/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-amd64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
|
||||||
cp artifacts/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
|
cp artifacts/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-linux-arm64-${{ steps.version.outputs.VERSION_WITH_V }}.deb
|
||||||
cp artifacts/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe
|
cp artifacts/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe
|
||||||
|
cp artifacts/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}/* release/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip
|
||||||
|
|
||||||
- name: List release files
|
- name: List release files
|
||||||
run: ls -lh release/
|
run: ls -lh release/
|
||||||
@@ -416,6 +360,10 @@ jobs:
|
|||||||
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe",
|
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe",
|
||||||
"filename": "crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe"
|
"filename": "crossdesk-win-x64-${{ steps.version.outputs.VERSION_WITH_V }}.exe"
|
||||||
},
|
},
|
||||||
|
"windows-x64-portable": {
|
||||||
|
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip",
|
||||||
|
"filename": "crossdesk-win-x64-portable-${{ steps.version.outputs.VERSION_WITH_V }}.zip"
|
||||||
|
},
|
||||||
"macos-x64": {
|
"macos-x64": {
|
||||||
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg",
|
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg",
|
||||||
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg"
|
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.VERSION_WITH_V }}.pkg"
|
||||||
|
|||||||
24
.github/workflows/update-version-json.yml
vendored
24
.github/workflows/update-version-json.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
update-version-json:
|
update-version-json:
|
||||||
name: Update version.json with release information
|
name: Update version.json with release information
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
VERSION_ONLY="${TAG_NAME#v}"
|
VERSION_ONLY="${TAG_NAME#v}"
|
||||||
echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_OUTPUT
|
echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_OUTPUT
|
||||||
echo "VERSION_ONLY=${VERSION_ONLY}" >> $GITHUB_OUTPUT
|
echo "VERSION_ONLY=${VERSION_ONLY}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
# Extract date from tag if available (format: v1.2.3-20251113-abc)
|
# Extract date from tag if available (format: v1.2.3-20251113-abc)
|
||||||
if [[ "${TAG_NAME}" =~ -([0-9]{8})- ]]; then
|
if [[ "${TAG_NAME}" =~ -([0-9]{8})- ]]; then
|
||||||
DATE_STR="${BASH_REMATCH[1]}"
|
DATE_STR="${BASH_REMATCH[1]}"
|
||||||
@@ -45,7 +45,7 @@ jobs:
|
|||||||
# Use jq to properly escape JSON
|
# Use jq to properly escape JSON
|
||||||
RELEASE_BODY="${{ github.event.release.body }}"
|
RELEASE_BODY="${{ github.event.release.body }}"
|
||||||
RELEASE_NAME="${{ github.event.release.name }}"
|
RELEASE_NAME="${{ github.event.release.name }}"
|
||||||
|
|
||||||
# Handle empty values
|
# Handle empty values
|
||||||
if [ -z "$RELEASE_BODY" ]; then
|
if [ -z "$RELEASE_BODY" ]; then
|
||||||
RELEASE_BODY=""
|
RELEASE_BODY=""
|
||||||
@@ -53,15 +53,15 @@ jobs:
|
|||||||
if [ -z "$RELEASE_NAME" ]; then
|
if [ -z "$RELEASE_NAME" ]; then
|
||||||
RELEASE_NAME=""
|
RELEASE_NAME=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Save to temporary files for proper handling
|
# Save to temporary files for proper handling
|
||||||
echo -n "$RELEASE_BODY" > /tmp/release_body.txt
|
echo -n "$RELEASE_BODY" > /tmp/release_body.txt
|
||||||
echo -n "$RELEASE_NAME" > /tmp/release_name.txt
|
echo -n "$RELEASE_NAME" > /tmp/release_name.txt
|
||||||
|
|
||||||
# Use jq to escape JSON strings
|
# Use jq to escape JSON strings
|
||||||
RELEASE_BODY_JSON=$(jq -Rs . < /tmp/release_body.txt)
|
RELEASE_BODY_JSON=$(jq -Rs . < /tmp/release_body.txt)
|
||||||
RELEASE_NAME_JSON=$(jq -Rs . < /tmp/release_name.txt)
|
RELEASE_NAME_JSON=$(jq -Rs . < /tmp/release_name.txt)
|
||||||
|
|
||||||
echo "RELEASE_BODY=${RELEASE_BODY_JSON}" >> $GITHUB_OUTPUT
|
echo "RELEASE_BODY=${RELEASE_BODY_JSON}" >> $GITHUB_OUTPUT
|
||||||
echo "RELEASE_NAME=${RELEASE_NAME_JSON}" >> $GITHUB_OUTPUT
|
echo "RELEASE_NAME=${RELEASE_NAME_JSON}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ jobs:
|
|||||||
else
|
else
|
||||||
DOWNLOADS_JSON=""
|
DOWNLOADS_JSON=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If downloads is empty, use default structure
|
# If downloads is empty, use default structure
|
||||||
if [ -z "$DOWNLOADS_JSON" ]; then
|
if [ -z "$DOWNLOADS_JSON" ]; then
|
||||||
DOWNLOADS_JSON=$(cat << DOWNLOADS_EOF
|
DOWNLOADS_JSON=$(cat << DOWNLOADS_EOF
|
||||||
@@ -94,6 +94,10 @@ jobs:
|
|||||||
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe",
|
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe",
|
||||||
"filename": "crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe"
|
"filename": "crossdesk-win-x64-${{ steps.version.outputs.TAG_NAME }}.exe"
|
||||||
},
|
},
|
||||||
|
"windows-x64-portable": {
|
||||||
|
"url": "https://downloads.crossdesk.cn/crossdesk-win-x64-portable-${{ steps.version.outputs.TAG_NAME }}.zip",
|
||||||
|
"filename": "crossdesk-win-x64-portable-${{ steps.version.outputs.TAG_NAME }}.zip"
|
||||||
|
},
|
||||||
"macos-x64": {
|
"macos-x64": {
|
||||||
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg",
|
"url": "https://downloads.crossdesk.cn/crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg",
|
||||||
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg"
|
"filename": "crossdesk-macos-x64-${{ steps.version.outputs.TAG_NAME }}.pkg"
|
||||||
@@ -114,7 +118,7 @@ jobs:
|
|||||||
DOWNLOADS_EOF
|
DOWNLOADS_EOF
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate version.json using cat and heredoc
|
# Generate version.json using cat and heredoc
|
||||||
cat > version.json << EOF
|
cat > version.json << EOF
|
||||||
{
|
{
|
||||||
@@ -126,7 +130,7 @@ jobs:
|
|||||||
"downloads": ${DOWNLOADS_JSON}
|
"downloads": ${DOWNLOADS_JSON}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat version.json
|
cat version.json
|
||||||
|
|
||||||
- name: Upload version.json to server
|
- name: Upload version.json to server
|
||||||
@@ -137,4 +141,4 @@ jobs:
|
|||||||
remote_path: /var/www/html/version/
|
remote_path: /var/www/html/version/
|
||||||
remote_host: ${{ secrets.SERVER_HOST }}
|
remote_host: ${{ secrets.SERVER_HOST }}
|
||||||
remote_user: ${{ secrets.SERVER_USER }}
|
remote_user: ${{ secrets.SERVER_USER }}
|
||||||
remote_key: ${{ secrets.SERVER_KEY }}
|
remote_key: ${{ secrets.SERVER_KEY }}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
# Xmake cache
|
# Xmake cache
|
||||||
.xmake/
|
.xmake/
|
||||||
build/
|
build/
|
||||||
certs/
|
|
||||||
|
|
||||||
# MacOS Cache
|
# MacOS Cache
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
30
README.md
30
README.md
@@ -214,7 +214,7 @@ sudo docker run -d \
|
|||||||
**注意**:
|
**注意**:
|
||||||
- **服务器需开放端口:COTURN_PORT/udp,COTURN_PORT/tcp,MIN_PORT-MAX_PORT/udp,CROSSDESK_SERVER_PORT/tcp。**
|
- **服务器需开放端口:COTURN_PORT/udp,COTURN_PORT/tcp,MIN_PORT-MAX_PORT/udp,CROSSDESK_SERVER_PORT/tcp。**
|
||||||
- 如果不挂载 volume,容器删除后数据会丢失
|
- 如果不挂载 volume,容器删除后数据会丢失
|
||||||
- 证书文件会在首次启动时自动生成并持久化到宿主机的 `/var/lib/crossdesk/certs` 路径下
|
- 证书文件会在首次启动时自动生成并持久化到宿主机的 `/var/lib/crossdesk/certs` 路径下。由于默认使用的是自签证书,无法保障安全性,建议在云服务商申请正式证书放到该目录下并重启服务。
|
||||||
- 数据库文件会自动创建并持久化到宿主机的 `/var/lib/crossdesk/db/crossdesk-server.db` 路径下
|
- 数据库文件会自动创建并持久化到宿主机的 `/var/lib/crossdesk/db/crossdesk-server.db` 路径下
|
||||||
- 日志文件会自动创建并持久化到宿主机的 `/var/log/crossdesk/` 路径下
|
- 日志文件会自动创建并持久化到宿主机的 `/var/log/crossdesk/` 路径下
|
||||||
|
|
||||||
@@ -232,16 +232,30 @@ sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
|
|||||||
|
|
||||||
### 客户端
|
### 客户端
|
||||||
1. 点击右上角设置进入设置页面。<br><br>
|
1. 点击右上角设置进入设置页面。<br><br>
|
||||||
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br>
|
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br>
|
||||||
|
|
||||||
2. 点击点击`自托管服务器配置`按钮。<br><br>
|
2. 点击`自托管服务器配置`按钮。<br><br>
|
||||||
<img width="600" height="140" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br><br>
|
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br>
|
||||||
|
|
||||||
3. 输入`服务器地址`(**EXTERNAL_IP**)、`信令服务端口`(**CROSSDESK_SERVER_PORT**)、`中继服务端口`(**COTURN_PORT**)。<br><br>
|
3. 输入`服务器地址`(**EXTERNAL_IP**)、`信令服务端口`(**CROSSDESK_SERVER_PORT**)、`中继服务端口`(**COTURN_PORT**),点击确认按钮。
|
||||||
<img width="600" height="200" alt="image" src="https://github.com/user-attachments/assets/9a32ddd5-37f8-4bee-9a51-eae295820f9a" /><br><br>
|
|
||||||
|
4. 勾选`自托管服务器配置`选项,点击确认按钮保存设置。如果服务端使用的是正式证书,则到此步骤为止,客户端即可显示已连接服务器。
|
||||||
|
|
||||||
4. 后续如果自托管服务器被重置或因其他原因导致证书更换,可以点击`重置证书指纹`按钮重置客户端保存的证书指纹。<br><br>
|
5. 如果使用默认证书(正式证书忽略此步骤),则需要将服务端`/var/lib/crossdesk/certs/`目录下的`api.crossdesk.cn_root.crt`自签根证书下载到运行客户端的机器,并执行下述命令安装证书:
|
||||||
<img width="600" height="200" alt="image" src="https://github.com/user-attachments/assets/d9e423ab-0c2b-4fab-b132-4dc27462d704" /><br><br>
|
|
||||||
|
Windows 平台使用**管理员权限**打开 PowerShell 执行
|
||||||
|
```
|
||||||
|
certutil -addstore "Root" "C:\path\to\api.crossdesk.cn_root.crt"
|
||||||
|
```
|
||||||
|
Linux
|
||||||
|
```
|
||||||
|
sudo cp /path/to/api.crossdesk.cn_root.crt /usr/local/share/ca-certificates/api.crossdesk.cn_root.crt
|
||||||
|
sudo update-ca-certificates
|
||||||
|
```
|
||||||
|
macOS
|
||||||
|
```
|
||||||
|
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/api.crossdesk.cn_root.crt
|
||||||
|
```
|
||||||
|
|
||||||
### Web 客户端
|
### Web 客户端
|
||||||
详情见项目 [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
|
详情见项目 [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
|
||||||
|
|||||||
29
README_EN.md
29
README_EN.md
@@ -222,7 +222,7 @@ sudo docker run -d \
|
|||||||
**Notes**
|
**Notes**
|
||||||
- **The server must open the following ports: COTURN_PORT/udp, COTURN_PORT/tcp, MIN_PORT–MAX_PORT/udp, and CROSSDESK_SERVER_PORT/tcp.**
|
- **The server must open the following ports: COTURN_PORT/udp, COTURN_PORT/tcp, MIN_PORT–MAX_PORT/udp, and CROSSDESK_SERVER_PORT/tcp.**
|
||||||
- If you don’t mount volumes, all data will be lost when the container is removed.
|
- If you don’t mount volumes, all data will be lost when the container is removed.
|
||||||
- Certificate files will be automatically generated on first startup and persisted to the host at `/var/lib/crossdesk/certs`.
|
- Certificate files will be automatically generated on first startup and persisted to the host at `/var/lib/crossdesk/certs`.As the default certificates are self-signed and cannot guarantee security, it is strongly recommended to apply for a trusted certificate from a cloud provider, deploy it to this directory, and restart the service.
|
||||||
- The database file will be automatically created and stored at `/var/lib/crossdesk/db/crossdesk-server.db`.
|
- The database file will be automatically created and stored at `/var/lib/crossdesk/db/crossdesk-server.db`.
|
||||||
- Log files will be created and stored at `/var/log/crossdesk/`.
|
- Log files will be created and stored at `/var/log/crossdesk/`.
|
||||||
|
|
||||||
@@ -243,16 +243,31 @@ Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/y
|
|||||||
|
|
||||||
### Client Side
|
### Client Side
|
||||||
1. Click the settings icon in the top-right corner to enter the settings page.<br><br>
|
1. Click the settings icon in the top-right corner to enter the settings page.<br><br>
|
||||||
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br>
|
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br>
|
||||||
|
|
||||||
2. Click `Self-Hosted Server Configuration` button.<br><br>
|
2. Click `Self-Hosted Server Configuration` button.<br><br>
|
||||||
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br><br>
|
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/24c761a3-1985-4d7e-84be-787383c2afb8" /><br>
|
||||||
|
|
||||||
3. Enter the `Server Address` (**EXTERNAL_IP**), `Signaling Service Port` (**CROSSDESK_SERVER_PORT**), and `Relay Service Port` (**COTURN_PORT**).<br><br>
|
3. Enter the `Server Address` (**EXTERNAL_IP**), `Signaling Service Port` (**CROSSDESK_SERVER_PORT**), and `Relay Service Port` (**COTURN_PORT**) and click OK button.
|
||||||
<img width="600" height="200" alt="image" src="https://github.com/user-attachments/assets/9a32ddd5-37f8-4bee-9a51-eae295820f9a" /><br><br>
|
|
||||||
|
4. Check the `Self-hosted server configuration` option and click the OK button to save the settings. If the server is using a valid (official) certificate, the process ends here and the client will show that it is connected to the server.
|
||||||
|
|
||||||
|
5. If the default certificate is used (skip this step if an official certificate is used), download the self-signed root certificate `api.crossdesk.cn_root.crt` from the server directory /var/lib/crossdesk/certs/ to the machine running the client, and install the certificate by executing the following command:
|
||||||
|
|
||||||
|
On Windows, open PowerShell with **administrator privileges** and execute:
|
||||||
|
```
|
||||||
|
certutil -addstore "Root" "C:\path\to\api.crossdesk.cn_root.crt"
|
||||||
|
```
|
||||||
|
Linux
|
||||||
|
```
|
||||||
|
sudo cp /path/to/api.crossdesk.cn_root.crt /usr/local/share/ca-certificates/api.crossdesk.cn_root.crt
|
||||||
|
sudo update-ca-certificates
|
||||||
|
```
|
||||||
|
macOS
|
||||||
|
```
|
||||||
|
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/api.crossdesk.cn_root.crt
|
||||||
|
```
|
||||||
|
|
||||||
4. If the self-hosted server is later reset or the certificate is replaced for any reason, you can click the `Reset Certificate Fingerprint` button to clear the certificate fingerprint saved on the client.<br><br>
|
|
||||||
<img width="600" height="200" alt="image" src="https://github.com/user-attachments/assets/d9e423ab-0c2b-4fab-b132-4dc27462d704" /><br><br>
|
|
||||||
|
|
||||||
### Web Client
|
### Web Client
|
||||||
See [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
|
See [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
|
||||||
|
|||||||
@@ -15,21 +15,18 @@ DEB_VERSION="${APP_VERSION#v}"
|
|||||||
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
|
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
|
||||||
DEBIAN_DIR="$DEB_DIR/DEBIAN"
|
DEBIAN_DIR="$DEB_DIR/DEBIAN"
|
||||||
BIN_DIR="$DEB_DIR/usr/bin"
|
BIN_DIR="$DEB_DIR/usr/bin"
|
||||||
CERT_SRC_DIR="$DEB_DIR/opt/$PKG_NAME/certs"
|
|
||||||
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
|
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
|
||||||
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
|
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
|
||||||
|
|
||||||
rm -rf "$DEB_DIR"
|
rm -rf "$DEB_DIR"
|
||||||
|
|
||||||
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$CERT_SRC_DIR" "$DESKTOP_DIR"
|
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$DESKTOP_DIR"
|
||||||
|
|
||||||
cp build/linux/x86_64/release/crossdesk "$BIN_DIR/$PKG_NAME"
|
cp build/linux/x86_64/release/crossdesk "$BIN_DIR/$PKG_NAME"
|
||||||
chmod +x "$BIN_DIR/$PKG_NAME"
|
chmod +x "$BIN_DIR/$PKG_NAME"
|
||||||
|
|
||||||
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
|
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
|
||||||
|
|
||||||
cp certs/crossdesk.cn_root.crt "$CERT_SRC_DIR/crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
for size in 16 24 32 48 64 96 128 256; do
|
for size in 16 24 32 48 64 96 128 256; do
|
||||||
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
|
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
|
||||||
cp "icons/linux/crossdesk_${size}x${size}.png" \
|
cp "icons/linux/crossdesk_${size}x${size}.png" \
|
||||||
@@ -71,7 +68,6 @@ if [ "\$1" = "remove" ] || [ "\$1" = "purge" ]; then
|
|||||||
rm -f /usr/bin/$PKG_NAME || true
|
rm -f /usr/bin/$PKG_NAME || true
|
||||||
rm -f /usr/bin/$APP_NAME || true
|
rm -f /usr/bin/$APP_NAME || true
|
||||||
rm -f /usr/share/applications/$PKG_NAME.desktop || true
|
rm -f /usr/share/applications/$PKG_NAME.desktop || true
|
||||||
rm -rf /opt/$PKG_NAME/certs || true
|
|
||||||
for size in 16 24 32 48 64 96 128 256; do
|
for size in 16 24 32 48 64 96 128 256; do
|
||||||
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
|
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
|
||||||
done
|
done
|
||||||
@@ -85,32 +81,9 @@ cat > "$DEBIAN_DIR/postinst" << 'EOF'
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
CERT_SRC="/opt/crossdesk/certs"
|
|
||||||
CERT_FILE="crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
for user_home in /home/*; do
|
|
||||||
[ -d "$user_home" ] || continue
|
|
||||||
username=$(basename "$user_home")
|
|
||||||
config_dir="$user_home/.config/CrossDesk/certs"
|
|
||||||
target="$config_dir/$CERT_FILE"
|
|
||||||
|
|
||||||
if [ ! -f "$target" ]; then
|
|
||||||
mkdir -p "$config_dir" || true
|
|
||||||
cp "$CERT_SRC/$CERT_FILE" "$target" || true
|
|
||||||
chown -R "$username:$username" "$user_home/.config/CrossDesk" || true
|
|
||||||
echo "✔ Installed cert for $username at $target"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -d "/root" ]; then
|
|
||||||
config_dir="/root/.config/CrossDesk/certs"
|
|
||||||
mkdir -p "$config_dir" || true
|
|
||||||
cp "$CERT_SRC/$CERT_FILE" "$config_dir/$CERT_FILE" || true
|
|
||||||
chown -R root:root /root/.config/CrossDesk || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x "$DEBIAN_DIR/postinst"
|
chmod +x "$DEBIAN_DIR/postinst"
|
||||||
|
|
||||||
dpkg-deb --build "$DEB_DIR"
|
dpkg-deb --build "$DEB_DIR"
|
||||||
|
|||||||
@@ -15,21 +15,18 @@ DEB_VERSION="${APP_VERSION#v}"
|
|||||||
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
|
DEB_DIR="${PKG_NAME}-${DEB_VERSION}"
|
||||||
DEBIAN_DIR="$DEB_DIR/DEBIAN"
|
DEBIAN_DIR="$DEB_DIR/DEBIAN"
|
||||||
BIN_DIR="$DEB_DIR/usr/bin"
|
BIN_DIR="$DEB_DIR/usr/bin"
|
||||||
CERT_SRC_DIR="$DEB_DIR/opt/$PKG_NAME/certs"
|
|
||||||
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
|
ICON_BASE_DIR="$DEB_DIR/usr/share/icons/hicolor"
|
||||||
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
|
DESKTOP_DIR="$DEB_DIR/usr/share/applications"
|
||||||
|
|
||||||
rm -rf "$DEB_DIR"
|
rm -rf "$DEB_DIR"
|
||||||
|
|
||||||
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$CERT_SRC_DIR" "$DESKTOP_DIR"
|
mkdir -p "$DEBIAN_DIR" "$BIN_DIR" "$DESKTOP_DIR"
|
||||||
|
|
||||||
cp build/linux/arm64/release/crossdesk "$BIN_DIR"
|
cp build/linux/arm64/release/crossdesk "$BIN_DIR"
|
||||||
chmod +x "$BIN_DIR/$PKG_NAME"
|
chmod +x "$BIN_DIR/$PKG_NAME"
|
||||||
|
|
||||||
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
|
ln -s "$PKG_NAME" "$BIN_DIR/$APP_NAME"
|
||||||
|
|
||||||
cp certs/crossdesk.cn_root.crt "$CERT_SRC_DIR/crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
for size in 16 24 32 48 64 96 128 256; do
|
for size in 16 24 32 48 64 96 128 256; do
|
||||||
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
|
mkdir -p "$ICON_BASE_DIR/${size}x${size}/apps"
|
||||||
cp "icons/linux/crossdesk_${size}x${size}.png" \
|
cp "icons/linux/crossdesk_${size}x${size}.png" \
|
||||||
@@ -70,7 +67,6 @@ if [ "\$1" = "remove" ] || [ "\$1" = "purge" ]; then
|
|||||||
rm -f /usr/bin/$PKG_NAME || true
|
rm -f /usr/bin/$PKG_NAME || true
|
||||||
rm -f /usr/bin/$APP_NAME || true
|
rm -f /usr/bin/$APP_NAME || true
|
||||||
rm -f /usr/share/applications/$PKG_NAME.desktop || true
|
rm -f /usr/share/applications/$PKG_NAME.desktop || true
|
||||||
rm -rf /opt/$PKG_NAME/certs || true
|
|
||||||
for size in 16 24 32 48 64 96 128 256; do
|
for size in 16 24 32 48 64 96 128 256; do
|
||||||
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
|
rm -f /usr/share/icons/hicolor/\${size}x\${size}/apps/$PKG_NAME.png || true
|
||||||
done
|
done
|
||||||
@@ -84,30 +80,6 @@ cat > "$DEBIAN_DIR/postinst" << 'EOF'
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
CERT_SRC="/opt/crossdesk/certs"
|
|
||||||
CERT_FILE="crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
for user_home in /home/*; do
|
|
||||||
[ -d "$user_home" ] || continue
|
|
||||||
username=$(basename "$user_home")
|
|
||||||
config_dir="$user_home/.config/CrossDesk/certs"
|
|
||||||
target="$config_dir/$CERT_FILE"
|
|
||||||
|
|
||||||
if [ ! -f "$target" ]; then
|
|
||||||
mkdir -p "$config_dir" || true
|
|
||||||
cp "$CERT_SRC/$CERT_FILE" "$target" || true
|
|
||||||
chown -R "$username:$username" "$user_home/.config/CrossDesk" || true
|
|
||||||
echo "✔ Installed cert for $username at $target"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -d "/root" ]; then
|
|
||||||
config_dir="/root/.config/CrossDesk/certs"
|
|
||||||
mkdir -p "$config_dir" || true
|
|
||||||
cp "$CERT_SRC/$CERT_FILE" "$config_dir/$CERT_FILE" || true
|
|
||||||
chown -R root:root /root/.config/CrossDesk || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ IDENTIFIER="cn.crossdesk.app"
|
|||||||
ICON_PATH="icons/macos/crossdesk.icns"
|
ICON_PATH="icons/macos/crossdesk.icns"
|
||||||
MACOS_MIN_VERSION="10.12"
|
MACOS_MIN_VERSION="10.12"
|
||||||
|
|
||||||
CERTS_SOURCE="certs"
|
|
||||||
CERT_NAME="crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
APP_BUNDLE="${APP_NAME_UPPER}.app"
|
APP_BUNDLE="${APP_NAME_UPPER}.app"
|
||||||
CONTENTS_DIR="${APP_BUNDLE}/Contents"
|
CONTENTS_DIR="${APP_BUNDLE}/Contents"
|
||||||
MACOS_DIR="${CONTENTS_DIR}/MacOS"
|
MACOS_DIR="${CONTENTS_DIR}/MacOS"
|
||||||
@@ -98,11 +95,6 @@ IDENTIFIER="cn.crossdesk.app"
|
|||||||
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
|
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
|
||||||
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
|
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
|
||||||
|
|
||||||
# 复制证书文件
|
|
||||||
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
|
|
||||||
mkdir -p "$DEST"
|
|
||||||
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
|
|
||||||
|
|
||||||
# 清除应用的权限授权,以便重新授权
|
# 清除应用的权限授权,以便重新授权
|
||||||
# 使用 tccutil 重置录屏权限和辅助功能权限
|
# 使用 tccutil 重置录屏权限和辅助功能权限
|
||||||
if command -v tccutil >/dev/null 2>&1; then
|
if command -v tccutil >/dev/null 2>&1; then
|
||||||
@@ -140,17 +132,8 @@ EOF
|
|||||||
|
|
||||||
chmod +x build_pkg_scripts/postinstall
|
chmod +x build_pkg_scripts/postinstall
|
||||||
|
|
||||||
pkgbuild \
|
|
||||||
--root "${CERTS_SOURCE}" \
|
|
||||||
--identifier "${IDENTIFIER}.certs" \
|
|
||||||
--version "${APP_VERSION}" \
|
|
||||||
--install-location "/Library/Application Support/CrossDesk/certs" \
|
|
||||||
--scripts build_pkg_scripts \
|
|
||||||
build_pkg_temp/${APP_NAME}-certs.pkg
|
|
||||||
|
|
||||||
productbuild \
|
productbuild \
|
||||||
--package build_pkg_temp/${APP_NAME}-component.pkg \
|
--package build_pkg_temp/${APP_NAME}-component.pkg \
|
||||||
--package build_pkg_temp/${APP_NAME}-certs.pkg \
|
|
||||||
"${PKG_NAME}"
|
"${PKG_NAME}"
|
||||||
|
|
||||||
echo "PKG package created: ${PKG_NAME}"
|
echo "PKG package created: ${PKG_NAME}"
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ IDENTIFIER="cn.crossdesk.app"
|
|||||||
ICON_PATH="icons/macos/crossdesk.icns"
|
ICON_PATH="icons/macos/crossdesk.icns"
|
||||||
MACOS_MIN_VERSION="10.12"
|
MACOS_MIN_VERSION="10.12"
|
||||||
|
|
||||||
CERTS_SOURCE="certs"
|
|
||||||
CERT_NAME="crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
APP_BUNDLE="${APP_NAME_UPPER}.app"
|
APP_BUNDLE="${APP_NAME_UPPER}.app"
|
||||||
CONTENTS_DIR="${APP_BUNDLE}/Contents"
|
CONTENTS_DIR="${APP_BUNDLE}/Contents"
|
||||||
MACOS_DIR="${CONTENTS_DIR}/MacOS"
|
MACOS_DIR="${CONTENTS_DIR}/MacOS"
|
||||||
@@ -98,11 +95,6 @@ IDENTIFIER="cn.crossdesk.app"
|
|||||||
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
|
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
|
||||||
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
|
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
|
||||||
|
|
||||||
# 复制证书文件
|
|
||||||
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
|
|
||||||
mkdir -p "$DEST"
|
|
||||||
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
|
|
||||||
|
|
||||||
# 清除应用的权限授权,以便重新授权
|
# 清除应用的权限授权,以便重新授权
|
||||||
# 使用 tccutil 重置录屏权限和辅助功能权限
|
# 使用 tccutil 重置录屏权限和辅助功能权限
|
||||||
if command -v tccutil >/dev/null 2>&1; then
|
if command -v tccutil >/dev/null 2>&1; then
|
||||||
@@ -140,17 +132,8 @@ EOF
|
|||||||
|
|
||||||
chmod +x build_pkg_scripts/postinstall
|
chmod +x build_pkg_scripts/postinstall
|
||||||
|
|
||||||
pkgbuild \
|
|
||||||
--root "${CERTS_SOURCE}" \
|
|
||||||
--identifier "${IDENTIFIER}.certs" \
|
|
||||||
--version "${APP_VERSION}" \
|
|
||||||
--install-location "/Library/Application Support/CrossDesk/certs" \
|
|
||||||
--scripts build_pkg_scripts \
|
|
||||||
build_pkg_temp/${APP_NAME}-certs.pkg
|
|
||||||
|
|
||||||
productbuild \
|
productbuild \
|
||||||
--package build_pkg_temp/${APP_NAME}-component.pkg \
|
--package build_pkg_temp/${APP_NAME}-component.pkg \
|
||||||
--package build_pkg_temp/${APP_NAME}-certs.pkg \
|
|
||||||
"${PKG_NAME}"
|
"${PKG_NAME}"
|
||||||
|
|
||||||
echo "PKG package created: ${PKG_NAME}"
|
echo "PKG package created: ${PKG_NAME}"
|
||||||
|
|||||||
2
scripts/windows/crossdesk.rc
Normal file
2
scripts/windows/crossdesk.rc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Application icon (IDI_ICON1 = 1, which is the default app icon resource ID)
|
||||||
|
IDI_ICON1 ICON "..\\..\\icons\\windows\\crossdesk.ico"
|
||||||
@@ -12,9 +12,6 @@
|
|||||||
; Installer icon path
|
; Installer icon path
|
||||||
!define MUI_ICON "${__FILEDIR__}\..\..\icons\windows\crossdesk.ico"
|
!define MUI_ICON "${__FILEDIR__}\..\..\icons\windows\crossdesk.ico"
|
||||||
|
|
||||||
; Certificate path
|
|
||||||
!define CERT_FILE "${__FILEDIR__}\..\..\certs\crossdesk.cn_root.crt"
|
|
||||||
|
|
||||||
; Compression settings
|
; Compression settings
|
||||||
SetCompressor /FINAL lzma
|
SetCompressor /FINAL lzma
|
||||||
|
|
||||||
@@ -49,7 +46,7 @@ ShowInstDetails show
|
|||||||
|
|
||||||
Section "MainSection"
|
Section "MainSection"
|
||||||
; Check if CrossDesk is running
|
; Check if CrossDesk is running
|
||||||
StrCpy $1 "crossdesk.exe"
|
StrCpy $1 "CrossDesk.exe"
|
||||||
|
|
||||||
nsProcess::_FindProcess "$1"
|
nsProcess::_FindProcess "$1"
|
||||||
Pop $R0
|
Pop $R0
|
||||||
@@ -75,10 +72,7 @@ installApp:
|
|||||||
SetOverwrite ifnewer
|
SetOverwrite ifnewer
|
||||||
|
|
||||||
; Main application executable path
|
; Main application executable path
|
||||||
File /oname=crossdesk.exe "..\..\build\windows\x64\release\crossdesk.exe"
|
File /oname=CrossDesk.exe "..\..\build\windows\x64\release\crossdesk.exe"
|
||||||
|
|
||||||
; Copy icon file to installation directory
|
|
||||||
File "${MUI_ICON}"
|
|
||||||
|
|
||||||
; Write uninstall information
|
; Write uninstall information
|
||||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
@@ -88,33 +82,23 @@ installApp:
|
|||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayIcon" "$INSTDIR\crossdesk.ico"
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "DisplayIcon" "$INSTDIR\CrossDesk.exe"
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoModify" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoModify" 1
|
||||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoRepair" 1
|
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINSTALL_REG_KEY}" "NoRepair" 1
|
||||||
WriteRegStr HKCU "Software\${PRODUCT_NAME}" "InstallDir" "$INSTDIR"
|
WriteRegStr HKCU "Software\${PRODUCT_NAME}" "InstallDir" "$INSTDIR"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
; After installation
|
|
||||||
Section -Post
|
|
||||||
ExecWait '"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x86\mt.exe" -manifest "$INSTDIR\crossdesk.manifest" -outputresource:"$INSTDIR\crossdesk.exe";1'
|
|
||||||
SectionEnd
|
|
||||||
|
|
||||||
Section "Cert"
|
|
||||||
SetOutPath "$APPDATA\CrossDesk\certs"
|
|
||||||
File /r "${CERT_FILE}"
|
|
||||||
SectionEnd
|
|
||||||
|
|
||||||
Section -AdditionalIcons
|
Section -AdditionalIcons
|
||||||
; Desktop shortcut
|
; Desktop shortcut
|
||||||
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\crossdesk.exe" "" "$INSTDIR\crossdesk.ico"
|
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\CrossDesk.exe" "" "$INSTDIR\CrossDesk.exe"
|
||||||
|
|
||||||
; Start menu shortcut
|
; Start menu shortcut
|
||||||
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$INSTDIR\crossdesk.exe" "" "$INSTDIR\crossdesk.ico"
|
CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}.lnk" "$INSTDIR\CrossDesk.exe" "" "$INSTDIR\CrossDesk.exe"
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
Section "Uninstall"
|
Section "Uninstall"
|
||||||
; Check if CrossDesk is running
|
; Check if CrossDesk is running
|
||||||
StrCpy $1 "crossdesk.exe"
|
StrCpy $1 "CrossDesk.exe"
|
||||||
|
|
||||||
nsProcess::_FindProcess "$1"
|
nsProcess::_FindProcess "$1"
|
||||||
Pop $R0
|
Pop $R0
|
||||||
@@ -137,7 +121,7 @@ cancelUninstall:
|
|||||||
|
|
||||||
uninstallApp:
|
uninstallApp:
|
||||||
; Delete main executable and uninstaller
|
; Delete main executable and uninstaller
|
||||||
Delete "$INSTDIR\crossdesk.exe"
|
Delete "$INSTDIR\CrossDesk.exe"
|
||||||
Delete "$INSTDIR\uninstall.exe"
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
|
|
||||||
; Recursively delete installation directory
|
; Recursively delete installation directory
|
||||||
@@ -160,5 +144,5 @@ SectionEnd
|
|||||||
|
|
||||||
; ------ Functions ------
|
; ------ Functions ------
|
||||||
Function LaunchApp
|
Function LaunchApp
|
||||||
Exec "$INSTDIR\crossdesk.exe"
|
Exec "$INSTDIR\CrossDesk.exe"
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|||||||
@@ -35,11 +35,8 @@ int main(int argc, char* argv[]) {
|
|||||||
bool enable_daemon = false;
|
bool enable_daemon = false;
|
||||||
auto path_manager = std::make_unique<crossdesk::PathManager>("CrossDesk");
|
auto path_manager = std::make_unique<crossdesk::PathManager>("CrossDesk");
|
||||||
if (path_manager) {
|
if (path_manager) {
|
||||||
std::string cert_path =
|
|
||||||
(path_manager->GetCertPath() / "crossdesk.cn_root.crt").string();
|
|
||||||
std::string cache_path = path_manager->GetCachePath().string();
|
std::string cache_path = path_manager->GetCachePath().string();
|
||||||
crossdesk::ConfigCenter config_center(cache_path + "/config.ini",
|
crossdesk::ConfigCenter config_center(cache_path + "/config.ini");
|
||||||
cert_path);
|
|
||||||
enable_daemon = config_center.IsEnableDaemon();
|
enable_daemon = config_center.IsEnableDaemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,8 @@
|
|||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
ConfigCenter::ConfigCenter(const std::string& config_path,
|
ConfigCenter::ConfigCenter(const std::string& config_path)
|
||||||
const std::string& cert_file_path)
|
: config_path_(config_path) {
|
||||||
: config_path_(config_path),
|
|
||||||
cert_file_path_(cert_file_path),
|
|
||||||
cert_file_path_default_(cert_file_path) {
|
|
||||||
ini_.SetUnicode(true);
|
ini_.SetUnicode(true);
|
||||||
Load();
|
Load();
|
||||||
}
|
}
|
||||||
@@ -70,71 +67,6 @@ int ConfigCenter::Load() {
|
|||||||
} else {
|
} else {
|
||||||
coturn_server_port_ = 0;
|
coturn_server_port_ = 0;
|
||||||
}
|
}
|
||||||
const char* cert_file_path_value =
|
|
||||||
ini_.GetValue(section_, "cert_file_path", nullptr);
|
|
||||||
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
|
|
||||||
cert_file_path_ = cert_file_path_value;
|
|
||||||
} else {
|
|
||||||
cert_file_path_ = "";
|
|
||||||
}
|
|
||||||
const char* cert_fingerprint_value =
|
|
||||||
ini_.GetValue(section_, "cert_fingerprint", nullptr);
|
|
||||||
if (cert_fingerprint_value != nullptr && strlen(cert_fingerprint_value) > 0) {
|
|
||||||
cert_fingerprint_ = cert_fingerprint_value;
|
|
||||||
} else {
|
|
||||||
cert_fingerprint_ = "";
|
|
||||||
}
|
|
||||||
const char* cert_fingerprint_server_host_value =
|
|
||||||
ini_.GetValue(section_, "cert_fingerprint_server_host", nullptr);
|
|
||||||
if (cert_fingerprint_server_host_value != nullptr &&
|
|
||||||
strlen(cert_fingerprint_server_host_value) > 0) {
|
|
||||||
cert_fingerprint_server_host_ = cert_fingerprint_server_host_value;
|
|
||||||
} else {
|
|
||||||
cert_fingerprint_server_host_ = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* default_cert_fingerprint_value =
|
|
||||||
ini_.GetValue(section_, "default_cert_fingerprint", nullptr);
|
|
||||||
if (default_cert_fingerprint_value != nullptr &&
|
|
||||||
strlen(default_cert_fingerprint_value) > 0) {
|
|
||||||
default_cert_fingerprint_ = default_cert_fingerprint_value;
|
|
||||||
} else {
|
|
||||||
default_cert_fingerprint_ = "";
|
|
||||||
}
|
|
||||||
const char* default_cert_fingerprint_server_host_value =
|
|
||||||
ini_.GetValue(section_, "default_cert_fingerprint_server_host", nullptr);
|
|
||||||
if (default_cert_fingerprint_server_host_value != nullptr &&
|
|
||||||
strlen(default_cert_fingerprint_server_host_value) > 0) {
|
|
||||||
default_cert_fingerprint_server_host_ =
|
|
||||||
default_cert_fingerprint_server_host_value;
|
|
||||||
} else {
|
|
||||||
default_cert_fingerprint_server_host_ = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable_self_hosted_ && !cert_fingerprint_.empty() &&
|
|
||||||
!cert_fingerprint_server_host_.empty() &&
|
|
||||||
signal_server_host_ != cert_fingerprint_server_host_) {
|
|
||||||
LOG_INFO("Server IP changed from {} to {}, clearing old fingerprint",
|
|
||||||
cert_fingerprint_server_host_, signal_server_host_);
|
|
||||||
cert_fingerprint_.clear();
|
|
||||||
cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "cert_fingerprint_server_host", false);
|
|
||||||
ini_.SaveFile(config_path_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enable_self_hosted_ && !default_cert_fingerprint_.empty() &&
|
|
||||||
!default_cert_fingerprint_server_host_.empty() &&
|
|
||||||
signal_server_host_default_ != default_cert_fingerprint_server_host_) {
|
|
||||||
LOG_INFO(
|
|
||||||
"Default server IP changed from {} to {}, clearing old fingerprint",
|
|
||||||
default_cert_fingerprint_server_host_, signal_server_host_default_);
|
|
||||||
default_cert_fingerprint_.clear();
|
|
||||||
default_cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "default_cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "default_cert_fingerprint_server_host", false);
|
|
||||||
ini_.SaveFile(config_path_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
enable_autostart_ =
|
enable_autostart_ =
|
||||||
ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_);
|
ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_);
|
||||||
@@ -142,6 +74,15 @@ int ConfigCenter::Load() {
|
|||||||
enable_minimize_to_tray_ = ini_.GetBoolValue(
|
enable_minimize_to_tray_ = ini_.GetBoolValue(
|
||||||
section_, "enable_minimize_to_tray", enable_minimize_to_tray_);
|
section_, "enable_minimize_to_tray", enable_minimize_to_tray_);
|
||||||
|
|
||||||
|
const char* file_transfer_save_path_value =
|
||||||
|
ini_.GetValue(section_, "file_transfer_save_path", nullptr);
|
||||||
|
if (file_transfer_save_path_value != nullptr &&
|
||||||
|
strlen(file_transfer_save_path_value) > 0) {
|
||||||
|
file_transfer_save_path_ = file_transfer_save_path_value;
|
||||||
|
} else {
|
||||||
|
file_transfer_save_path_ = "";
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,19 +106,6 @@ int ConfigCenter::Save() {
|
|||||||
static_cast<long>(signal_server_port_));
|
static_cast<long>(signal_server_port_));
|
||||||
ini_.SetLongValue(section_, "coturn_server_port",
|
ini_.SetLongValue(section_, "coturn_server_port",
|
||||||
static_cast<long>(coturn_server_port_));
|
static_cast<long>(coturn_server_port_));
|
||||||
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
|
||||||
if (!cert_fingerprint_.empty()) {
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint", cert_fingerprint_.c_str());
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint_server_host",
|
|
||||||
cert_fingerprint_server_host_.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!default_cert_fingerprint_.empty()) {
|
|
||||||
ini_.SetValue(section_, "default_cert_fingerprint",
|
|
||||||
default_cert_fingerprint_.c_str());
|
|
||||||
ini_.SetValue(section_, "default_cert_fingerprint_server_host",
|
|
||||||
default_cert_fingerprint_server_host_.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_);
|
ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_);
|
||||||
@@ -185,6 +113,9 @@ int ConfigCenter::Save() {
|
|||||||
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
|
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
|
||||||
enable_minimize_to_tray_);
|
enable_minimize_to_tray_);
|
||||||
|
|
||||||
|
ini_.SetValue(section_, "file_transfer_save_path",
|
||||||
|
file_transfer_save_path_.c_str());
|
||||||
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -270,15 +201,6 @@ int ConfigCenter::SetSrtp(bool enable_srtp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ConfigCenter::SetServerHost(const std::string& signal_server_host) {
|
int ConfigCenter::SetServerHost(const std::string& signal_server_host) {
|
||||||
if (enable_self_hosted_ && !cert_fingerprint_.empty() &&
|
|
||||||
signal_server_host != signal_server_host_) {
|
|
||||||
LOG_INFO("Server IP changed from {} to {}, clearing old fingerprint",
|
|
||||||
signal_server_host_, signal_server_host);
|
|
||||||
cert_fingerprint_.clear();
|
|
||||||
cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "cert_fingerprint_server_host", false);
|
|
||||||
}
|
|
||||||
signal_server_host_ = signal_server_host;
|
signal_server_host_ = signal_server_host;
|
||||||
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
||||||
@@ -310,67 +232,6 @@ int ConfigCenter::SetCoturnServerPort(int coturn_server_port) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfigCenter::SetCertFilePath(const std::string& cert_file_path) {
|
|
||||||
cert_file_path_ = cert_file_path;
|
|
||||||
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
|
||||||
if (rc < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigCenter::SetCertFingerprint(const std::string& fingerprint) {
|
|
||||||
cert_fingerprint_ = fingerprint;
|
|
||||||
cert_fingerprint_server_host_ = signal_server_host_;
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint", cert_fingerprint_.c_str());
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint_server_host",
|
|
||||||
cert_fingerprint_server_host_.c_str());
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
|
||||||
if (rc < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigCenter::SetDefaultCertFingerprint(const std::string& fingerprint) {
|
|
||||||
default_cert_fingerprint_ = fingerprint;
|
|
||||||
default_cert_fingerprint_server_host_ = signal_server_host_default_;
|
|
||||||
ini_.SetValue(section_, "default_cert_fingerprint",
|
|
||||||
default_cert_fingerprint_.c_str());
|
|
||||||
ini_.SetValue(section_, "default_cert_fingerprint_server_host",
|
|
||||||
default_cert_fingerprint_server_host_.c_str());
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
|
||||||
if (rc < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigCenter::ClearCertFingerprint() {
|
|
||||||
cert_fingerprint_.clear();
|
|
||||||
cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "cert_fingerprint_server_host", false);
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
|
||||||
if (rc < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigCenter::ClearDefaultCertFingerprint() {
|
|
||||||
default_cert_fingerprint_.clear();
|
|
||||||
default_cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "default_cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "default_cert_fingerprint_server_host", false);
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
|
||||||
if (rc < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
|
int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
|
||||||
enable_self_hosted_ = enable_self_hosted;
|
enable_self_hosted_ = enable_self_hosted;
|
||||||
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
|
||||||
@@ -397,45 +258,12 @@ int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
|
|||||||
coturn_server_port_ = static_cast<int>(
|
coturn_server_port_ = static_cast<int>(
|
||||||
ini_.GetLongValue(section_, "coturn_server_port", 0));
|
ini_.GetLongValue(section_, "coturn_server_port", 0));
|
||||||
}
|
}
|
||||||
const char* cert_file_path_value =
|
|
||||||
ini_.GetValue(section_, "cert_file_path", nullptr);
|
|
||||||
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
|
|
||||||
cert_file_path_ = cert_file_path_value;
|
|
||||||
}
|
|
||||||
const char* cert_fingerprint_value =
|
|
||||||
ini_.GetValue(section_, "cert_fingerprint", nullptr);
|
|
||||||
if (cert_fingerprint_value != nullptr &&
|
|
||||||
strlen(cert_fingerprint_value) > 0) {
|
|
||||||
cert_fingerprint_ = cert_fingerprint_value;
|
|
||||||
}
|
|
||||||
const char* cert_fingerprint_server_host_value =
|
|
||||||
ini_.GetValue(section_, "cert_fingerprint_server_host", nullptr);
|
|
||||||
if (cert_fingerprint_server_host_value != nullptr &&
|
|
||||||
strlen(cert_fingerprint_server_host_value) > 0) {
|
|
||||||
cert_fingerprint_server_host_ = cert_fingerprint_server_host_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cert_fingerprint_.empty() && !cert_fingerprint_server_host_.empty() &&
|
|
||||||
signal_server_host_ != cert_fingerprint_server_host_) {
|
|
||||||
LOG_INFO("Server IP changed from {} to {}, clearing old fingerprint",
|
|
||||||
cert_fingerprint_server_host_, signal_server_host_);
|
|
||||||
cert_fingerprint_.clear();
|
|
||||||
cert_fingerprint_server_host_.clear();
|
|
||||||
ini_.Delete(section_, "cert_fingerprint", false);
|
|
||||||
ini_.Delete(section_, "cert_fingerprint_server_host", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
|
||||||
ini_.SetLongValue(section_, "signal_server_port",
|
ini_.SetLongValue(section_, "signal_server_port",
|
||||||
static_cast<long>(signal_server_port_));
|
static_cast<long>(signal_server_port_));
|
||||||
ini_.SetLongValue(section_, "coturn_server_port",
|
ini_.SetLongValue(section_, "coturn_server_port",
|
||||||
static_cast<long>(coturn_server_port_));
|
static_cast<long>(coturn_server_port_));
|
||||||
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
|
|
||||||
if (!cert_fingerprint_.empty()) {
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint", cert_fingerprint_.c_str());
|
|
||||||
ini_.SetValue(section_, "cert_fingerprint_server_host",
|
|
||||||
cert_fingerprint_server_host_.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
||||||
@@ -523,16 +351,6 @@ int ConfigCenter::GetSignalServerPort() const { return signal_server_port_; }
|
|||||||
|
|
||||||
int ConfigCenter::GetCoturnServerPort() const { return coturn_server_port_; }
|
int ConfigCenter::GetCoturnServerPort() const { return coturn_server_port_; }
|
||||||
|
|
||||||
std::string ConfigCenter::GetCertFilePath() const { return cert_file_path_; }
|
|
||||||
|
|
||||||
std::string ConfigCenter::GetCertFingerprint() const {
|
|
||||||
return cert_fingerprint_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ConfigCenter::GetDefaultCertFingerprint() const {
|
|
||||||
return default_cert_fingerprint_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ConfigCenter::GetDefaultServerHost() const {
|
std::string ConfigCenter::GetDefaultServerHost() const {
|
||||||
return signal_server_host_default_;
|
return signal_server_host_default_;
|
||||||
}
|
}
|
||||||
@@ -545,10 +363,6 @@ int ConfigCenter::GetDefaultCoturnServerPort() const {
|
|||||||
return coturn_server_port_default_;
|
return coturn_server_port_default_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ConfigCenter::GetDefaultCertFilePath() const {
|
|
||||||
return cert_file_path_default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; }
|
bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; }
|
||||||
|
|
||||||
bool ConfigCenter::IsMinimizeToTray() const { return enable_minimize_to_tray_; }
|
bool ConfigCenter::IsMinimizeToTray() const { return enable_minimize_to_tray_; }
|
||||||
@@ -556,4 +370,19 @@ bool ConfigCenter::IsMinimizeToTray() const { return enable_minimize_to_tray_; }
|
|||||||
bool ConfigCenter::IsEnableAutostart() const { return enable_autostart_; }
|
bool ConfigCenter::IsEnableAutostart() const { return enable_autostart_; }
|
||||||
|
|
||||||
bool ConfigCenter::IsEnableDaemon() const { return enable_daemon_; }
|
bool ConfigCenter::IsEnableDaemon() const { return enable_daemon_; }
|
||||||
|
|
||||||
|
int ConfigCenter::SetFileTransferSavePath(const std::string& path) {
|
||||||
|
file_transfer_save_path_ = path;
|
||||||
|
ini_.SetValue(section_, "file_transfer_save_path",
|
||||||
|
file_transfer_save_path_.c_str());
|
||||||
|
SI_Error rc = ini_.SaveFile(config_path_.c_str());
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ConfigCenter::GetFileTransferSavePath() const {
|
||||||
|
return file_transfer_save_path_;
|
||||||
|
}
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
@@ -21,9 +21,7 @@ class ConfigCenter {
|
|||||||
enum class VIDEO_ENCODE_FORMAT { H264 = 0, AV1 = 1 };
|
enum class VIDEO_ENCODE_FORMAT { H264 = 0, AV1 = 1 };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigCenter(
|
explicit ConfigCenter(const std::string& config_path = "config.ini");
|
||||||
const std::string& config_path = "config.ini",
|
|
||||||
const std::string& cert_file_path = "crossdesk.cn_root.crt");
|
|
||||||
~ConfigCenter();
|
~ConfigCenter();
|
||||||
|
|
||||||
// write config
|
// write config
|
||||||
@@ -37,15 +35,11 @@ class ConfigCenter {
|
|||||||
int SetServerHost(const std::string& signal_server_host);
|
int SetServerHost(const std::string& signal_server_host);
|
||||||
int SetServerPort(int signal_server_port);
|
int SetServerPort(int signal_server_port);
|
||||||
int SetCoturnServerPort(int coturn_server_port);
|
int SetCoturnServerPort(int coturn_server_port);
|
||||||
int SetCertFilePath(const std::string& cert_file_path);
|
|
||||||
int SetCertFingerprint(const std::string& fingerprint);
|
|
||||||
int SetDefaultCertFingerprint(const std::string& fingerprint);
|
|
||||||
int ClearCertFingerprint();
|
|
||||||
int ClearDefaultCertFingerprint();
|
|
||||||
int SetSelfHosted(bool enable_self_hosted);
|
int SetSelfHosted(bool enable_self_hosted);
|
||||||
int SetMinimizeToTray(bool enable_minimize_to_tray);
|
int SetMinimizeToTray(bool enable_minimize_to_tray);
|
||||||
int SetAutostart(bool enable_autostart);
|
int SetAutostart(bool enable_autostart);
|
||||||
int SetDaemon(bool enable_daemon);
|
int SetDaemon(bool enable_daemon);
|
||||||
|
int SetFileTransferSavePath(const std::string& path);
|
||||||
|
|
||||||
// read config
|
// read config
|
||||||
|
|
||||||
@@ -59,17 +53,14 @@ class ConfigCenter {
|
|||||||
std::string GetSignalServerHost() const;
|
std::string GetSignalServerHost() const;
|
||||||
int GetSignalServerPort() const;
|
int GetSignalServerPort() const;
|
||||||
int GetCoturnServerPort() const;
|
int GetCoturnServerPort() const;
|
||||||
std::string GetCertFilePath() const;
|
|
||||||
std::string GetCertFingerprint() const;
|
|
||||||
std::string GetDefaultCertFingerprint() const;
|
|
||||||
std::string GetDefaultServerHost() const;
|
std::string GetDefaultServerHost() const;
|
||||||
int GetDefaultSignalServerPort() const;
|
int GetDefaultSignalServerPort() const;
|
||||||
int GetDefaultCoturnServerPort() const;
|
int GetDefaultCoturnServerPort() const;
|
||||||
std::string GetDefaultCertFilePath() const;
|
|
||||||
bool IsSelfHosted() const;
|
bool IsSelfHosted() const;
|
||||||
bool IsMinimizeToTray() const;
|
bool IsMinimizeToTray() const;
|
||||||
bool IsEnableAutostart() const;
|
bool IsEnableAutostart() const;
|
||||||
bool IsEnableDaemon() const;
|
bool IsEnableDaemon() const;
|
||||||
|
std::string GetFileTransferSavePath() const;
|
||||||
|
|
||||||
int Load();
|
int Load();
|
||||||
int Save();
|
int Save();
|
||||||
@@ -92,16 +83,11 @@ class ConfigCenter {
|
|||||||
int server_port_default_ = 9099;
|
int server_port_default_ = 9099;
|
||||||
int coturn_server_port_ = 0;
|
int coturn_server_port_ = 0;
|
||||||
int coturn_server_port_default_ = 3478;
|
int coturn_server_port_default_ = 3478;
|
||||||
std::string cert_file_path_ = "";
|
|
||||||
std::string cert_file_path_default_ = "";
|
|
||||||
std::string cert_fingerprint_ = "";
|
|
||||||
std::string cert_fingerprint_server_host_ = "";
|
|
||||||
std::string default_cert_fingerprint_ = "";
|
|
||||||
std::string default_cert_fingerprint_server_host_ = "";
|
|
||||||
bool enable_self_hosted_ = false;
|
bool enable_self_hosted_ = false;
|
||||||
bool enable_minimize_to_tray_ = false;
|
bool enable_minimize_to_tray_ = false;
|
||||||
bool enable_autostart_ = false;
|
bool enable_autostart_ = false;
|
||||||
bool enable_daemon_ = false;
|
bool enable_daemon_ = false;
|
||||||
|
std::string file_transfer_save_path_ = "";
|
||||||
};
|
};
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
#endif
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -112,13 +112,8 @@ static std::vector<std::string> self_hosted_server_port = {
|
|||||||
reinterpret_cast<const char*>(u8"信令服务端口:"), "Signal Service Port:"};
|
reinterpret_cast<const char*>(u8"信令服务端口:"), "Signal Service Port:"};
|
||||||
static std::vector<std::string> self_hosted_server_coturn_server_port = {
|
static std::vector<std::string> self_hosted_server_coturn_server_port = {
|
||||||
reinterpret_cast<const char*>(u8"中继服务端口:"), "Relay Service Port:"};
|
reinterpret_cast<const char*>(u8"中继服务端口:"), "Relay Service Port:"};
|
||||||
static std::vector<std::string> self_hosted_server_certificate_path = {
|
|
||||||
reinterpret_cast<const char*>(u8"证书文件路径:"), "Certificate File Path:"};
|
|
||||||
static std::vector<std::string> select_a_file = {
|
static std::vector<std::string> select_a_file = {
|
||||||
reinterpret_cast<const char*>(u8"请选择文件"), "Please select a file"};
|
reinterpret_cast<const char*>(u8"请选择文件"), "Please select a file"};
|
||||||
static std::vector<std::string> reset_cert_fingerprint = {
|
|
||||||
reinterpret_cast<const char*>(u8"重置证书指纹"),
|
|
||||||
"Reset Certificate Fingerprint"};
|
|
||||||
static std::vector<std::string> ok = {reinterpret_cast<const char*>(u8"确认"),
|
static std::vector<std::string> ok = {reinterpret_cast<const char*>(u8"确认"),
|
||||||
"OK"};
|
"OK"};
|
||||||
static std::vector<std::string> cancel = {
|
static std::vector<std::string> cancel = {
|
||||||
@@ -203,11 +198,17 @@ static std::vector<std::string> file_transfer = {
|
|||||||
reinterpret_cast<const char*>(u8"文件传输:"), "File Transfer:"};
|
reinterpret_cast<const char*>(u8"文件传输:"), "File Transfer:"};
|
||||||
static std::vector<std::string> connection_status = {
|
static std::vector<std::string> connection_status = {
|
||||||
reinterpret_cast<const char*>(u8"连接状态:"), "Connection Status:"};
|
reinterpret_cast<const char*>(u8"连接状态:"), "Connection Status:"};
|
||||||
|
static std::vector<std::string> file_transfer_save_path = {
|
||||||
#if _WIN32
|
reinterpret_cast<const char*>(u8"文件接收保存路径:"),
|
||||||
|
"File Transfer Save Path:"};
|
||||||
|
static std::vector<std::string> browse = {
|
||||||
|
reinterpret_cast<const char*>(u8"浏览"), "Browse"};
|
||||||
|
static std::vector<std::string> default_desktop = {
|
||||||
|
reinterpret_cast<const char*>(u8"桌面"), "Desktop"};
|
||||||
static std::vector<std::string> minimize_to_tray = {
|
static std::vector<std::string> minimize_to_tray = {
|
||||||
reinterpret_cast<const char*>(u8"退出时最小化到系统托盘:"),
|
reinterpret_cast<const char*>(u8"退出时最小化到系统托盘:"),
|
||||||
"Minimize to system tray when exit:"};
|
"Minimize to system tray when exit:"};
|
||||||
|
#if _WIN32
|
||||||
static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"};
|
static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"};
|
||||||
#endif
|
#endif
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|||||||
@@ -492,6 +492,16 @@ int Render::LoadSettingsFromCacheFile() {
|
|||||||
enable_daemon_ = config_center_->IsEnableDaemon();
|
enable_daemon_ = config_center_->IsEnableDaemon();
|
||||||
enable_minimize_to_tray_ = config_center_->IsMinimizeToTray();
|
enable_minimize_to_tray_ = config_center_->IsMinimizeToTray();
|
||||||
|
|
||||||
|
// File transfer save path
|
||||||
|
{
|
||||||
|
std::string saved_path = config_center_->GetFileTransferSavePath();
|
||||||
|
strncpy(file_transfer_save_path_buf_, saved_path.c_str(),
|
||||||
|
sizeof(file_transfer_save_path_buf_) - 1);
|
||||||
|
file_transfer_save_path_buf_[sizeof(file_transfer_save_path_buf_) - 1] =
|
||||||
|
'\0';
|
||||||
|
file_transfer_save_path_last_ = saved_path;
|
||||||
|
}
|
||||||
|
|
||||||
language_button_value_last_ = language_button_value_;
|
language_button_value_last_ = language_button_value_;
|
||||||
video_quality_button_value_last_ = video_quality_button_value_;
|
video_quality_button_value_last_ = video_quality_button_value_;
|
||||||
video_encode_format_button_value_last_ = video_encode_format_button_value_;
|
video_encode_format_button_value_last_ = video_encode_format_button_value_;
|
||||||
@@ -672,13 +682,11 @@ int Render::CreateConnectionPeer() {
|
|||||||
std::string signal_server_ip;
|
std::string signal_server_ip;
|
||||||
int signal_server_port;
|
int signal_server_port;
|
||||||
int coturn_server_port;
|
int coturn_server_port;
|
||||||
std::string tls_cert_fingerprint;
|
|
||||||
|
|
||||||
if (config_center_->IsSelfHosted()) {
|
if (config_center_->IsSelfHosted()) {
|
||||||
signal_server_ip = config_center_->GetSignalServerHost();
|
signal_server_ip = config_center_->GetSignalServerHost();
|
||||||
signal_server_port = config_center_->GetSignalServerPort();
|
signal_server_port = config_center_->GetSignalServerPort();
|
||||||
coturn_server_port = config_center_->GetCoturnServerPort();
|
coturn_server_port = config_center_->GetCoturnServerPort();
|
||||||
tls_cert_fingerprint = config_center_->GetCertFingerprint();
|
|
||||||
|
|
||||||
std::string current_self_hosted_ip = config_center_->GetSignalServerHost();
|
std::string current_self_hosted_ip = config_center_->GetSignalServerHost();
|
||||||
bool use_cached_id = false;
|
bool use_cached_id = false;
|
||||||
@@ -739,7 +747,6 @@ int Render::CreateConnectionPeer() {
|
|||||||
signal_server_ip = config_center_->GetDefaultServerHost();
|
signal_server_ip = config_center_->GetDefaultServerHost();
|
||||||
signal_server_port = config_center_->GetDefaultSignalServerPort();
|
signal_server_port = config_center_->GetDefaultSignalServerPort();
|
||||||
coturn_server_port = config_center_->GetDefaultCoturnServerPort();
|
coturn_server_port = config_center_->GetDefaultCoturnServerPort();
|
||||||
tls_cert_fingerprint = config_center_->GetDefaultCertFingerprint();
|
|
||||||
params_.user_id = client_id_with_password_;
|
params_.user_id = client_id_with_password_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,7 +770,6 @@ int Render::CreateConnectionPeer() {
|
|||||||
} else {
|
} else {
|
||||||
coturn_server_port_self_[0] = '\0';
|
coturn_server_port_self_[0] = '\0';
|
||||||
}
|
}
|
||||||
tls_cert_path_self_ = config_center_->GetCertFilePath();
|
|
||||||
|
|
||||||
// peer config
|
// peer config
|
||||||
strncpy((char*)params_.signal_server_ip, signal_server_ip.c_str(),
|
strncpy((char*)params_.signal_server_ip, signal_server_ip.c_str(),
|
||||||
@@ -784,30 +790,6 @@ int Render::CreateConnectionPeer() {
|
|||||||
strncpy((char*)params_.turn_server_password, "crossdeskpw",
|
strncpy((char*)params_.turn_server_password, "crossdeskpw",
|
||||||
sizeof(params_.turn_server_password) - 1);
|
sizeof(params_.turn_server_password) - 1);
|
||||||
params_.turn_server_password[sizeof(params_.turn_server_password) - 1] = '\0';
|
params_.turn_server_password[sizeof(params_.turn_server_password) - 1] = '\0';
|
||||||
strncpy(params_.tls_cert_fingerprint, tls_cert_fingerprint.c_str(),
|
|
||||||
sizeof(params_.tls_cert_fingerprint) - 1);
|
|
||||||
params_.tls_cert_fingerprint[sizeof(params_.tls_cert_fingerprint) - 1] = '\0';
|
|
||||||
|
|
||||||
if (config_center_->IsSelfHosted()) {
|
|
||||||
params_.on_cert_fingerprint = [](const char* fingerprint, void* user_data) {
|
|
||||||
Render* render = static_cast<Render*>(user_data);
|
|
||||||
if (render && render->config_center_) {
|
|
||||||
render->config_center_->SetCertFingerprint(fingerprint);
|
|
||||||
LOG_INFO("Saved self-hosted certificate fingerprint: {}", fingerprint);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
params_.fingerprint_user_data = this;
|
|
||||||
} else {
|
|
||||||
params_.on_cert_fingerprint = [](const char* fingerprint, void* user_data) {
|
|
||||||
Render* render = static_cast<Render*>(user_data);
|
|
||||||
if (render && render->config_center_) {
|
|
||||||
render->config_center_->SetDefaultCertFingerprint(fingerprint);
|
|
||||||
LOG_INFO("Saved default server certificate fingerprint: {}",
|
|
||||||
fingerprint);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
params_.fingerprint_user_data = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(params_.log_path, dll_log_path_.c_str(),
|
strncpy(params_.log_path, dll_log_path_.c_str(),
|
||||||
sizeof(params_.log_path) - 1);
|
sizeof(params_.log_path) - 1);
|
||||||
@@ -911,7 +893,7 @@ void Render::UpdateInteractions() {
|
|||||||
mouse_controller_is_started_ = false;
|
mouse_controller_is_started_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start_keyboard_capturer_ && foucs_on_stream_window_) {
|
if (start_keyboard_capturer_ && focus_on_stream_window_) {
|
||||||
if (!keyboard_capturer_is_started_) {
|
if (!keyboard_capturer_is_started_) {
|
||||||
StartKeyboardCapturer();
|
StartKeyboardCapturer();
|
||||||
keyboard_capturer_is_started_ = true;
|
keyboard_capturer_is_started_ = true;
|
||||||
@@ -1411,23 +1393,19 @@ int Render::DrawServerWindow() {
|
|||||||
LOG_ERROR("Server context is null");
|
LOG_ERROR("Server context is null");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server_window_) {
|
|
||||||
int w = 0;
|
|
||||||
int h = 0;
|
|
||||||
SDL_GetWindowSize(server_window_, &w, &h);
|
|
||||||
if (w > 0 && h > 0) {
|
|
||||||
server_window_width_ = (float)w;
|
|
||||||
server_window_height_ = (float)h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetCurrentContext(server_ctx_);
|
ImGui::SetCurrentContext(server_ctx_);
|
||||||
ImGui_ImplSDLRenderer3_NewFrame();
|
ImGui_ImplSDLRenderer3_NewFrame();
|
||||||
ImGui_ImplSDL3_NewFrame();
|
ImGui_ImplSDL3_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
server_window_width_ = io.DisplaySize.x;
|
||||||
|
server_window_height_ = io.DisplaySize.y;
|
||||||
|
|
||||||
ServerWindow();
|
ServerWindow();
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
SDL_SetRenderScale(server_renderer_, io.DisplayFramebufferScale.x,
|
||||||
|
io.DisplayFramebufferScale.y);
|
||||||
SDL_SetRenderDrawColor(server_renderer_, 255, 255, 255, 255);
|
SDL_SetRenderDrawColor(server_renderer_, 255, 255, 255, 255);
|
||||||
SDL_RenderClear(server_renderer_);
|
SDL_RenderClear(server_renderer_);
|
||||||
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), server_renderer_);
|
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), server_renderer_);
|
||||||
@@ -1458,13 +1436,11 @@ int Render::Run() {
|
|||||||
|
|
||||||
path_manager_ = std::make_unique<PathManager>("CrossDesk");
|
path_manager_ = std::make_unique<PathManager>("CrossDesk");
|
||||||
if (path_manager_) {
|
if (path_manager_) {
|
||||||
cert_path_ =
|
|
||||||
(path_manager_->GetCertPath() / "crossdesk.cn_root.crt").string();
|
|
||||||
exec_log_path_ = path_manager_->GetLogPath().string();
|
exec_log_path_ = path_manager_->GetLogPath().string();
|
||||||
dll_log_path_ = path_manager_->GetLogPath().string();
|
dll_log_path_ = path_manager_->GetLogPath().string();
|
||||||
cache_path_ = path_manager_->GetCachePath().string();
|
cache_path_ = path_manager_->GetCachePath().string();
|
||||||
config_center_ =
|
config_center_ =
|
||||||
std::make_unique<ConfigCenter>(cache_path_ + "/config.ini", cert_path_);
|
std::make_unique<ConfigCenter>(cache_path_ + "/config.ini");
|
||||||
strncpy(signal_server_ip_self_,
|
strncpy(signal_server_ip_self_,
|
||||||
config_center_->GetSignalServerHost().c_str(),
|
config_center_->GetSignalServerHost().c_str(),
|
||||||
sizeof(signal_server_ip_self_) - 1);
|
sizeof(signal_server_ip_self_) - 1);
|
||||||
@@ -1478,8 +1454,6 @@ int Render::Run() {
|
|||||||
} else {
|
} else {
|
||||||
signal_server_port_self_[0] = '\0';
|
signal_server_port_self_[0] = '\0';
|
||||||
}
|
}
|
||||||
strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1);
|
|
||||||
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Failed to create PathManager" << std::endl;
|
std::cerr << "Failed to create PathManager" << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2073,7 +2047,8 @@ void Render::UpdateRenderRect() {
|
|||||||
(int)(render_area_width * video_ratio_reverse)};
|
(int)(render_area_width * video_ratio_reverse)};
|
||||||
} else if (render_area_width > render_area_height * video_ratio) {
|
} else if (render_area_width > render_area_height * video_ratio) {
|
||||||
props->stream_render_rect_ = {
|
props->stream_render_rect_ = {
|
||||||
(int)abs(render_area_width - render_area_height * video_ratio) / 2,
|
(int)abs(render_area_width - render_area_height * video_ratio) / 2 +
|
||||||
|
(int)props->render_window_x_,
|
||||||
(int)props->render_window_y_, (int)(render_area_height * video_ratio),
|
(int)props->render_window_y_, (int)(render_area_height * video_ratio),
|
||||||
(int)render_area_height};
|
(int)render_area_height};
|
||||||
} else {
|
} else {
|
||||||
@@ -2198,7 +2173,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
|||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
if (stream_window_ &&
|
if (stream_window_ &&
|
||||||
SDL_GetWindowID(stream_window_) == event.window.windowID) {
|
SDL_GetWindowID(stream_window_) == event.window.windowID) {
|
||||||
foucs_on_stream_window_ = true;
|
focus_on_stream_window_ = true;
|
||||||
} else if (main_window_ &&
|
} else if (main_window_ &&
|
||||||
SDL_GetWindowID(main_window_) == event.window.windowID) {
|
SDL_GetWindowID(main_window_) == event.window.windowID) {
|
||||||
foucs_on_main_window_ = true;
|
foucs_on_main_window_ = true;
|
||||||
@@ -2208,7 +2183,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
|||||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||||
if (stream_window_ &&
|
if (stream_window_ &&
|
||||||
SDL_GetWindowID(stream_window_) == event.window.windowID) {
|
SDL_GetWindowID(stream_window_) == event.window.windowID) {
|
||||||
foucs_on_stream_window_ = false;
|
focus_on_stream_window_ = false;
|
||||||
} else if (main_window_ &&
|
} else if (main_window_ &&
|
||||||
SDL_GetWindowID(main_window_) == event.window.windowID) {
|
SDL_GetWindowID(main_window_) == event.window.windowID) {
|
||||||
foucs_on_main_window_ = false;
|
foucs_on_main_window_ = false;
|
||||||
@@ -2222,7 +2197,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
|||||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
case SDL_EVENT_MOUSE_WHEEL:
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
if (foucs_on_stream_window_) {
|
if (focus_on_stream_window_) {
|
||||||
ProcessMouseEvent(event);
|
ProcessMouseEvent(event);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -226,7 +226,6 @@ class Render {
|
|||||||
int RecentConnectionsWindow();
|
int RecentConnectionsWindow();
|
||||||
int SettingWindow();
|
int SettingWindow();
|
||||||
int SelfHostedServerWindow();
|
int SelfHostedServerWindow();
|
||||||
int ShowSimpleFileBrowser();
|
|
||||||
int ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props);
|
int ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props);
|
||||||
int ControlBar(std::shared_ptr<SubStreamWindowProperties>& props);
|
int ControlBar(std::shared_ptr<SubStreamWindowProperties>& props);
|
||||||
int AboutWindow();
|
int AboutWindow();
|
||||||
@@ -381,7 +380,6 @@ class Render {
|
|||||||
ConfigCenter::LANGUAGE localization_language_ =
|
ConfigCenter::LANGUAGE localization_language_ =
|
||||||
ConfigCenter::LANGUAGE::CHINESE;
|
ConfigCenter::LANGUAGE::CHINESE;
|
||||||
std::unique_ptr<PathManager> path_manager_;
|
std::unique_ptr<PathManager> path_manager_;
|
||||||
std::string cert_path_;
|
|
||||||
std::string exec_log_path_;
|
std::string exec_log_path_;
|
||||||
std::string dll_log_path_;
|
std::string dll_log_path_;
|
||||||
std::string cache_path_;
|
std::string cache_path_;
|
||||||
@@ -436,7 +434,7 @@ class Render {
|
|||||||
bool show_cursor_ = false;
|
bool show_cursor_ = false;
|
||||||
bool keyboard_capturer_is_started_ = false;
|
bool keyboard_capturer_is_started_ = false;
|
||||||
bool foucs_on_main_window_ = false;
|
bool foucs_on_main_window_ = false;
|
||||||
bool foucs_on_stream_window_ = false;
|
bool focus_on_stream_window_ = false;
|
||||||
bool main_window_minimized_ = false;
|
bool main_window_minimized_ = false;
|
||||||
uint32_t last_main_minimize_request_tick_ = 0;
|
uint32_t last_main_minimize_request_tick_ = 0;
|
||||||
uint32_t last_stream_minimize_request_tick_ = 0;
|
uint32_t last_stream_minimize_request_tick_ = 0;
|
||||||
@@ -633,7 +631,6 @@ class Render {
|
|||||||
char signal_server_ip_[256] = "api.crossdesk.cn";
|
char signal_server_ip_[256] = "api.crossdesk.cn";
|
||||||
char signal_server_port_[6] = "9099";
|
char signal_server_port_[6] = "9099";
|
||||||
char coturn_server_port_[6] = "3478";
|
char coturn_server_port_[6] = "3478";
|
||||||
char cert_file_path_[256] = "";
|
|
||||||
bool enable_self_hosted_ = false;
|
bool enable_self_hosted_ = false;
|
||||||
int language_button_value_last_ = 0;
|
int language_button_value_last_ = 0;
|
||||||
int video_quality_button_value_last_ = 0;
|
int video_quality_button_value_last_ = 0;
|
||||||
@@ -649,10 +646,11 @@ class Render {
|
|||||||
bool enable_daemon_last_ = false;
|
bool enable_daemon_last_ = false;
|
||||||
bool enable_minimize_to_tray_ = false;
|
bool enable_minimize_to_tray_ = false;
|
||||||
bool enable_minimize_to_tray_last_ = false;
|
bool enable_minimize_to_tray_last_ = false;
|
||||||
|
char file_transfer_save_path_buf_[512] = "";
|
||||||
|
std::string file_transfer_save_path_last_ = "";
|
||||||
char signal_server_ip_self_[256] = "";
|
char signal_server_ip_self_[256] = "";
|
||||||
char signal_server_port_self_[6] = "";
|
char signal_server_port_self_[6] = "";
|
||||||
char coturn_server_port_self_[6] = "";
|
char coturn_server_port_self_[6] = "";
|
||||||
std::string tls_cert_path_self_ = "";
|
|
||||||
bool settings_window_pos_reset_ = true;
|
bool settings_window_pos_reset_ = true;
|
||||||
bool self_hosted_server_config_window_pos_reset_ = true;
|
bool self_hosted_server_config_window_pos_reset_ = true;
|
||||||
std::string selected_current_file_path_ = "";
|
std::string selected_current_file_path_ = "";
|
||||||
|
|||||||
@@ -321,6 +321,14 @@ void Render::OnReceiveDataBufferCb(const char* data, size_t size,
|
|||||||
std::string remote_user_id = std::string(user_id, user_id_size);
|
std::string remote_user_id = std::string(user_id, user_id_size);
|
||||||
|
|
||||||
static FileReceiver receiver;
|
static FileReceiver receiver;
|
||||||
|
// Update output directory from config
|
||||||
|
std::string configured_path =
|
||||||
|
render->config_center_->GetFileTransferSavePath();
|
||||||
|
if (!configured_path.empty()) {
|
||||||
|
receiver.SetOutputDir(std::filesystem::u8path(configured_path));
|
||||||
|
} else if (receiver.OutputDir().empty()) {
|
||||||
|
receiver = FileReceiver(); // re-init with default desktop path
|
||||||
|
}
|
||||||
receiver.SetOnSendAck([render,
|
receiver.SetOnSendAck([render,
|
||||||
remote_user_id](const FileTransferAck& ack) -> int {
|
remote_user_id](const FileTransferAck& ack) -> int {
|
||||||
bool is_server_sending = remote_user_id.rfind("C-", 0) != 0;
|
bool is_server_sending = remote_user_id.rfind("C-", 0) != 0;
|
||||||
@@ -613,10 +621,6 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
|
|||||||
render->signal_connected_ = false;
|
render->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalServerClosed == status) {
|
} else if (SignalStatus::SignalServerClosed == status) {
|
||||||
render->signal_connected_ = false;
|
render->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalFingerprintMismatch == status) {
|
|
||||||
render->signal_connected_ = false;
|
|
||||||
LOG_ERROR("[{}] signal server fingerprint mismatch", client_id);
|
|
||||||
render->config_center_->ClearDefaultCertFingerprint();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (client_id.rfind("C-", 0) != 0) {
|
if (client_id.rfind("C-", 0) != 0) {
|
||||||
@@ -644,9 +648,6 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
|
|||||||
props->signal_connected_ = false;
|
props->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalServerClosed == status) {
|
} else if (SignalStatus::SignalServerClosed == status) {
|
||||||
props->signal_connected_ = false;
|
props->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalFingerprintMismatch == status) {
|
|
||||||
props->signal_connected_ = false;
|
|
||||||
LOG_ERROR("[{}] signal server fingerprint mismatch", remote_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
@@ -24,13 +28,34 @@ void Render::Hyperlink(const std::string& label, const std::string& url,
|
|||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
std::string cmd = "start " + url;
|
int wide_len =
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, url.c_str(), -1, nullptr, 0);
|
||||||
|
if (wide_len > 0) {
|
||||||
|
std::wstring wide_url(static_cast<size_t>(wide_len), L'\0');
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, url.c_str(), -1, &wide_url[0],
|
||||||
|
wide_len);
|
||||||
|
if (!wide_url.empty() && wide_url.back() == L'\0') {
|
||||||
|
wide_url.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring cmd = L"cmd.exe /c start \"\" \"" + wide_url + L"\"";
|
||||||
|
STARTUPINFOW startup_info = {sizeof(startup_info)};
|
||||||
|
PROCESS_INFORMATION process_info = {};
|
||||||
|
if (CreateProcessW(nullptr, &cmd[0], nullptr, nullptr, FALSE,
|
||||||
|
CREATE_NO_WINDOW, nullptr, nullptr, &startup_info,
|
||||||
|
&process_info)) {
|
||||||
|
CloseHandle(process_info.hThread);
|
||||||
|
CloseHandle(process_info.hProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
std::string cmd = "open " + url;
|
std::string cmd = "open " + url;
|
||||||
#else
|
#else
|
||||||
std::string cmd = "xdg-open " + url;
|
std::string cmd = "xdg-open " + url;
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(_WIN32)
|
||||||
system(cmd.c_str()); // open browser
|
system(cmd.c_str()); // open browser
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ int Render::FileTransferWindow(
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 3.0f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 0.9f));
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 0.9f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_TitleBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "tinyfiledialogs.h"
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
|
||||||
@@ -15,28 +16,28 @@ int Render::SettingWindow() {
|
|||||||
!defined(__arm__) && USE_CUDA) || \
|
!defined(__arm__) && USE_CUDA) || \
|
||||||
defined(__APPLE__))
|
defined(__APPLE__))
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.07f));
|
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.05f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.85f));
|
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.9f));
|
||||||
#else
|
#else
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.1f));
|
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.08f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.8f));
|
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.85f));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
|
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
|
||||||
!defined(__arm__) && USE_CUDA) || \
|
!defined(__arm__) && USE_CUDA) || \
|
||||||
defined(__APPLE__))
|
defined(__APPLE__))
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.07f));
|
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.05f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.85f));
|
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.9f));
|
||||||
#else
|
#else
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.1f));
|
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.08f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.8f));
|
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.85f));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,10 +331,14 @@ int Render::SettingWindow() {
|
|||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if _WIN32
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||||
|
#endif
|
||||||
settings_items_offset += settings_items_padding;
|
settings_items_offset += settings_items_padding;
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
ImGui::SetCursorPosY(settings_items_offset);
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
@@ -349,8 +354,67 @@ int Render::SettingWindow() {
|
|||||||
|
|
||||||
ImGui::Checkbox("##enable_minimize_to_tray_",
|
ImGui::Checkbox("##enable_minimize_to_tray_",
|
||||||
&enable_minimize_to_tray_);
|
&enable_minimize_to_tray_);
|
||||||
}
|
#ifndef _WIN32
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::EndDisabled();
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
{
|
||||||
|
settings_items_offset += settings_items_padding;
|
||||||
|
ImGui::SetCursorPosY(settings_items_offset);
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text(
|
||||||
|
"%s",
|
||||||
|
localization::file_transfer_save_path[localization_language_index_]
|
||||||
|
.c_str());
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
|
||||||
|
ImGui::SetCursorPosX(title_bar_button_width_ * 2.82f);
|
||||||
|
} else {
|
||||||
|
ImGui::SetCursorPosX(title_bar_button_width_ * 4.3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string display_path =
|
||||||
|
strlen(file_transfer_save_path_buf_) > 0
|
||||||
|
? file_transfer_save_path_buf_
|
||||||
|
: localization::default_desktop[localization_language_index_];
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
|
||||||
|
ImVec4(0.95f, 0.95f, 0.95f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
|
||||||
|
ImVec4(0.9f, 0.9f, 0.9f, 1.0f));
|
||||||
|
ImGui::PushFont(main_windows_system_chinese_font_);
|
||||||
|
if (ImGui::Button(display_path.c_str(),
|
||||||
|
ImVec2(title_bar_button_width_ * 2.0f, 0))) {
|
||||||
|
const char* folder =
|
||||||
|
tinyfd_selectFolderDialog(localization::file_transfer_save_path
|
||||||
|
[localization_language_index_]
|
||||||
|
.c_str(),
|
||||||
|
strlen(file_transfer_save_path_buf_) > 0
|
||||||
|
? file_transfer_save_path_buf_
|
||||||
|
: nullptr);
|
||||||
|
if (folder) {
|
||||||
|
strncpy(file_transfer_save_path_buf_, folder,
|
||||||
|
sizeof(file_transfer_save_path_buf_) - 1);
|
||||||
|
file_transfer_save_path_buf_[sizeof(file_transfer_save_path_buf_) -
|
||||||
|
1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered() &&
|
||||||
|
strlen(file_transfer_save_path_buf_) > 0) {
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
|
ImGui::Text("%s", file_transfer_save_path_buf_);
|
||||||
|
ImGui::SetWindowFontScale(1.0f);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
ImGui::PopFont();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
|
||||||
if (stream_window_inited_) {
|
if (stream_window_inited_) {
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
@@ -469,6 +533,10 @@ int Render::SettingWindow() {
|
|||||||
enable_minimize_to_tray_last_ = enable_minimize_to_tray_;
|
enable_minimize_to_tray_last_ = enable_minimize_to_tray_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// File transfer save path
|
||||||
|
config_center_->SetFileTransferSavePath(file_transfer_save_path_buf_);
|
||||||
|
file_transfer_save_path_last_ = file_transfer_save_path_buf_;
|
||||||
|
|
||||||
settings_window_pos_reset_ = true;
|
settings_window_pos_reset_ = true;
|
||||||
|
|
||||||
// Recreate peer instance
|
// Recreate peer instance
|
||||||
@@ -516,6 +584,13 @@ int Render::SettingWindow() {
|
|||||||
enable_turn_ = enable_turn_last_;
|
enable_turn_ = enable_turn_last_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore file transfer save path
|
||||||
|
strncpy(file_transfer_save_path_buf_,
|
||||||
|
file_transfer_save_path_last_.c_str(),
|
||||||
|
sizeof(file_transfer_save_path_buf_) - 1);
|
||||||
|
file_transfer_save_path_buf_[sizeof(file_transfer_save_path_buf_) - 1] =
|
||||||
|
'\0';
|
||||||
|
|
||||||
settings_window_pos_reset_ = true;
|
settings_window_pos_reset_ = true;
|
||||||
}
|
}
|
||||||
ImGui::SetWindowFontScale(0.5f);
|
ImGui::SetWindowFontScale(0.5f);
|
||||||
|
|||||||
@@ -28,98 +28,6 @@ std::vector<std::string> GetRootEntries() {
|
|||||||
return roots;
|
return roots;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Render::ShowSimpleFileBrowser() {
|
|
||||||
std::string display_text;
|
|
||||||
|
|
||||||
if (selected_current_file_path_.empty()) {
|
|
||||||
selected_current_file_path_ = std::filesystem::current_path().string();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tls_cert_path_self_.empty()) {
|
|
||||||
display_text =
|
|
||||||
std::filesystem::path(tls_cert_path_self_).filename().string();
|
|
||||||
} else if (selected_current_file_path_ != "Root") {
|
|
||||||
display_text =
|
|
||||||
std::filesystem::path(selected_current_file_path_).filename().string();
|
|
||||||
if (display_text.empty()) {
|
|
||||||
display_text = selected_current_file_path_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (display_text.empty()) {
|
|
||||||
display_text =
|
|
||||||
localization::select_a_file[localization_language_index_].c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_file_browser_) {
|
|
||||||
ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
|
|
||||||
|
|
||||||
float fixed_width = title_bar_button_width_ * 3.8f;
|
|
||||||
ImGui::SetNextItemWidth(fixed_width);
|
|
||||||
ImGui::SetNextWindowSizeConstraints(ImVec2(fixed_width, 0),
|
|
||||||
ImVec2(fixed_width, 100.0f));
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("##select_a_file", display_text.c_str(), 0)) {
|
|
||||||
ImGui::SetWindowFontScale(0.5f);
|
|
||||||
bool file_selected = false;
|
|
||||||
|
|
||||||
auto roots = GetRootEntries();
|
|
||||||
if (selected_current_file_path_ == "Root" ||
|
|
||||||
!std::filesystem::exists(selected_current_file_path_) ||
|
|
||||||
!std::filesystem::is_directory(selected_current_file_path_)) {
|
|
||||||
for (const auto& root : roots) {
|
|
||||||
if (ImGui::Selectable(root.c_str())) {
|
|
||||||
selected_current_file_path_ = root;
|
|
||||||
tls_cert_path_self_.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::filesystem::path p(selected_current_file_path_);
|
|
||||||
|
|
||||||
if (ImGui::Selectable("..")) {
|
|
||||||
if (std::find(roots.begin(), roots.end(),
|
|
||||||
selected_current_file_path_) != roots.end()) {
|
|
||||||
selected_current_file_path_ = "Root";
|
|
||||||
} else if (p.has_parent_path()) {
|
|
||||||
selected_current_file_path_ = p.parent_path().string();
|
|
||||||
} else {
|
|
||||||
selected_current_file_path_ = "Root";
|
|
||||||
}
|
|
||||||
tls_cert_path_self_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (const auto& entry : std::filesystem::directory_iterator(
|
|
||||||
selected_current_file_path_)) {
|
|
||||||
std::string name = entry.path().filename().string();
|
|
||||||
if (entry.is_directory()) {
|
|
||||||
if (ImGui::Selectable(name.c_str())) {
|
|
||||||
selected_current_file_path_ = entry.path().string();
|
|
||||||
tls_cert_path_self_.clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ImGui::Selectable(name.c_str())) {
|
|
||||||
tls_cert_path_self_ = entry.path().string();
|
|
||||||
file_selected = true;
|
|
||||||
show_file_browser_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error: %s", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
ImGui::PopItemFlag();
|
|
||||||
} else {
|
|
||||||
show_file_browser_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Render::SelfHostedServerWindow() {
|
int Render::SelfHostedServerWindow() {
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
if (show_self_hosted_server_config_window_) {
|
if (show_self_hosted_server_config_window_) {
|
||||||
@@ -128,12 +36,12 @@ int Render::SelfHostedServerWindow() {
|
|||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.298f, io.DisplaySize.y * 0.25f));
|
ImVec2(io.DisplaySize.x * 0.298f, io.DisplaySize.y * 0.25f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.41f));
|
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.35f));
|
||||||
} else {
|
} else {
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(io.DisplaySize.x * 0.27f, io.DisplaySize.y * 0.3f));
|
ImVec2(io.DisplaySize.x * 0.27f, io.DisplaySize.y * 0.3f));
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(io.DisplaySize.x * 0.465f, io.DisplaySize.y * 0.41f));
|
ImVec2(io.DisplaySize.x * 0.465f, io.DisplaySize.y * 0.35f));
|
||||||
}
|
}
|
||||||
|
|
||||||
self_hosted_server_config_window_pos_reset_ = false;
|
self_hosted_server_config_window_pos_reset_ = false;
|
||||||
@@ -212,35 +120,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
IM_ARRAYSIZE(coturn_server_port_self_));
|
IM_ARRAYSIZE(coturn_server_port_self_));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// {
|
|
||||||
// ImGui::AlignTextToFramePadding();
|
|
||||||
// ImGui::Text(
|
|
||||||
// "%s",
|
|
||||||
// localization::reset_cert_fingerprint[localization_language_index_]
|
|
||||||
// .c_str());
|
|
||||||
// ImGui::SameLine();
|
|
||||||
// if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
|
|
||||||
// ImGui::SetCursorPosX(title_bar_button_width_ * 2.5f);
|
|
||||||
// } else {
|
|
||||||
// ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
|
|
||||||
// }
|
|
||||||
// ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
|
|
||||||
|
|
||||||
// ShowSimpleFileBrowser();
|
|
||||||
// }
|
|
||||||
|
|
||||||
{
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
if (ImGui::Button(localization::reset_cert_fingerprint
|
|
||||||
[localization_language_index_]
|
|
||||||
.c_str())) {
|
|
||||||
config_center_->ClearCertFingerprint();
|
|
||||||
LOG_INFO("Certificate fingerprint cleared by user");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_window_inited_) {
|
if (stream_window_inited_) {
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
@@ -263,7 +142,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
config_center_->SetServerHost(signal_server_ip_self_);
|
config_center_->SetServerHost(signal_server_ip_self_);
|
||||||
config_center_->SetServerPort(atoi(signal_server_port_self_));
|
config_center_->SetServerPort(atoi(signal_server_port_self_));
|
||||||
config_center_->SetCoturnServerPort(atoi(coturn_server_port_self_));
|
config_center_->SetCoturnServerPort(atoi(coturn_server_port_self_));
|
||||||
config_center_->SetCertFilePath(tls_cert_path_self_);
|
|
||||||
strncpy(signal_server_ip_, signal_server_ip_self_,
|
strncpy(signal_server_ip_, signal_server_ip_self_,
|
||||||
sizeof(signal_server_ip_) - 1);
|
sizeof(signal_server_ip_) - 1);
|
||||||
signal_server_ip_[sizeof(signal_server_ip_) - 1] = '\0';
|
signal_server_ip_[sizeof(signal_server_ip_) - 1] = '\0';
|
||||||
@@ -273,9 +151,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
strncpy(coturn_server_port_, coturn_server_port_self_,
|
strncpy(coturn_server_port_, coturn_server_port_self_,
|
||||||
sizeof(coturn_server_port_) - 1);
|
sizeof(coturn_server_port_) - 1);
|
||||||
coturn_server_port_[sizeof(coturn_server_port_) - 1] = '\0';
|
coturn_server_port_[sizeof(coturn_server_port_) - 1] = '\0';
|
||||||
strncpy(cert_file_path_, tls_cert_path_self_.c_str(),
|
|
||||||
sizeof(cert_file_path_) - 1);
|
|
||||||
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
|
|
||||||
|
|
||||||
self_hosted_server_config_window_pos_reset_ = true;
|
self_hosted_server_config_window_pos_reset_ = true;
|
||||||
}
|
}
|
||||||
@@ -306,7 +181,6 @@ int Render::SelfHostedServerWindow() {
|
|||||||
} else {
|
} else {
|
||||||
coturn_server_port_self_[0] = '\0';
|
coturn_server_port_self_[0] = '\0';
|
||||||
}
|
}
|
||||||
tls_cert_path_self_ = config_center_->GetCertFilePath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SetWindowFontScale(1.0f);
|
ImGui::SetWindowFontScale(1.0f);
|
||||||
|
|||||||
@@ -117,7 +117,9 @@ int Render::StreamWindow() {
|
|||||||
ImGui::SetWindowFontScale(0.6f);
|
ImGui::SetWindowFontScale(0.6f);
|
||||||
|
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(stream_window_width_, stream_window_height_),
|
ImVec2(stream_window_width_,
|
||||||
|
stream_window_height_ -
|
||||||
|
(fullscreen_button_pressed_ ? 0 : title_bar_height_)),
|
||||||
ImGuiCond_Always);
|
ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowPos(
|
ImGui::SetNextWindowPos(
|
||||||
ImVec2(0, fullscreen_button_pressed_ ? 0 : title_bar_height_),
|
ImVec2(0, fullscreen_button_pressed_ ? 0 : title_bar_height_),
|
||||||
@@ -138,7 +140,7 @@ int Render::StreamWindow() {
|
|||||||
UpdateRenderRect();
|
UpdateRenderRect();
|
||||||
|
|
||||||
ControlWindow(props);
|
ControlWindow(props);
|
||||||
|
|
||||||
// Show file transfer window if needed
|
// Show file transfer window if needed
|
||||||
FileTransferWindow(props);
|
FileTransferWindow(props);
|
||||||
|
|
||||||
@@ -151,12 +153,12 @@ int Render::StreamWindow() {
|
|||||||
// std::unique_lock unique_lock(client_properties_mutex_);
|
// std::unique_lock unique_lock(client_properties_mutex_);
|
||||||
auto erase_it = client_properties_.find(remote_id_to_erase);
|
auto erase_it = client_properties_.find(remote_id_to_erase);
|
||||||
if (erase_it != client_properties_.end()) {
|
if (erase_it != client_properties_.end()) {
|
||||||
erase_it = client_properties_.erase(erase_it);
|
// Ensure we flush pending STREAM_REFRESH_EVENT events and
|
||||||
if (client_properties_.empty()) {
|
// clean up peer resources before erasing the entry, otherwise
|
||||||
SDL_Event event;
|
// SDL events may still hold raw pointers to freed
|
||||||
event.type = SDL_EVENT_QUIT;
|
// SubStreamWindowProperties (including video_frame_mutex_),
|
||||||
SDL_PushEvent(&event);
|
// leading to std::system_error when locking.
|
||||||
}
|
CloseTab(erase_it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lock.lock();
|
// lock.lock();
|
||||||
@@ -217,7 +219,9 @@ int Render::StreamWindow() {
|
|||||||
|
|
||||||
if (props->tab_selected_) {
|
if (props->tab_selected_) {
|
||||||
ImGui::SetNextWindowSize(
|
ImGui::SetNextWindowSize(
|
||||||
ImVec2(stream_window_width_, stream_window_height_),
|
ImVec2(stream_window_width_,
|
||||||
|
stream_window_height_ -
|
||||||
|
(fullscreen_button_pressed_ ? 0 : title_bar_height_)),
|
||||||
ImGuiCond_Always);
|
ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||||
@@ -236,10 +240,10 @@ int Render::StreamWindow() {
|
|||||||
UpdateRenderRect();
|
UpdateRenderRect();
|
||||||
|
|
||||||
ControlWindow(props);
|
ControlWindow(props);
|
||||||
|
|
||||||
// Show file transfer window if needed
|
// Show file transfer window if needed
|
||||||
FileTransferWindow(props);
|
FileTransferWindow(props);
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
if (!props->peer_) {
|
if (!props->peer_) {
|
||||||
@@ -251,12 +255,7 @@ int Render::StreamWindow() {
|
|||||||
// std::unique_lock unique_lock(client_properties_mutex_);
|
// std::unique_lock unique_lock(client_properties_mutex_);
|
||||||
auto erase_it = client_properties_.find(remote_id_to_erase);
|
auto erase_it = client_properties_.find(remote_id_to_erase);
|
||||||
if (erase_it != client_properties_.end()) {
|
if (erase_it != client_properties_.end()) {
|
||||||
client_properties_.erase(erase_it);
|
CloseTab(erase_it);
|
||||||
if (client_properties_.empty()) {
|
|
||||||
SDL_Event event;
|
|
||||||
event.type = SDL_EVENT_QUIT;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lock.lock();
|
// lock.lock();
|
||||||
|
|||||||
@@ -40,20 +40,6 @@ std::filesystem::path PathManager::GetLogPath() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path PathManager::GetCertPath() {
|
|
||||||
#ifdef _WIN32
|
|
||||||
// %APPDATA%\AppName\Certs
|
|
||||||
return GetKnownFolder(FOLDERID_RoamingAppData) / app_name_ / "certs";
|
|
||||||
#elif __APPLE__
|
|
||||||
// $HOME/Library/Application Support/AppName/certs
|
|
||||||
return GetHome() + "/Library/Application Support/" + app_name_ + "/certs";
|
|
||||||
#else
|
|
||||||
// $XDG_CONFIG_HOME/AppName/certs
|
|
||||||
return GetEnvOrDefault("XDG_CONFIG_HOME", GetHome() + "/.config") /
|
|
||||||
app_name_ / "certs";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PathManager::CreateDirectories(const std::filesystem::path& p) {
|
bool PathManager::CreateDirectories(const std::filesystem::path& p) {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
bool created = std::filesystem::create_directories(p, ec);
|
bool created = std::filesystem::create_directories(p, ec);
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ class PathManager {
|
|||||||
|
|
||||||
std::filesystem::path GetLogPath();
|
std::filesystem::path GetLogPath();
|
||||||
|
|
||||||
std::filesystem::path GetCertPath();
|
|
||||||
|
|
||||||
bool CreateDirectories(const std::filesystem::path& p);
|
bool CreateDirectories(const std::filesystem::path& p);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -97,6 +97,14 @@ class FileReceiver {
|
|||||||
|
|
||||||
const std::filesystem::path& OutputDir() const { return output_dir_; }
|
const std::filesystem::path& OutputDir() const { return output_dir_; }
|
||||||
|
|
||||||
|
void SetOutputDir(const std::filesystem::path& dir) {
|
||||||
|
output_dir_ = dir;
|
||||||
|
if (!output_dir_.empty()) {
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(output_dir_, ec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::filesystem::path GetDefaultDesktopPath();
|
static std::filesystem::path GetDefaultDesktopPath();
|
||||||
|
|
||||||
|
|||||||
Submodule submodules/minirtc updated: 27f721015b...e08d744a1c
@@ -203,4 +203,7 @@ target("crossdesk")
|
|||||||
set_kind("binary")
|
set_kind("binary")
|
||||||
add_deps("rd_log", "common", "gui")
|
add_deps("rd_log", "common", "gui")
|
||||||
add_files("src/app/*.cpp")
|
add_files("src/app/*.cpp")
|
||||||
add_includedirs("src/app", {public = true})
|
add_includedirs("src/app", {public = true})
|
||||||
|
if is_os("windows") then
|
||||||
|
add_files("scripts/windows/crossdesk.rc")
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user