1 Commits

Author SHA1 Message Date
dijunkun
288bb96e0c [feat] add implementation for WGC capture on virtual screens 2025-10-21 17:30:36 +08:00
83 changed files with 3343 additions and 3135 deletions

View File

@@ -34,11 +34,10 @@ jobs:
shell: bash
id: set_deb_version
run: |
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
LEGAL_VERSION="0.0.0-${VERSION_NUM}-${SHORT_SHA}"
LEGAL_VERSION="0.0.0-${VERSION_NUM}"
else
LEGAL_VERSION="${VERSION_NUM}-${SHORT_SHA}"
LEGAL_VERSION="${VERSION_NUM}"
fi
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
@@ -53,7 +52,6 @@ jobs:
XMAKE_GLOBALDIR: /data
run: |
ls -la $XMAKE_GLOBALDIR
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --root -y
xmake b -vy --root crossdesk
- name: Decode and save certificate
@@ -98,11 +96,10 @@ jobs:
shell: bash
id: set_deb_version
run: |
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
if [[ ! "${VERSION_NUM}" =~ ^[0-9] ]]; then
LEGAL_VERSION="0.0.0-${VERSION_NUM}-${SHORT_SHA}"
LEGAL_VERSION="0.0.0-${VERSION_NUM}"
else
LEGAL_VERSION="${VERSION_NUM}-${SHORT_SHA}"
LEGAL_VERSION="${VERSION_NUM}"
fi
echo "LEGAL_VERSION=${LEGAL_VERSION}" >> $GITHUB_ENV
@@ -116,7 +113,6 @@ jobs:
CUDA_PATH: /usr/local/cuda
XMAKE_GLOBALDIR: /data
run: |
xmake f --CROSSDESK_VERSION=${LEGAL_VERSION} --root -y
xmake b -vy --root crossdesk
- name: Decode and save certificate
@@ -144,7 +140,7 @@ jobs:
matrix:
include:
- arch: x64
runner: macos-13
runner: macos-15-intel
cache-key: intel
out-dir: ./build/macosx/x86_64/release/crossdesk
package_script: ./scripts/macosx/pkg_x64.sh
@@ -159,8 +155,7 @@ jobs:
id: version
run: |
VERSION="${GITHUB_REF##*/}"
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
VERSION_NUM="${VERSION#v}-${SHORT_SHA}"
VERSION_NUM="${VERSION#v}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_ENV
echo "VERSION_NUM=${VERSION_NUM}"
@@ -182,9 +177,7 @@ jobs:
run: git submodule update --init --recursive
- name: Build CrossDesk
run: |
xmake f --CROSSDESK_VERSION=${VERSION_NUM} -y
xmake b -vy crossdesk
run: xmake b -vy crossdesk
- name: Decode and save certificate
shell: bash
@@ -222,8 +215,7 @@ jobs:
$version = $ref -replace '^refs/(tags|heads)/', ''
$version = $version -replace '^v', ''
$version = $version -replace '/', '-'
$SHORT_SHA = $env:GITHUB_SHA.Substring(0,7)
echo "VERSION_NUM=$version-$SHORT_SHA" >> $env:GITHUB_ENV
echo "VERSION_NUM=$version" >> $env:GITHUB_ENV
- name: Cache xmake dependencies
uses: actions/cache@v4
@@ -289,10 +281,8 @@ jobs:
copy "${{ github.workspace }}\scripts\windows\nsProcess.dll" $nsisPluginDir
- name: Build CrossDesk
run: |
xmake f --CROSSDESK_VERSION=${{ env.VERSION_NUM }} -y
xmake b -vy crossdesk
run: xmake b -vy crossdesk
- name: Decode and save certificate
shell: powershell
run: |
@@ -331,8 +321,7 @@ jobs:
id: version
run: |
VERSION="${GITHUB_REF##*/}"
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
VERSION_NUM="${VERSION#v}-${SHORT_SHA}"
VERSION_NUM="${VERSION#v}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_OUTPUT
- name: Rename artifacts

View File

@@ -5,11 +5,6 @@ on:
# run every day at midnight
- cron: "0 0 * * *"
permissions:
issues: write
pull-requests: write
contents: read
jobs:
close_inactive_issues:
runs-on: ubuntu-latest
@@ -22,59 +17,26 @@ jobs:
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100,
});
const now = new Date().getTime();
const inactivePeriod = 7 * 24 * 60 * 60 * 1000; // 7 days
for (const issue of issues) {
// skip pull requests (they are also returned by listForRepo)
if (issue.pull_request) continue;
// skip labeled issues
if (issue.labels.length > 0) {
console.log(`Skipping issue #${issue.number} (Has labels).`);
continue;
}
// fetch comments for this issue
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
per_page: 100,
});
// determine the "last activity" time
let lastActivityTime;
if (comments.length > 0) {
const lastComment = comments[comments.length - 1];
lastActivityTime = new Date(lastComment.updated_at).getTime();
} else {
lastActivityTime = new Date(issue.created_at).getTime();
}
// check inactivity
if (now - lastActivityTime > inactivePeriod) {
console.log(`Closing inactive issue: #${issue.number} (No recent replies for 7 days)`);
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: "This issue has been automatically closed due to inactivity for 7 days."
});
const lastUpdated = new Date(issue.updated_at).getTime();
// if the issue hasn't been updated in the past week, close it
if (now - lastUpdated > inactivePeriod && issue.labels.length === 0) {
console.log(`Closing inactive issue: ${issue.number} (No labels)`);
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
});
} else if (issue.labels.length === 0) {
console.log(`Skipping issue ${issue.number} (No labels) as it has been recently updated.`);
} else {
console.log(`Skipping issue #${issue.number} (Active within 7 days).`);
console.log(`Skipping issue ${issue.number} (Has labels).`);
}
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,9 +15,8 @@ jobs:
- name: Set version number
id: version
run: |
SHORT_SHA=$(echo "${GITHUB_SHA}" | cut -c1-7)
VERSION_NUM="${GITHUB_REF##*/}"
VERSION_NUM="${VERSION_NUM#v}-${SHORT_SHA}"
VERSION_NUM="${VERSION_NUM#v}"
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_ENV
echo "VERSION_NUM=${VERSION_NUM}" >> $GITHUB_OUTPUT
@@ -31,13 +30,11 @@ jobs:
- name: Update download links
run: |
cd pages
echo "Updating download links to ${VERSION_NUM}"
sed -E -i "s/crossdesk-win-x64-[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?\.exe/crossdesk-win-x64-${VERSION_NUM}.exe/g" index.html
sed -E -i "s/crossdesk-macos-x64-[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?\.pkg/crossdesk-macos-x64-${VERSION_NUM}.pkg/g" index.html
sed -E -i "s/crossdesk-macos-arm64-[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?\.pkg/crossdesk-macos-arm64-${VERSION_NUM}.pkg/g" index.html
sed -E -i "s/crossdesk-linux-amd64-[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?\.deb/crossdesk-linux-amd64-${VERSION_NUM}.deb/g" index.html
sed -E -i "s/crossdesk-linux-arm64-[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9._-]+)?\.deb/crossdesk-linux-arm64-${VERSION_NUM}.deb/g" index.html
git diff index.html || true
sed -E -i "s/crossdesk-win-x64-[0-9]+\.[0-9]+\.[0-9]+\.exe/crossdesk-win-x64-${VERSION_NUM}.exe/g" index.html
sed -E -i "s/crossdesk-macos-x64-[0-9]+\.[0-9]+\.[0-9]+\.pkg/crossdesk-macos-x64-${VERSION_NUM}.pkg/g" index.html
sed -E -i "s/crossdesk-macos-arm64-[0-9]+\.[0-9]+\.[0-9]+\.pkg/crossdesk-macos-arm64-${VERSION_NUM}.pkg/g" index.html
sed -E -i "s/crossdesk-linux-amd64-[0-9]+\.[0-9]+\.[0-9]+\.deb/crossdesk-linux-amd64-${VERSION_NUM}.deb/g" index.html
sed -E -i "s/crossdesk-linux-arm64-[0-9]+\.[0-9]+\.[0-9]+\.deb/crossdesk-linux-arm64-${VERSION_NUM}.deb/g" index.html
- name: Commit & Push changes
run: |

4
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "submodules/minirtc"]
path = submodules/minirtc
[submodule "thirdparty/minirtc"]
path = thirdparty/minirtc
url = https://github.com/kunkundi/minirtc.git

View File

@@ -1,9 +1,9 @@
# CrossDesk
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-brightgreen.svg)]()
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
[![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/self-hosted-server)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yaml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Docker Pulls](https://img.shields.io/docker/pulls/crossdesk/crossdesk-server)](https://hub.docker.com/r/crossdesk/crossdesk-server/tags)
[![GitHub issues](https://img.shields.io/github/issues/kunkundi/crossdesk.svg)]()
[![GitHub stars](https://img.shields.io/github/stars/kunkundi/crossdesk.svg?style=social)]()
@@ -65,7 +65,7 @@ xmake r crossdesk
### 无 CUDA 环境下的开发支持
对于**未安装 CUDA 环境的 Linux 开发者**,这里提供了预配置的 [Ubuntu 22.04 Docker 镜像](https://hub.docker.com/r/crossdesk/ubuntu22.04)。该镜像内置必要的构建依赖,可在容器中开箱即用,无需额外配置即可直接编译项目。
对于未安装 **CUDA 环境** 的 Linux 开发者,这里提供了预配置的 [Ubuntu 22.04 Docker 镜像](https://hub.docker.com/r/crossdesk/ubuntu22.04)。该镜像内置必要的构建依赖,可在容器中开箱即用,无需额外配置即可直接编译项目。
进入容器,下载工程后执行:
```
@@ -75,7 +75,7 @@ export XMAKE_GLOBALDIR=/data
xmake b --root -vy crossdesk
```
对于**未安装 CUDA 环境的 Windows 开发者**,执行下面的命令安装 CUDA 编译环境:
对于未安装 **CUDA 环境** 的 Windows 开发者,执行下面的命令安装 CUDA 编译环境:
```
xmake require -vy "cuda 12.6.3"
```
@@ -146,14 +146,11 @@ sudo docker run -d \
--network host \
-e EXTERNAL_IP=xxx.xxx.xxx.xxx \
-e INTERNAL_IP=xxx.xxx.xxx.xxx \
-e CROSSDESK_SERVER_PORT=xxxx \
-e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \
-e CROSSDESK_SERVER_PORT=9099 \
-v /path/to/your/certs:/crossdesk-server/certs \
-v /path/to/your/db:/crossdesk-server/db \
-v /path/to/your/logs:/crossdesk-server/logs \
crossdesk/crossdesk-server:v1.0.0
crossdesk/crossdesk-server:latest
```
上述命令中,用户需注意的参数如下:
@@ -164,10 +161,6 @@ sudo docker run -d \
- CROSSDESK_SERVER_PORT自托管服务使用的端口对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口**
- COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口**
- MIN_PORT/MAX_PORTCOTURN 服务使用的端口范围例如MIN_PORT=50000, MAX_PORT=60000范围可根据客户端数量调整。
- /path/to/your/certs证书文件目录
- /path/to/your/dbCrossDesk Server 设备管理数据库
@@ -176,7 +169,7 @@ sudo docker run -d \
**注意**
- **/path/to/your/ 是示例路径,请替换为你自己的实际路径。挂载的目录必须事先创建好,否则容器会报错。**
- **服务器需开放端口3478/udp3478/tcpMIN_PORT-MAX_PORT/udpCROSSDESK_SERVER_PORT/tcp。**
- **服务器需开放端口3478/udp3478/tcp30000-60000/udpCROSSDESK_SERVER_PORT/tcp443/tcp。**
## 证书文件
客户端需加载根证书文件,服务端需加载服务器私钥和服务器证书文件。
@@ -302,6 +295,3 @@ Generation complete. Deployment files::
7. 勾选使用**自托管服务器配置**,点击确认配置生效。<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br>
# 常见问题
见 [常见问题](https://github.com/kunkundi/crossdesk/blob/self-hosted-server/docs/FAQ.md) 。

View File

@@ -1,9 +1,9 @@
# CrossDesk
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-brightgreen.svg)]()
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0)
[![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/self-hosted-server)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Build Status](https://github.com/kunkundi/crossdesk/actions/workflows/build.yaml/badge.svg)](https://github.com/kunkundi/crossdesk/actions)
[![Docker Pulls](https://img.shields.io/docker/pulls/crossdesk/crossdesk-server)](https://hub.docker.com/r/crossdesk/crossdesk-server/tags)
[![GitHub issues](https://img.shields.io/github/issues/kunkundi/crossdesk.svg)]()
[![GitHub stars](https://img.shields.io/github/stars/kunkundi/crossdesk.svg?style=social)]()
@@ -65,7 +65,7 @@ xmake r crossdesk
#### Development Without CUDA Environment
For **Linux developers who do not have a CUDA environment** installed, a preconfigured [Ubuntu 22.04 Docker image](https://hub.docker.com/r/crossdesk/ubuntu22.04) is provided.
For **Linux** developers who do not have a **CUDA environment** installed, a preconfigured [Ubuntu 22.04 Docker image](https://hub.docker.com/r/crossdesk/ubuntu22.04) is provided.
This image comes with all required build dependencies and allows you to build the project directly inside the container without any additional setup.
After entering the container, download the project and run:
@@ -76,7 +76,7 @@ export XMAKE_GLOBALDIR=/data
xmake b --root -vy crossdesk
```
For **Windows developers without a CUDA environment** installed, run the following command to install the CUDA build environment:
For **Windows** developers without a **CUDA environment** installed, run the following command to install the CUDA build environment:
```
xmake require -vy "cuda 12.6.3"
```
@@ -149,16 +149,13 @@ It is recommended to deploy CrossDesk Server using Docker.
sudo docker run -d \
--name crossdesk_server \
--network host \
-e EXTERNAL_IP=xxx.xxx.xxx.xxx \
-e INTERNAL_IP=xxx.xxx.xxx.xxx \
-e CROSSDESK_SERVER_PORT=xxxx \
-e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \
-e EXTERNAL_IP=150.158.81.30 \
-e INTERNAL_IP=10.0.4.3 \
-e CROSSDESK_SERVER_PORT=9099 \
-v /path/to/your/certs:/crossdesk-server/certs \
-v /path/to/your/db:/crossdesk-server/db \
-v /path/to/your/logs:/crossdesk-server/logs \
crossdesk/crossdesk-server:v1.0.0
crossdesk/crossdesk-server:latest
```
The parameters you need to pay attention to are as follows:
@@ -169,10 +166,6 @@ The parameters you need to pay attention to are as follows:
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted server, corresponding to the **Server Port** in the CrossDesk client **Self-Hosted Server Configuration**.
- **COTURN_PORT**: The port used by Coturn, corresponding to the **Relay Server Port** in the CrossDesk client **Self-Hosted Server Configuration**.
- **MIN_PORT** and **MAX_PORT**: The range of ports used by the self-hosted server, corresponding to the **Minimum Port** and **Maximum Port** in the CrossDesk client **Self-Hosted Server Configuration**. Example: 50000-60000. It depends on the number of devices connected to the server.
- **/path/to/your/certs**: Directory for certificate files.
- **/path/to/your/db**: CrossDesk Server device management database.
@@ -181,7 +174,7 @@ The parameters you need to pay attention to are as follows:
**Note**:
- **/path/to/your/ is an example path; please replace it with your actual path. The mounted directories must be created in advance, otherwise the container will fail.**
- **The server must open the following ports: 3478/udp, 3478/tcp, 30000-60000/udp, CROSSDESK_SERVER_PORT/tcp.**
- **The server must open the following ports: 3478/udp, 3478/tcp, 30000-60000/udp, CROSSDESK_SERVER_PORT/tcp, 443/tcp.**
## Certificate Files
The client needs to load the root certificate, and the server needs to load the server private key and server certificate.
@@ -307,6 +300,3 @@ Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/y
4. Check the option to use **Self-Hosted Server Configuration**.<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br>
# FAQ
See [FAQ](https://github.com/kunkundi/crosssesk/blob/self-hosted-server/docs/FAQ.md) .

View File

@@ -1,33 +0,0 @@
# 常见问题FAQ
欢迎来到 **CrossDesk 常见问题** 页面!
这里整理了用户和开发者最常见的一些疑问。如果你没有找到答案,欢迎在 [Issues](https://github.com/kunkundi/crossdesk/issues) 中反馈。
---
### Q1. 对等连接失败
**A:**
打开设置,勾选 **启用中继服务** 选项,尝试重新发起连接。
<img width="396" height="306" alt="Image" src="https://github.com/user-attachments/assets/fd8db148-c782-4f4d-b874-8f1b2a7ec7d6" />
由于公共中继服务器带宽较小,连接的清晰度流畅度可能会下降,建议自建服务器。 [Issue #8](https://github.com/kunkundi/crossdesk/issues/8)
### Q2. Windows 无 CUDA 环境下编译
**A:**
运行下面的命令安装 CUDA 编译环境。
```
xmake require -vy "cuda 12.6.3"
```
安装完成后执行
```
xmake require --info "cuda 12.6.3"
```
输出如下
<img width="860" height="226" alt="Image" src="https://github.com/user-attachments/assets/999ac365-581a-4b9a-806e-05eb3e4cf44d" />
根据上述输出获取到 CUDA 的安装目录,即 installdir 指向的位置。将 CUDA_PATH 加入系统环境变量,或在终端中输入 set CUDA_PATH=path_to_cuda_installdir重新执行 xmake b -vy crossdesk 即可。
[Issue #6](https://github.com/kunkundi/crossdesk/issues/6)
---

View File

@@ -9,8 +9,8 @@
#include "rd_log.h"
#include "render.h"
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
crossdesk::Render render;
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) {
Render render;
render.Run();
return 0;

View File

@@ -9,8 +9,6 @@
#include <string>
namespace crossdesk {
class DisplayInfo {
public:
DisplayInfo(std::string name, int left, int top, int right, int bottom)
@@ -42,5 +40,5 @@ class DisplayInfo {
int width = 0;
int height = 0;
};
} // namespace crossdesk
#endif

View File

@@ -19,8 +19,6 @@
#include <unistd.h>
#endif
namespace crossdesk {
std::string GetMac() {
char mac_addr[16];
int len = 0;
@@ -41,21 +39,21 @@ std::string GetMac() {
#elif __APPLE__
std::string if_name = "en0";
struct ifaddrs* addrs;
struct ifaddrs* cursor;
const struct sockaddr_dl* dlAddr;
struct ifaddrs *addrs;
struct ifaddrs *cursor;
const struct sockaddr_dl *dlAddr;
if (!getifaddrs(&addrs)) {
cursor = addrs;
while (cursor != 0) {
const struct sockaddr_dl* socAddr =
(const struct sockaddr_dl*)cursor->ifa_addr;
const struct sockaddr_dl *socAddr =
(const struct sockaddr_dl *)cursor->ifa_addr;
if ((cursor->ifa_addr->sa_family == AF_LINK) &&
(socAddr->sdl_type == IFT_ETHER) &&
strcmp(if_name.c_str(), cursor->ifa_name) == 0) {
dlAddr = (const struct sockaddr_dl*)cursor->ifa_addr;
const unsigned char* base =
(const unsigned char*)&dlAddr->sdl_data[dlAddr->sdl_nlen];
dlAddr = (const struct sockaddr_dl *)cursor->ifa_addr;
const unsigned char *base =
(const unsigned char *)&dlAddr->sdl_data[dlAddr->sdl_nlen];
for (int i = 0; i < dlAddr->sdl_alen; i++) {
len +=
snprintf(mac_addr + len, sizeof(mac_addr) - len, "%.2X", base[i]);
@@ -79,8 +77,8 @@ std::string GetMac() {
close(sock);
return "";
}
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
struct ifreq *it = ifc.ifc_req;
const struct ifreq *const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it) {
std::strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
@@ -124,5 +122,4 @@ std::string GetHostName() {
}
#endif
return hostname;
}
} // namespace crossdesk
}

View File

@@ -9,10 +9,7 @@
#include <iostream>
namespace crossdesk {
std::string GetMac();
std::string GetHostName();
} // namespace crossdesk
#endif

View File

@@ -1,7 +1,5 @@
#include "config_center.h"
namespace crossdesk {
ConfigCenter::ConfigCenter(const std::string& config_path,
const std::string& cert_file_path)
: config_path_(config_path),
@@ -38,20 +36,14 @@ int ConfigCenter::Load() {
enable_turn_ = ini_.GetBoolValue(section_, "enable_turn", enable_turn_);
enable_srtp_ = ini_.GetBoolValue(section_, "enable_srtp", enable_srtp_);
signal_server_host_ = ini_.GetValue(section_, "signal_server_host",
signal_server_host_.c_str());
signal_server_port_ = static_cast<int>(
ini_.GetLongValue(section_, "signal_server_port", signal_server_port_));
coturn_server_port_ = static_cast<int>(
ini_.GetLongValue(section_, "coturn_server_port", coturn_server_port_));
server_host_ = ini_.GetValue(section_, "server_host", server_host_.c_str());
server_port_ = static_cast<int>(
ini_.GetLongValue(section_, "server_port", server_port_));
cert_file_path_ =
ini_.GetValue(section_, "cert_file_path", cert_file_path_.c_str());
enable_self_hosted_ =
ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
enable_minimize_to_tray_ = ini_.GetBoolValue(
section_, "enable_minimize_to_tray", enable_minimize_to_tray_);
return 0;
}
@@ -66,13 +58,10 @@ int ConfigCenter::Save() {
ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_);
ini_.SetBoolValue(section_, "enable_turn", enable_turn_);
ini_.SetBoolValue(section_, "enable_srtp", enable_srtp_);
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
ini_.SetLongValue(section_, "signal_server_port",
static_cast<long>(signal_server_port_));
ini_.SetValue(section_, "server_host", server_host_.c_str());
ini_.SetLongValue(section_, "server_port", static_cast<long>(server_port_));
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
enable_minimize_to_tray_);
SI_Error rc = ini_.SaveFile(config_path_.c_str());
if (rc < 0) {
@@ -158,9 +147,9 @@ int ConfigCenter::SetSrtp(bool enable_srtp) {
return 0;
}
int ConfigCenter::SetServerHost(const std::string& signal_server_host) {
signal_server_host_ = signal_server_host;
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
int ConfigCenter::SetServerHost(const std::string& server_host) {
server_host_ = server_host;
ini_.SetValue(section_, "server_host", server_host_.c_str());
SI_Error rc = ini_.SaveFile(config_path_.c_str());
if (rc < 0) {
return -1;
@@ -168,10 +157,9 @@ int ConfigCenter::SetServerHost(const std::string& signal_server_host) {
return 0;
}
int ConfigCenter::SetServerPort(int signal_server_port) {
signal_server_port_ = signal_server_port;
ini_.SetLongValue(section_, "signal_server_port",
static_cast<long>(signal_server_port_));
int ConfigCenter::SetServerPort(int server_port) {
server_port_ = server_port;
ini_.SetLongValue(section_, "server_port", static_cast<long>(server_port_));
SI_Error rc = ini_.SaveFile(config_path_.c_str());
if (rc < 0) {
return -1;
@@ -179,16 +167,6 @@ int ConfigCenter::SetServerPort(int signal_server_port) {
return 0;
}
int ConfigCenter::SetCoturnServerPort(int coturn_server_port) {
coturn_server_port_ = coturn_server_port;
SI_Error rc = ini_.SetLongValue(section_, "coturn_server_port",
static_cast<long>(coturn_server_port_));
if (rc < 0) {
return -1;
}
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());
@@ -208,11 +186,6 @@ int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
return 0;
}
int ConfigCenter::SetMinimizeToTray(bool enable_minimize_to_tray) {
enable_minimize_to_tray_ = enable_minimize_to_tray;
return 0;
}
// getters
ConfigCenter::LANGUAGE ConfigCenter::GetLanguage() const { return language_; }
@@ -237,33 +210,20 @@ bool ConfigCenter::IsEnableTurn() const { return enable_turn_; }
bool ConfigCenter::IsEnableSrtp() const { return enable_srtp_; }
std::string ConfigCenter::GetSignalServerHost() const {
return signal_server_host_;
}
std::string ConfigCenter::GetServerHost() const { return server_host_; }
int ConfigCenter::GetSignalServerPort() const { return signal_server_port_; }
int ConfigCenter::GetCoturnServerPort() const { return coturn_server_port_; }
int ConfigCenter::GetServerPort() const { return server_port_; }
std::string ConfigCenter::GetCertFilePath() const { return cert_file_path_; }
std::string ConfigCenter::GetDefaultServerHost() const {
return signal_server_host_default_;
return server_host_default_;
}
int ConfigCenter::GetDefaultSignalServerPort() const {
return server_port_default_;
}
int ConfigCenter::GetDefaultCoturnServerPort() const {
return coturn_server_port_default_;
}
int ConfigCenter::GetDefaultServerPort() const { return server_port_default_; }
std::string ConfigCenter::GetDefaultCertFilePath() const {
return cert_file_path_default_;
}
bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; }
bool ConfigCenter::IsMinimizeToTray() const { return enable_minimize_to_tray_; }
} // namespace crossdesk
bool ConfigCenter::IsSelfHosted() const { return enable_self_hosted_; }

View File

@@ -11,8 +11,6 @@
#include "SimpleIni.h"
namespace crossdesk {
class ConfigCenter {
public:
enum class LANGUAGE { CHINESE = 0, ENGLISH = 1 };
@@ -34,12 +32,10 @@ class ConfigCenter {
int SetHardwareVideoCodec(bool hardware_video_codec);
int SetTurn(bool enable_turn);
int SetSrtp(bool enable_srtp);
int SetServerHost(const std::string& signal_server_host);
int SetServerPort(int signal_server_port);
int SetCoturnServerPort(int coturn_server_port);
int SetServerHost(const std::string& server_host);
int SetServerPort(int server_port);
int SetCertFilePath(const std::string& cert_file_path);
int SetSelfHosted(bool enable_self_hosted);
int SetMinimizeToTray(bool enable_minimize_to_tray);
// read config
@@ -50,16 +46,13 @@ class ConfigCenter {
bool IsHardwareVideoCodec() const;
bool IsEnableTurn() const;
bool IsEnableSrtp() const;
std::string GetSignalServerHost() const;
int GetSignalServerPort() const;
int GetCoturnServerPort() const;
std::string GetServerHost() const;
int GetServerPort() const;
std::string GetCertFilePath() const;
std::string GetDefaultServerHost() const;
int GetDefaultSignalServerPort() const;
int GetDefaultCoturnServerPort() const;
int GetDefaultServerPort() const;
std::string GetDefaultCertFilePath() const;
bool IsSelfHosted() const;
bool IsMinimizeToTray() const;
int Load();
int Save();
@@ -77,15 +70,12 @@ class ConfigCenter {
bool hardware_video_codec_ = false;
bool enable_turn_ = false;
bool enable_srtp_ = false;
std::string signal_server_host_ = "api.crossdesk.cn";
std::string signal_server_host_default_ = "api.crossdesk.cn";
int signal_server_port_ = 9099;
std::string server_host_ = "api.crossdesk.cn";
int server_port_ = 9099;
std::string server_host_default_ = "api.crossdesk.cn";
int server_port_default_ = 9099;
int coturn_server_port_ = 3478;
int coturn_server_port_default_ = 3478;
std::string cert_file_path_default_ = "";
bool enable_self_hosted_ = false;
bool enable_minimize_to_tray_ = false;
};
} // namespace crossdesk
#endif

View File

@@ -11,8 +11,6 @@
#include "display_info.h"
namespace crossdesk {
typedef enum {
mouse = 0,
keyboard,
@@ -81,5 +79,5 @@ class DeviceController {
// virtual int Hook();
// virtual int Unhook();
};
} // namespace crossdesk
#endif

View File

@@ -11,8 +11,6 @@
#include "keyboard_capturer.h"
#include "mouse_controller.h"
namespace crossdesk {
class DeviceControllerFactory {
public:
enum Device { Mouse = 0, Keyboard };
@@ -32,5 +30,5 @@ class DeviceControllerFactory {
}
}
};
} // namespace crossdesk
#endif

View File

@@ -3,8 +3,6 @@
#include "keyboard_converter.h"
#include "rd_log.h"
namespace crossdesk {
static OnKeyAction g_on_key_action = nullptr;
static void* g_user_ptr = nullptr;
@@ -69,4 +67,3 @@ int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
}
return 0;
}
} // namespace crossdesk

View File

@@ -13,22 +13,20 @@
#include "device_controller.h"
namespace crossdesk {
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void* user_ptr);
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
private:
Display* display_;
Display *display_;
Window root_;
bool running_;
};
} // namespace crossdesk
#endif

View File

@@ -3,14 +3,12 @@
#include "keyboard_converter.h"
#include "rd_log.h"
namespace crossdesk {
static OnKeyAction g_on_key_action = nullptr;
static void* g_user_ptr = nullptr;
static void *g_user_ptr = nullptr;
CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type,
CGEventRef event, void* userInfo) {
KeyboardCapturer* keyboard_capturer = (KeyboardCapturer*)userInfo;
CGEventRef event, void *userInfo) {
KeyboardCapturer *keyboard_capturer = (KeyboardCapturer *)userInfo;
if (!keyboard_capturer) {
LOG_ERROR("keyboard_capturer is nullptr");
return event;
@@ -93,7 +91,7 @@ KeyboardCapturer::KeyboardCapturer() {}
KeyboardCapturer::~KeyboardCapturer() {}
int KeyboardCapturer::Hook(OnKeyAction on_key_action, void* user_ptr) {
int KeyboardCapturer::Hook(OnKeyAction on_key_action, void *user_ptr) {
g_on_key_action = on_key_action;
g_user_ptr = user_ptr;
@@ -166,5 +164,4 @@ int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -11,15 +11,13 @@
#include "device_controller.h"
namespace crossdesk {
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void* user_ptr);
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
@@ -35,5 +33,5 @@ class KeyboardCapturer : public DeviceController {
bool command_flag_ = false;
int fn_key_code_ = 0x3F;
};
} // namespace crossdesk
#endif

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
namespace crossdesk {
static OnKeyAction g_on_key_action = nullptr;
static void* g_user_ptr = nullptr;
@@ -55,5 +53,4 @@ int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
SendInput(1, &input, sizeof(INPUT));
return 0;
}
} // namespace crossdesk
}

View File

@@ -11,21 +11,18 @@
#include "device_controller.h"
namespace crossdesk {
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void* user_ptr);
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
private:
HHOOK keyboard_hook_ = nullptr;
};
} // namespace crossdesk
#endif

View File

@@ -9,8 +9,6 @@
#include <map>
namespace crossdesk {
// Windows vkCode to macOS CGKeyCode (104 keys)
std::map<int, int> vkCodeToCGKeyCode = {
// A-Z
@@ -738,5 +736,5 @@ std::map<int, int> x11KeySymToCgKeyCode = {
{0xFFEB, 0x37}, // Left Command
{0xFFEC, 0x36}, // Right Command
};
} // namespace crossdesk
#endif

View File

@@ -4,8 +4,6 @@
#include "rd_log.h"
namespace crossdesk {
MouseController::MouseController() {}
MouseController::~MouseController() { Destroy(); }
@@ -123,5 +121,4 @@ void MouseController::SimulateMouseWheel(int direction_button, int count) {
XTestFakeButtonEvent(display_, direction_button, False, CurrentTime);
}
XFlush(display_);
}
} // namespace crossdesk
}

View File

@@ -15,8 +15,6 @@
#include "device_controller.h"
namespace crossdesk {
class MouseController : public DeviceController {
public:
MouseController();
@@ -39,5 +37,5 @@ class MouseController : public DeviceController {
int screen_width_ = 0;
int screen_height_ = 0;
};
} // namespace crossdesk
#endif

View File

@@ -4,8 +4,6 @@
#include "rd_log.h"
namespace crossdesk {
MouseController::MouseController() {}
MouseController::~MouseController() {}
@@ -100,5 +98,4 @@ int MouseController::SendMouseCommand(RemoteAction remote_action,
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -11,8 +11,6 @@
#include "device_controller.h"
namespace crossdesk {
class MouseController : public DeviceController {
public:
MouseController();
@@ -28,5 +26,5 @@ class MouseController : public DeviceController {
bool left_dragging_ = false;
bool right_dragging_ = false;
};
} // namespace crossdesk
#endif

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
namespace crossdesk {
MouseController::MouseController() {}
MouseController::~MouseController() {}
@@ -71,5 +69,4 @@ int MouseController::SendMouseCommand(RemoteAction remote_action,
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -11,8 +11,6 @@
#include "device_controller.h"
namespace crossdesk {
class MouseController : public DeviceController {
public:
MouseController();
@@ -26,5 +24,5 @@ class MouseController : public DeviceController {
private:
std::vector<DisplayInfo> display_info_list_;
};
} // namespace crossdesk
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -20,17 +20,12 @@
#define INPUT_WINDOW_PADDING_EN 96
#define SETTINGS_WINDOW_WIDTH_CN 202
#define SETTINGS_WINDOW_WIDTH_EN 248
#if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 345
#define SETTINGS_WINDOW_HEIGHT_EN 345
#else
#define SETTINGS_WINDOW_HEIGHT_CN 315
#define SETTINGS_WINDOW_HEIGHT_EN 315
#endif
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 195
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 195
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 165
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 165
#define LANGUAGE_SELECT_WINDOW_PADDING_CN 120
#define LANGUAGE_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120
@@ -47,8 +42,6 @@
#define ENABLE_SRTP_CHECKBOX_PADDING_EN 218
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218
#define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171
#define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90

View File

@@ -8,13 +8,6 @@
#include <string>
#include <vector>
#if _WIN32
#include <Windows.h>
#endif
namespace crossdesk {
namespace localization {
static std::vector<std::string> local_desktop = {
@@ -109,9 +102,7 @@ static std::vector<std::string> self_hosted_server_settings = {
static std::vector<std::string> self_hosted_server_address = {
reinterpret_cast<const char*>(u8"服务器地址:"), "Server Address:"};
static std::vector<std::string> self_hosted_server_port = {
reinterpret_cast<const char*>(u8"信令服务端口:"), "Signal Service 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"服务端口:"), "Server 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 = {
@@ -164,13 +155,6 @@ static std::vector<std::string> version = {
static std::vector<std::string> confirm_delete_connection = {
reinterpret_cast<const char*>(u8"确认删除此连接"),
"Confirm to delete this connection"};
#if _WIN32
static std::vector<std::string> minimize_to_tray = {
reinterpret_cast<const char*>(u8"退出时最小化到系统托盘:"),
"Minimize to system tray when exit:"};
static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"};
#endif
} // namespace localization
} // namespace crossdesk
#endif

View File

@@ -5,8 +5,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::LocalWindow() {
ImGui::SetNextWindowPos(ImVec2(-1.0f, title_bar_height_), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
@@ -289,5 +287,4 @@ int Render::LocalWindow() {
ImGui::PopStyleVar();
return 0;
}
} // namespace crossdesk
}

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::RecentConnectionsWindow() {
ImGui::SetNextWindowPos(
ImVec2(0, title_bar_height_ + local_window_height_ - 1.0f),
@@ -286,4 +284,3 @@ int Render::ConfirmDeleteConnection() {
ImGui::PopStyleVar();
return 0;
}
} // namespace crossdesk

View File

@@ -3,9 +3,7 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
static int InputTextCallback(ImGuiInputTextCallbackData* data);
static int InputTextCallback(ImGuiInputTextCallbackData *data);
int Render::RemoteWindow() {
ImGui::SetNextWindowPos(ImVec2(local_window_width_ + 1.0f, title_bar_height_),
@@ -79,7 +77,7 @@ int Render::RemoteWindow() {
enter_pressed) {
connect_button_pressed_ = true;
bool found = false;
for (auto& [id, props] : recent_connections_) {
for (auto &[id, props] : recent_connections_) {
if (id.find(remote_id) != std::string::npos) {
found = true;
if (client_properties_.find(remote_id) !=
@@ -103,7 +101,7 @@ int Render::RemoteWindow() {
if (need_to_rejoin_) {
need_to_rejoin_ = false;
for (const auto& [_, props] : client_properties_) {
for (const auto &[_, props] : client_properties_) {
if (props->rejoin_) {
ConnectTo(props->remote_id_, props->remote_password_,
props->remember_password_);
@@ -119,7 +117,7 @@ int Render::RemoteWindow() {
return 0;
}
static int InputTextCallback(ImGuiInputTextCallbackData* data) {
static int InputTextCallback(ImGuiInputTextCallbackData *data) {
if (data->BufTextLen > 3 && data->Buf[3] != ' ') {
data->InsertChars(3, " ");
}
@@ -131,7 +129,7 @@ static int InputTextCallback(ImGuiInputTextCallbackData* data) {
return 0;
}
int Render::ConnectTo(const std::string& remote_id, const char* password,
int Render::ConnectTo(const std::string &remote_id, const char *password,
bool remember_password) {
LOG_INFO("Connect to [{}]", remote_id);
focused_remote_id_ = remote_id;
@@ -180,5 +178,4 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -21,8 +21,6 @@
#define MOUSE_GRAB_PADDING 5
namespace crossdesk {
std::vector<char> Render::SerializeRemoteAction(const RemoteAction& action) {
std::vector<char> buffer;
buffer.push_back(static_cast<char>(action.type));
@@ -429,57 +427,39 @@ int Render::StopKeyboardCapturer() {
int Render::CreateConnectionPeer() {
params_.use_cfg_file = false;
std::string signal_server_ip;
int signal_server_port;
int coturn_server_port;
std::string tls_cert_path;
std::string server_ip;
int server_port;
std::string server_cert_path;
if (config_center_->IsSelfHosted()) {
signal_server_ip = config_center_->GetSignalServerHost();
signal_server_port = config_center_->GetSignalServerPort();
coturn_server_port = config_center_->GetCoturnServerPort();
tls_cert_path = config_center_->GetCertFilePath();
server_ip = config_center_->GetServerHost();
server_port = config_center_->GetServerPort();
server_cert_path = config_center_->GetCertFilePath();
} else {
signal_server_ip = config_center_->GetDefaultServerHost();
signal_server_port = config_center_->GetDefaultSignalServerPort();
coturn_server_port = config_center_->GetDefaultCoturnServerPort();
tls_cert_path = config_center_->GetDefaultCertFilePath();
server_ip = config_center_->GetDefaultServerHost();
server_port = config_center_->GetDefaultServerPort();
server_cert_path = config_center_->GetDefaultCertFilePath();
}
// self hosted server config
strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(),
sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_,
std::to_string(config_center_->GetSignalServerPort()).c_str(),
sizeof(signal_server_port_self_) - 1);
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
strncpy(coturn_server_port_self_,
std::to_string(config_center_->GetCoturnServerPort()).c_str(),
sizeof(coturn_server_port_self_) - 1);
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
tls_cert_path_self_ = config_center_->GetCertFilePath();
// peer config
strncpy((char*)params_.signal_server_ip, signal_server_ip.c_str(),
strncpy((char*)params_.signal_server_ip, server_ip.c_str(),
sizeof(params_.signal_server_ip) - 1);
params_.signal_server_ip[sizeof(params_.signal_server_ip) - 1] = '\0';
params_.signal_server_port = signal_server_port;
strncpy((char*)params_.stun_server_ip, signal_server_ip.c_str(),
params_.signal_server_port = server_port;
strncpy((char*)params_.stun_server_ip, server_ip.c_str(),
sizeof(params_.stun_server_ip) - 1);
params_.stun_server_ip[sizeof(params_.stun_server_ip) - 1] = '\0';
params_.stun_server_port = coturn_server_port;
strncpy((char*)params_.turn_server_ip, signal_server_ip.c_str(),
params_.stun_server_port = 3478;
strncpy((char*)params_.turn_server_ip, server_ip.c_str(),
sizeof(params_.turn_server_ip) - 1);
params_.turn_server_ip[sizeof(params_.turn_server_ip) - 1] = '\0';
params_.turn_server_port = coturn_server_port;
strncpy((char*)params_.turn_server_username, "crossdesk",
params_.turn_server_port = 3478;
strncpy((char*)params_.turn_server_username, "dijunkun",
sizeof(params_.turn_server_username) - 1);
params_.turn_server_username[sizeof(params_.turn_server_username) - 1] = '\0';
strncpy((char*)params_.turn_server_password, "crossdeskpw",
strncpy((char*)params_.turn_server_password, "dijunkunpw",
sizeof(params_.turn_server_password) - 1);
params_.turn_server_password[sizeof(params_.turn_server_password) - 1] = '\0';
strncpy(params_.tls_cert_path, tls_cert_path.c_str(),
strncpy(params_.tls_cert_path, server_cert_path.c_str(),
sizeof(params_.tls_cert_path) - 1);
params_.tls_cert_path[sizeof(params_.tls_cert_path) - 1] = '\0';
@@ -608,17 +588,6 @@ int Render::CreateMainWindow() {
// for window region action
SDL_SetWindowHitTest(main_window_, HitTestCallback, this);
#if _WIN32
SDL_PropertiesID props = SDL_GetWindowProperties(main_window_);
HWND main_hwnd = (HWND)SDL_GetPointerProperty(
props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
HICON tray_icon = (HICON)LoadImageW(NULL, L"crossdesk.ico", IMAGE_ICON, 0, 0,
LR_LOADFROMFILE | LR_DEFAULTSIZE);
tray_ = std::make_unique<WinTray>(main_hwnd, tray_icon, L"CrossDesk",
localization_language_index_);
#endif
return 0;
}
@@ -903,14 +872,13 @@ int Render::Run() {
cache_path_ = path_manager_->GetCachePath().string();
config_center_ =
std::make_unique<ConfigCenter>(cache_path_ + "/config.ini", cert_path_);
strncpy(signal_server_ip_self_,
config_center_->GetSignalServerHost().c_str(),
sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_,
std::to_string(config_center_->GetSignalServerPort()).c_str(),
sizeof(signal_server_port_self_) - 1);
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
strncpy(signal_server_ip_tmp_, config_center_->GetServerHost().c_str(),
sizeof(signal_server_ip_tmp_) - 1);
signal_server_ip_tmp_[sizeof(signal_server_ip_tmp_) - 1] = '\0';
strncpy(signal_server_port_tmp_,
std::to_string(config_center_->GetServerPort()).c_str(),
sizeof(signal_server_port_tmp_) - 1);
signal_server_port_tmp_[sizeof(signal_server_port_tmp_) - 1] = '\0';
strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1);
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
} else {
@@ -1000,14 +968,6 @@ void Render::MainLoop() {
ProcessSdlEvent(event);
}
#if _WIN32
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
#endif
UpdateLabels();
HandleRecentConnections();
HandleStreamWindow();
@@ -1433,5 +1393,4 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
}
break;
}
}
} // namespace crossdesk
}

View File

@@ -29,11 +29,7 @@
#include "screen_capturer_factory.h"
#include "speaker_capturer_factory.h"
#include "thumbnail.h"
#if _WIN32
#include "win_tray.h"
#endif
namespace crossdesk {
class Render {
public:
struct SubStreamWindowProperties {
@@ -302,9 +298,6 @@ class Render {
ImGuiContext* main_ctx_ = nullptr;
bool exit_ = false;
const int sdl_refresh_ms_ = 16; // ~60 FPS
#if _WIN32
std::unique_ptr<WinTray> tray_;
#endif
// main window properties
bool start_mouse_controller_ = false;
@@ -342,8 +335,8 @@ class Render {
float connection_status_window_height_ = 150;
float notification_window_width_ = 200;
float notification_window_height_ = 80;
float about_window_width_ = 300;
float about_window_height_ = 170;
float about_window_width_ = 200;
float about_window_height_ = 150;
int screen_width_ = 1280;
int screen_height_ = 720;
int selected_display_ = 0;
@@ -443,7 +436,6 @@ class Render {
bool enable_srtp_ = false;
char signal_server_ip_[256] = "api.crossdesk.cn";
char signal_server_port_[6] = "9099";
char coturn_server_port_[6] = "3478";
char cert_file_path_[256] = "";
bool enable_self_hosted_server_ = false;
int language_button_value_last_ = 0;
@@ -452,16 +444,12 @@ class Render {
bool enable_hardware_video_codec_last_ = false;
bool enable_turn_last_ = false;
bool enable_srtp_last_ = false;
bool enable_minimize_to_tray_ = false;
bool enable_minimize_to_tray_last_ = false;
char signal_server_ip_self_[256] = "";
char signal_server_port_self_[6] = "";
char coturn_server_port_self_[6] = "";
std::string tls_cert_path_self_ = "";
char signal_server_ip_tmp_[256] = "api.crossdesk.cn";
char signal_server_port_tmp_[6] = "9099";
bool settings_window_pos_reset_ = true;
bool self_hosted_server_config_window_pos_reset_ = true;
std::string selected_current_file_path_ = "";
bool show_file_browser_ = true;
std::string selected_file_ = "";
/* ------ main window property end ------ */
/* ------ sub stream window property start ------ */
@@ -470,5 +458,5 @@ class Render {
void CloseTab(decltype(client_properties_)::iterator& it);
/* ------ stream window property end ------ */
};
} // namespace crossdesk
#endif

View File

@@ -11,8 +11,6 @@
#define MOUSE_CONTROL 1
#endif
namespace crossdesk {
int Render::SendKeyCommand(int key_code, bool is_down) {
RemoteAction remote_action;
remote_action.type = ControlType::keyboard;
@@ -544,5 +542,4 @@ void Render::NetStatusReport(const char* client_id, size_t client_id_size,
if (!(render->peer_reserved_ && !strstr(client_id, "C-"))) {
props->net_traffic_stats_ = *net_traffic_stats;
}
}
} // namespace crossdesk
}

View File

@@ -3,8 +3,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int CountDigits(int number) {
if (number == 0) return 1;
return (int)std::floor(std::log10(std::abs(number))) + 1;
@@ -326,4 +324,3 @@ int Render::NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props) {
return 0;
}
} // namespace crossdesk

View File

@@ -1,8 +1,6 @@
#include "localization.h"
#include "render.h"
namespace crossdesk {
int Render::StatusBar() {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
static bool a, b, c, d, e;
@@ -37,5 +35,4 @@ int Render::StatusBar() {
ImGui::PopStyleColor();
ImGui::EndChild();
return 0;
}
} // namespace crossdesk
}

View File

@@ -4,8 +4,6 @@
#define BUTTON_PADDING 36.0f
namespace crossdesk {
int Render::TitleBar(bool main_window) {
ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
@@ -141,17 +139,9 @@ int Render::TitleBar(bool main_window) {
float xmark_size = 12.0f;
std::string close_button = "##xmark"; // ICON_FA_XMARK;
if (ImGui::Button(close_button.c_str(), ImVec2(BUTTON_PADDING, 30))) {
#if _WIN32
if (enable_minimize_to_tray_) {
tray_->MinimizeToTray();
} else {
#endif
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
#if _WIN32
}
#endif
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f,
xmark_pos_y - xmark_size / 2 + 0.75f),
@@ -173,5 +163,4 @@ int Render::TitleBar(bool main_window) {
ImGui::EndChild();
ImGui::PopStyleColor();
return 0;
}
} // namespace crossdesk
}

View File

@@ -1,115 +0,0 @@
#include "win_tray.h"
#include <SDL3/SDL.h>
#include "localization.h"
namespace crossdesk {
// callback for the message-only window that handles tray icon messages
static LRESULT CALLBACK MsgWndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam) {
WinTray* tray =
reinterpret_cast<WinTray*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (!tray) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
if (msg == WM_TRAY_CALLBACK) {
MSG tmpMsg = {};
tmpMsg.message = msg;
tmpMsg.wParam = wParam;
tmpMsg.lParam = lParam;
tray->HandleTrayMessage(&tmpMsg);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
WinTray::WinTray(HWND app_hwnd, HICON icon, const std::wstring& tooltip,
int language_index)
: app_hwnd_(app_hwnd),
icon_(icon),
tip_(tooltip),
hwnd_message_only_(nullptr),
language_index_(language_index) {
WNDCLASS wc = {};
wc.lpfnWndProc = MsgWndProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = L"TrayMessageWindow";
RegisterClass(&wc);
// create a message-only window to receive tray messages
hwnd_message_only_ =
CreateWindowEx(0, wc.lpszClassName, L"TrayMsg", 0, 0, 0, 0, 0,
HWND_MESSAGE, nullptr, wc.hInstance, nullptr);
// store pointer to this WinTray instance in window data
SetWindowLongPtr(hwnd_message_only_, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(this));
// initialize NOTIFYICONDATA structure
ZeroMemory(&nid_, sizeof(nid_));
nid_.cbSize = sizeof(nid_);
nid_.hWnd = hwnd_message_only_;
nid_.uID = 1;
nid_.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid_.uCallbackMessage = WM_TRAY_CALLBACK;
nid_.hIcon = icon_;
wcsncpy_s(nid_.szTip, tip_.c_str(), _TRUNCATE);
}
WinTray::~WinTray() {
RemoveTrayIcon();
if (hwnd_message_only_) DestroyWindow(hwnd_message_only_);
}
void WinTray::MinimizeToTray() {
Shell_NotifyIcon(NIM_ADD, &nid_);
// hide application window
ShowWindow(app_hwnd_, SW_HIDE);
}
void WinTray::RemoveTrayIcon() { Shell_NotifyIcon(NIM_DELETE, &nid_); }
bool WinTray::HandleTrayMessage(MSG* msg) {
if (!msg || msg->message != WM_TRAY_CALLBACK) return false;
switch (LOWORD(msg->lParam)) {
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP: {
ShowWindow(app_hwnd_, SW_SHOW);
SetForegroundWindow(app_hwnd_);
break;
}
case WM_RBUTTONUP: {
POINT pt;
GetCursorPos(&pt);
HMENU menu = CreatePopupMenu();
AppendMenuW(menu, MF_STRING, 1001,
localization::exit_program[language_index_]);
SetForegroundWindow(hwnd_message_only_);
int cmd =
TrackPopupMenu(menu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_LEFTALIGN,
pt.x, pt.y, 0, hwnd_message_only_, nullptr);
DestroyMenu(menu);
// handle menu command
if (cmd == 1001) {
// exit application
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
} else if (cmd == 1002) {
ShowWindow(app_hwnd_, SW_SHOW); // show main window
SetForegroundWindow(app_hwnd_);
}
break;
}
}
return true;
}
} // namespace crossdesk

View File

@@ -1,38 +0,0 @@
/*
* @Author: DI JUNKUN
* @Date: 2025-10-22
* Copyright (c) 2025 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _WIN_TRAY_H_
#define _WIN_TRAY_H_
#include <Windows.h>
#include <shellapi.h>
#include <string>
#define WM_TRAY_CALLBACK (WM_USER + 1)
namespace crossdesk {
class WinTray {
public:
WinTray(HWND app_hwnd, HICON icon, const std::wstring& tooltip,
int language_index);
~WinTray();
void MinimizeToTray();
void RemoveTrayIcon();
bool HandleTrayMessage(MSG* msg);
private:
HWND app_hwnd_;
HWND hwnd_message_only_;
HICON icon_;
std::wstring tip_;
int language_index_;
NOTIFYICONDATA nid_;
};
} // namespace crossdesk
#endif

View File

@@ -3,11 +3,9 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::AboutWindow() {
if (show_about_window_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
const ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2(
(viewport->WorkSize.x - viewport->WorkPos.x - about_window_width_) / 2,
@@ -29,21 +27,15 @@ int Render::AboutWindow() {
ImGui::SetWindowFontScale(0.5f);
std::string version;
#ifdef CROSSDESK_VERSION
version = CROSSDESK_VERSION;
#ifdef RD_VERSION
version = RD_VERSION;
#else
version = "Unknown";
#endif
std::string text = localization::version[localization_language_index_] +
": CrossDesk v" + version;
std::string text =
localization::version[localization_language_index_] + ": " + version;
ImGui::Text("%s", text.c_str());
ImGui::Text("");
std::string copyright_text = "© 2025 by JUNKUN DI. All rights reserved.";
std::string license_text = "Licensed under GNU LGPL v3.";
ImGui::Text("%s", copyright_text.c_str());
ImGui::Text("%s", license_text.c_str());
ImGui::SetCursorPosX(about_window_width_ * 0.42f);
ImGui::SetCursorPosY(about_window_height_ * 0.75f);
@@ -60,5 +52,4 @@ int Render::AboutWindow() {
ImGui::PopStyleColor();
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -3,11 +3,9 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
bool Render::ConnectionStatusWindow(
std::shared_ptr<SubStreamWindowProperties>& props) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
std::shared_ptr<SubStreamWindowProperties> &props) {
const ImGuiViewport *viewport = ImGui::GetMainViewport();
bool ret_flag = false;
ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x -
connection_status_window_width_) /
@@ -170,5 +168,4 @@ bool Render::ConnectionStatusWindow(
ImGui::PopStyleVar();
return ret_flag;
}
} // namespace crossdesk
}

View File

@@ -1,9 +1,7 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties> &props) {
double time_duration =
ImGui::GetTime() - props->control_bar_button_pressed_time_;
if (props->control_window_width_is_changing_) {
@@ -222,5 +220,4 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::PopStyleColor();
return 0;
}
} // namespace crossdesk
}

View File

@@ -3,8 +3,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::SettingWindow() {
if (show_settings_window_) {
if (settings_window_pos_reset_) {
@@ -59,7 +57,7 @@ int Render::SettingWindow() {
localization::language_en[localization_language_index_].c_str()};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text(
"%s", localization::language[localization_language_index_].c_str());
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
@@ -90,7 +88,7 @@ int Render::SettingWindow() {
.c_str()};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text(
"%s",
localization::video_quality[localization_language_index_].c_str());
@@ -113,7 +111,7 @@ int Render::SettingWindow() {
const char* video_frame_rate_items[] = {"30 fps", "60 fps"};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s",
localization::video_frame_rate[localization_language_index_]
.c_str());
@@ -139,7 +137,7 @@ int Render::SettingWindow() {
localization::av1[localization_language_index_].c_str()};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text(
"%s",
localization::video_encode_format[localization_language_index_]
@@ -162,7 +160,7 @@ int Render::SettingWindow() {
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s", localization::enable_hardware_video_codec
[localization_language_index_]
.c_str());
@@ -181,7 +179,7 @@ int Render::SettingWindow() {
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text(
"%s",
localization::enable_turn[localization_language_index_].c_str());
@@ -199,7 +197,7 @@ int Render::SettingWindow() {
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text(
"%s",
localization::enable_srtp[localization_language_index_].c_str());
@@ -217,7 +215,7 @@ int Render::SettingWindow() {
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 1);
ImGui::SetCursorPosY(settings_items_offset + 2);
if (ImGui::Button(localization::self_hosted_server_config
[localization_language_index_]
@@ -234,27 +232,7 @@ int Render::SettingWindow() {
ImGui::Checkbox("##enable_self_hosted_server",
&enable_self_hosted_server_);
}
#if _WIN32
ImGui::Separator();
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::Text("%s",
localization::minimize_to_tray[localization_language_index_]
.c_str());
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_CN);
} else {
ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_EN);
}
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_minimize_to_tray_",
&enable_minimize_to_tray_);
}
#endif
if (stream_window_inited_) {
ImGui::EndDisabled();
}
@@ -392,5 +370,4 @@ int Render::SettingWindow() {
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
int Render::MainWindow() {
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
@@ -49,4 +47,3 @@ int Render::MainWindow() {
return 0;
}
} // namespace crossdesk

View File

@@ -10,8 +10,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
std::vector<std::string> GetRootEntries() {
std::vector<std::string> roots;
#ifdef _WIN32
@@ -30,14 +28,8 @@ std::vector<std::string> GetRootEntries() {
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();
if (!selected_file_.empty()) {
display_text = std::filesystem::path(selected_file_).filename().string();
} else if (selected_current_file_path_ != "Root") {
display_text =
std::filesystem::path(selected_current_file_path_).filename().string();
@@ -51,69 +43,49 @@ int Render::ShowSimpleFileBrowser() {
localization::select_a_file[localization_language_index_].c_str();
}
if (show_file_browser_) {
ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
float fixed_width = 130.0f;
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)) {
bool file_selected = false;
if (ImGui::BeginCombo("##select_a_file", display_text.c_str())) {
if (selected_current_file_path_ == "Root" ||
!std::filesystem::exists(selected_current_file_path_) ||
!std::filesystem::is_directory(selected_current_file_path_)) {
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());
for (const auto& root : roots) {
if (ImGui::Selectable(root.c_str())) {
selected_current_file_path_ = root;
selected_file_.clear();
}
}
} else {
std::filesystem::path p(selected_current_file_path_);
ImGui::EndCombo();
if (ImGui::Selectable("..")) {
if (p.has_parent_path() && p != p.root_path())
selected_current_file_path_ = p.parent_path().string();
else
selected_current_file_path_ = "Root";
selected_file_.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();
selected_file_.clear();
}
} else {
if (ImGui::Selectable(name.c_str())) {
selected_file_ = entry.path().string();
}
}
}
} catch (const std::exception& e) {
ImGui::TextColored(ImVec4(1, 0, 0, 1), "Error: %s", e.what());
}
}
ImGui::PopItemFlag();
} else {
show_file_browser_ = true;
ImGui::EndCombo();
}
return 0;
@@ -185,8 +157,8 @@ int Render::SelfHostedServerWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##signal_server_ip_self_", signal_server_ip_self_,
IM_ARRAYSIZE(signal_server_ip_self_),
ImGui::InputText("##signal_server_ip_tmp_", signal_server_ip_tmp_,
IM_ARRAYSIZE(signal_server_ip_tmp_),
ImGuiInputTextFlags_AlwaysOverwrite);
}
@@ -208,29 +180,8 @@ int Render::SelfHostedServerWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##signal_server_port_self_", signal_server_port_self_,
IM_ARRAYSIZE(signal_server_port_self_));
}
ImGui::Separator();
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s", localization::self_hosted_server_coturn_server_port
[localization_language_index_]
.c_str());
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN);
} else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN);
}
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##coturn_server_port_self_", coturn_server_port_self_,
IM_ARRAYSIZE(coturn_server_port_self_));
ImGui::InputText("##signal_server_port_tmp_", signal_server_port_tmp_,
IM_ARRAYSIZE(signal_server_port_tmp_));
}
ImGui::Separator();
@@ -272,20 +223,16 @@ int Render::SelfHostedServerWindow() {
localization::ok[localization_language_index_].c_str())) {
show_self_hosted_server_config_window_ = false;
config_center_->SetServerHost(signal_server_ip_self_);
config_center_->SetServerPort(atoi(signal_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_,
config_center_->SetServerHost(signal_server_ip_tmp_);
config_center_->SetServerPort(atoi(signal_server_port_tmp_));
config_center_->SetCertFilePath(selected_file_);
strncpy(signal_server_ip_, signal_server_ip_tmp_,
sizeof(signal_server_ip_) - 1);
signal_server_ip_[sizeof(signal_server_ip_) - 1] = '\0';
strncpy(signal_server_port_, signal_server_port_self_,
strncpy(signal_server_port_, signal_server_port_tmp_,
sizeof(signal_server_port_) - 1);
signal_server_port_[sizeof(signal_server_port_) - 1] = '\0';
strncpy(coturn_server_port_, coturn_server_port_self_,
sizeof(coturn_server_port_) - 1);
coturn_server_port_[sizeof(coturn_server_port_) - 1] = '\0';
strncpy(cert_file_path_, tls_cert_path_self_.c_str(),
strncpy(cert_file_path_, selected_file_.c_str(),
sizeof(cert_file_path_) - 1);
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
@@ -299,15 +246,15 @@ int Render::SelfHostedServerWindow() {
show_self_hosted_server_config_window_ = false;
self_hosted_server_config_window_pos_reset_ = true;
strncpy(signal_server_ip_self_, signal_server_ip_,
sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_, signal_server_port_,
sizeof(signal_server_port_self_) - 1);
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
config_center_->SetServerHost(signal_server_ip_self_);
config_center_->SetServerPort(atoi(signal_server_port_self_));
tls_cert_path_self_.clear();
strncpy(signal_server_ip_tmp_, signal_server_ip_,
sizeof(signal_server_ip_tmp_) - 1);
signal_server_ip_tmp_[sizeof(signal_server_ip_tmp_) - 1] = '\0';
strncpy(signal_server_port_tmp_, signal_server_port_,
sizeof(signal_server_port_tmp_) - 1);
signal_server_port_tmp_[sizeof(signal_server_port_tmp_) - 1] = '\0';
config_center_->SetServerHost(signal_server_ip_tmp_);
config_center_->SetServerPort(atoi(signal_server_port_tmp_));
selected_file_.clear();
}
ImGui::SetWindowFontScale(1.0f);
@@ -320,5 +267,4 @@ int Render::SelfHostedServerWindow() {
}
return 0;
}
} // namespace crossdesk
}

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
#include "render.h"
namespace crossdesk {
void Render::DrawConnectionStatusText(
std::shared_ptr<SubStreamWindowProperties>& props) {
std::string text;
@@ -201,5 +199,4 @@ int Render::StreamWindow() {
ImGui::End(); // End VideoBg
return 0;
}
} // namespace crossdesk
}

View File

@@ -3,8 +3,6 @@
#include <atomic>
#include <filesystem>
namespace crossdesk {
namespace {
std::string g_log_dir = "logs";
@@ -62,4 +60,3 @@ std::shared_ptr<spdlog::logger> get_logger() {
return g_logger;
}
} // namespace crossdesk

View File

@@ -25,8 +25,6 @@
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
namespace crossdesk {
constexpr auto LOGGER_NAME = "crossdesk";
void InitLogger(const std::string& log_dir);
@@ -37,5 +35,5 @@ std::shared_ptr<spdlog::logger> get_logger();
#define LOG_WARN(...) SPDLOG_LOGGER_WARN(get_logger(), __VA_ARGS__)
#define LOG_ERROR(...) SPDLOG_LOGGER_ERROR(get_logger(), __VA_ARGS__)
#define LOG_FATAL(...) SPDLOG_LOGGER_CRITICAL(get_logger(), __VA_ARGS__)
} // namespace crossdesk
#endif

View File

@@ -2,8 +2,6 @@
#include <cstdlib>
namespace crossdesk {
PathManager::PathManager(const std::string& app_name) : app_name_(app_name) {}
std::filesystem::path PathManager::GetConfigPath() {
@@ -91,4 +89,3 @@ std::filesystem::path PathManager::GetEnvOrDefault(const char* env_var,
return std::filesystem::path(def);
}
} // namespace crossdesk

View File

@@ -14,8 +14,6 @@
#include <windows.h>
#endif
namespace crossdesk {
class PathManager {
public:
explicit PathManager(const std::string& app_name);
@@ -42,5 +40,5 @@ class PathManager {
private:
std::string app_name_;
};
} // namespace crossdesk
#endif

View File

@@ -6,8 +6,6 @@
#include "libyuv.h"
#include "rd_log.h"
namespace crossdesk {
ScreenCapturerX11::ScreenCapturerX11() {}
ScreenCapturerX11::~ScreenCapturerX11() { Destroy(); }
@@ -173,5 +171,4 @@ void ScreenCapturerX11::OnFrame() {
}
XDestroyImage(image);
}
} // namespace crossdesk
}

View File

@@ -20,8 +20,6 @@
#include "screen_capturer.h"
namespace crossdesk {
class ScreenCapturerX11 : public ScreenCapturer {
public:
ScreenCapturerX11();
@@ -62,5 +60,5 @@ class ScreenCapturerX11 : public ScreenCapturer {
std::vector<uint8_t> y_plane_;
std::vector<uint8_t> uv_plane_;
};
} // namespace crossdesk
#endif

View File

@@ -2,8 +2,6 @@
#include "rd_log.h"
namespace crossdesk {
ScreenCapturerSck::ScreenCapturerSck() {}
ScreenCapturerSck::~ScreenCapturerSck() {}
@@ -72,5 +70,4 @@ std::vector<DisplayInfo> ScreenCapturerSck::GetDisplayInfoList() {
void ScreenCapturerSck::OnFrame() {}
void ScreenCapturerSck::CleanUp() {}
} // namespace crossdesk
void ScreenCapturerSck::CleanUp() {}

View File

@@ -16,8 +16,6 @@
#include "screen_capturer.h"
namespace crossdesk {
class ScreenCapturerSck : public ScreenCapturer {
public:
ScreenCapturerSck();
@@ -57,5 +55,5 @@ class ScreenCapturerSck : public ScreenCapturer {
private:
std::unique_ptr<ScreenCapturer> screen_capturer_sck_impl_;
};
} // namespace crossdesk
#endif

View File

@@ -22,11 +22,8 @@
#include "display_info.h"
#include "rd_log.h"
using namespace crossdesk;
class ScreenCapturerSckImpl;
static const int kFullDesktopScreenId = -1;
class ScreenCapturerSckImpl;
// The ScreenCaptureKit API was available in macOS 12.3, but full-screen capture
// was reported to be broken before macOS 13 - see http://crbug.com/40234870.
@@ -427,6 +424,10 @@ void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
[SCShareableContent getShareableContentWithCompletionHandler:handler];
}
std::unique_ptr<ScreenCapturer> ScreenCapturerSck::CreateScreenCapturerSck() {
return std::make_unique<ScreenCapturerSckImpl>();
}
@implementation SckHelper {
// This lock is to prevent the capturer being destroyed while an instance
// method is still running on another thread.
@@ -484,8 +485,4 @@ void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
_capturer = nullptr;
}
@end
std::unique_ptr<ScreenCapturer> ScreenCapturerSck::CreateScreenCapturerSck() {
return std::make_unique<ScreenCapturerSckImpl>();
}
@end

View File

@@ -11,8 +11,6 @@
#include "display_info.h"
namespace crossdesk {
class ScreenCapturer {
public:
typedef std::function<void(unsigned char*, int, int, int, const char*)>
@@ -32,5 +30,5 @@ class ScreenCapturer {
virtual std::vector<DisplayInfo> GetDisplayInfoList() = 0;
virtual int SwitchTo(int monitor_index) = 0;
};
} // namespace crossdesk
#endif

View File

@@ -16,8 +16,6 @@
#include "screen_capturer_sck.h"
#endif
namespace crossdesk {
class ScreenCapturerFactory {
public:
virtual ~ScreenCapturerFactory() {}
@@ -36,5 +34,5 @@ class ScreenCapturerFactory {
#endif
}
};
} // namespace crossdesk
#endif

View File

@@ -10,8 +10,6 @@
#include "libyuv.h"
#include "rd_log.h"
namespace crossdesk {
static std::vector<DisplayInfo> gs_display_list;
std::string WideToUtf8(const wchar_t* wideStr) {
@@ -247,19 +245,21 @@ int ScreenCapturerWgc::SwitchTo(int monitor_index) {
void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame,
int id) {
if (on_data_) {
if (!nv12_frame_) {
nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2];
}
libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4,
(uint8_t*)nv12_frame_, frame.width,
(uint8_t*)(nv12_frame_ + frame.width * frame.height),
frame.width, frame.width, frame.height);
on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width,
frame.height, display_info_list_[id].name.c_str());
if (!on_data_) {
return;
}
if (!nv12_frame_) {
nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2];
}
libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4,
(uint8_t*)nv12_frame_, frame.width,
(uint8_t*)(nv12_frame_ + frame.width * frame.height),
frame.width, frame.width, frame.height);
on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width,
frame.height, display_info_list_[id].name.c_str());
}
void ScreenCapturerWgc::CleanUp() {
@@ -272,4 +272,3 @@ void ScreenCapturerWgc::CleanUp() {
sessions_.clear();
}
}
} // namespace crossdesk

View File

@@ -11,8 +11,6 @@
#include "wgc_session.h"
#include "wgc_session_impl.h"
namespace crossdesk {
class ScreenCapturerWgc : public ScreenCapturer,
public WgcSession::wgc_session_observer {
public:
@@ -45,6 +43,8 @@ class ScreenCapturerWgc : public ScreenCapturer,
std::vector<DisplayInfo> display_info_list_;
int monitor_index_ = 0;
HWND hwnd_ = nullptr;
private:
class WgcSessionInfo {
public:
@@ -65,6 +65,9 @@ class ScreenCapturerWgc : public ScreenCapturer,
unsigned char* nv12_frame_ = nullptr;
unsigned char* nv12_frame_scaled_ = nullptr;
private:
bool CreateHiddenWindow();
};
} // namespace crossdesk
#endif

View File

@@ -0,0 +1,68 @@
#ifndef _SCREEN_CAPTURER_WGC_H_
#define _SCREEN_CAPTURER_WGC_H_
#include <atomic>
#include <functional>
#include <string>
#include <thread>
#include <vector>
#include "screen_capturer.h"
#include "wgc_session.h"
#include "wgc_session_impl.h"
class ScreenCapturerWgc : public ScreenCapturer,
public WgcSession::wgc_session_observer {
public:
ScreenCapturerWgc();
~ScreenCapturerWgc();
public:
bool IsWgcSupported();
int Init(const int fps, cb_desktop_data cb) override;
int Destroy() override;
int Start() override;
int Stop() override;
int Pause(int monitor_index) override;
int Resume(int monitor_index) override;
std::vector<DisplayInfo> GetDisplayInfoList() { return display_info_list_; }
int SwitchTo(int monitor_index);
void OnFrame(const WgcSession::wgc_session_frame& frame, int id);
protected:
void CleanUp();
private:
HMONITOR monitor_;
MONITORINFOEX monitor_info_;
std::vector<DisplayInfo> display_info_list_;
int monitor_index_ = 0;
private:
class WgcSessionInfo {
public:
std::unique_ptr<WgcSession> session_;
bool inited_ = false;
bool running_ = false;
bool paused_ = false;
};
std::vector<WgcSessionInfo> sessions_;
std::atomic_bool running_;
std::atomic_bool inited_;
int fps_ = 60;
cb_desktop_data on_data_ = nullptr;
unsigned char* nv12_frame_ = nullptr;
unsigned char* nv12_frame_scaled_ = nullptr;
};
#endif

View File

@@ -0,0 +1,187 @@
#include <Windows.h>
#include <d3d11_4.h>
#include <iostream>
#include <thread>
#include "libyuv.h"
#include "rd_log.h"
#include "screen_capturer_wgc.h"
// Dummy window proc for hidden window
static LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ======================= 构造函数 / 析构函数 =======================
ScreenCapturerWgc::ScreenCapturerWgc()
: monitor_(nullptr),
hwnd_(nullptr),
monitor_index_(0),
running_(false),
inited_(false),
fps_(60),
on_data_(nullptr),
nv12_frame_(nullptr),
nv12_frame_scaled_(nullptr) {}
ScreenCapturerWgc::~ScreenCapturerWgc() {
Stop();
CleanUp();
if (nv12_frame_) {
delete[] nv12_frame_;
nv12_frame_ = nullptr;
}
if (nv12_frame_scaled_) {
delete[] nv12_frame_scaled_;
nv12_frame_scaled_ = nullptr;
}
}
// ======================= 隐藏窗口创建 =======================
bool ScreenCapturerWgc::CreateHiddenWindow() {
const wchar_t kClassName[] = L"ScreenCapturerHiddenWindow";
WNDCLASSW wc = {};
wc.lpfnWndProc = DummyWndProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = kClassName;
if (!RegisterClassW(&wc)) {
std::cerr << "Failed to register dummy window class\n";
return false;
}
hwnd_ = CreateWindowW(kClassName, L"", WS_OVERLAPPEDWINDOW, 0, 0, 1, 1,
nullptr, nullptr, wc.hInstance, nullptr);
if (!hwnd_) {
std::cerr << "Failed to create dummy window\n";
return false;
}
ShowWindow(hwnd_, SW_HIDE);
return true;
}
// ======================= 初始化 =======================
int ScreenCapturerWgc::Init(const int fps, cb_desktop_data cb) {
if (inited_) return 0;
fps_ = fps;
on_data_ = cb;
// 创建隐藏窗口
if (!CreateHiddenWindow()) {
return -1;
}
// 初始化 WGC Session
sessions_.push_back(
{std::make_unique<WgcSessionImpl>(0), false, false, false});
sessions_.back().session_->RegisterObserver(this);
int error = sessions_.back().session_->Initialize(hwnd_);
if (error != 0) {
std::cerr << "WGC session init failed\n";
return error;
}
sessions_[0].inited_ = true;
inited_ = true;
return 0;
}
int ScreenCapturerWgc::Destroy() {
Stop();
CleanUp();
return 0;
}
int ScreenCapturerWgc::Pause(int monitor_index) {
// 目前只支持隐藏窗口,所以忽略 monitor_index
if (!running_) return -1;
sessions_[0].session_->Pause();
sessions_[0].paused_ = true;
return 0;
}
int ScreenCapturerWgc::Resume(int monitor_index) {
if (!running_) return -1;
sessions_[0].session_->Resume();
sessions_[0].paused_ = false;
return 0;
}
int ScreenCapturerWgc::SwitchTo(int monitor_index) {
// 单隐藏窗口模式,不支持切换
return 0;
}
// ======================= 开始 =======================
int ScreenCapturerWgc::Start() {
if (!inited_) return -1;
if (running_) return 0;
if (sessions_.empty()) return -1;
sessions_[0].session_->Start();
sessions_[0].running_ = true;
running_ = true;
return 0;
}
// ======================= 停止 =======================
int ScreenCapturerWgc::Stop() {
if (!running_) return 0;
if (!sessions_.empty()) {
sessions_[0].session_->Stop();
sessions_[0].running_ = false;
}
running_ = false;
if (hwnd_) {
DestroyWindow(hwnd_);
hwnd_ = nullptr;
}
inited_ = false;
sessions_.clear();
return 0;
}
// ======================= 帧回调 =======================
void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame,
int id) {
if (!on_data_) {
return;
}
if (!nv12_frame_) {
nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2];
}
libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4,
(uint8_t*)nv12_frame_, frame.width,
(uint8_t*)(nv12_frame_ + frame.width * frame.height),
frame.width, frame.width, frame.height);
on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width,
frame.height, "hidden_window");
}
// ======================= 清理 =======================
void ScreenCapturerWgc::CleanUp() {
if (inited_) {
for (auto& session : sessions_) {
if (session.session_) {
session.session_->Stop();
}
}
sessions_.clear();
}
}

View File

@@ -3,8 +3,6 @@
#include <Windows.h>
namespace crossdesk {
class WgcSession {
public:
struct wgc_session_frame {
@@ -12,13 +10,13 @@ class WgcSession {
unsigned int height;
unsigned int row_pitch;
const unsigned char* data;
const unsigned char *data;
};
class wgc_session_observer {
public:
virtual ~wgc_session_observer() {}
virtual void OnFrame(const wgc_session_frame& frame, int id) = 0;
virtual void OnFrame(const wgc_session_frame &frame, int id) = 0;
};
public:
@@ -27,7 +25,7 @@ class WgcSession {
virtual int Initialize(HWND hwnd) = 0;
virtual int Initialize(HMONITOR hmonitor) = 0;
virtual void RegisterObserver(wgc_session_observer* observer) = 0;
virtual void RegisterObserver(wgc_session_observer *observer) = 0;
virtual int Start() = 0;
virtual int Stop() = 0;
@@ -35,7 +33,7 @@ class WgcSession {
virtual int Pause() = 0;
virtual int Resume() = 0;
virtual ~WgcSession() {};
virtual ~WgcSession(){};
};
} // namespace crossdesk
#endif

View File

@@ -7,6 +7,8 @@
#include <iostream>
#include <memory>
#include "rd_log.h"
#define CHECK_INIT \
if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
@@ -18,8 +20,6 @@
throw winrt::hresult_error(RO_E_CLOSED); \
}
namespace crossdesk {
extern "C" {
HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
::IDXGIDevice* dxgiDevice, ::IInspectable** graphicsDevice);
@@ -28,116 +28,112 @@ HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
WgcSessionImpl::WgcSessionImpl(int id) : id_(id) {}
WgcSessionImpl::~WgcSessionImpl() {
Stop();
CleanUp();
try {
Stop();
CleanUp();
} catch (...) {
}
}
void WgcSessionImpl::Release() { delete this; }
int WgcSessionImpl::Initialize(HWND hwnd) {
std::lock_guard locker(lock_);
std::scoped_lock locker(lock_);
target_.hwnd = hwnd;
target_.is_window = true;
return Initialize();
}
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
std::lock_guard locker(lock_);
std::scoped_lock locker(lock_);
target_.hmonitor = hmonitor;
target_.is_window = false;
return Initialize();
}
void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) {
std::lock_guard locker(lock_);
std::scoped_lock locker(lock_);
observer_ = observer;
}
int WgcSessionImpl::Start() {
std::lock_guard locker(lock_);
std::scoped_lock locker(lock_);
CHECK_INIT;
if (is_running_) return 0;
int error = 1;
CHECK_INIT;
try {
if (!capture_session_) {
auto current_size = capture_item_.Size();
capture_framepool_ =
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
CreateFreeThreaded(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, current_size);
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
capture_frame_size_ = current_size;
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
capture_close_trigger_ = capture_item_.Closed(
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
if (!capture_item_) {
std::cout << "AE_NO_CAPTURE_ITEM" << std::endl;
LOG_ERROR("No capture item");
return 2;
}
if (!capture_framepool_) throw std::exception();
auto current_size = capture_item_.Size();
capture_framepool_ =
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
CreateFreeThreaded(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, current_size);
is_running_ = true;
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
capture_frame_size_ = current_size;
// we do not need to crate a thread to enter a message loop coz we use
// CreateFreeThreaded instead of Create to create a capture frame pool,
// we need to test the performance later
// loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this));
capture_session_.StartCapture();
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
capture_close_trigger_ = capture_item_.Closed(
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
capture_session_.IsCursorCaptureEnabled(false);
capture_session_.StartCapture();
error = 0;
} catch (winrt::hresult_error) {
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
is_running_ = true;
is_paused_ = false;
return 0;
} catch (winrt::hresult_error const& e) {
LOG_ERROR("Create WGC Capture Failed: {}", winrt::to_string(e.message()));
return 86;
} catch (...) {
return 86;
}
return error;
}
int WgcSessionImpl::Stop() {
std::lock_guard locker(lock_);
std::scoped_lock locker(lock_);
CHECK_INIT;
if (!is_running_) return 0;
is_running_ = false;
// if (loop_.joinable()) loop_.join();
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
if (capture_session_) {
capture_session_.Close();
capture_session_ = nullptr;
try {
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
if (capture_close_trigger_) capture_close_trigger_.revoke();
if (capture_session_) {
capture_session_.Close();
capture_session_ = nullptr;
}
if (capture_framepool_) {
capture_framepool_.Close();
capture_framepool_ = nullptr;
}
} catch (...) {
}
return 0;
}
int WgcSessionImpl::Pause() {
std::lock_guard locker(lock_);
is_paused_ = true;
std::scoped_lock locker(lock_);
CHECK_INIT;
is_paused_ = true;
return 0;
}
int WgcSessionImpl::Resume() {
std::lock_guard locker(lock_);
is_paused_ = false;
std::scoped_lock locker(lock_);
CHECK_INIT;
is_paused_ = false;
return 0;
}
@@ -145,19 +141,15 @@ auto WgcSessionImpl::CreateD3D11Device() {
winrt::com_ptr<ID3D11Device> d3d_device;
HRESULT hr;
WINRT_ASSERT(!d3d_device);
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(),
nullptr, nullptr);
if (DXGI_ERROR_UNSUPPORTED == hr) {
// change D3D_DRIVER_TYPE
type = D3D_DRIVER_TYPE_WARP;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr,
nullptr);
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, flags,
nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(),
nullptr, nullptr);
}
winrt::check_hresult(hr);
@@ -170,10 +162,11 @@ auto WgcSessionImpl::CreateD3D11Device() {
}
auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
auto interop_factory =
winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>()
.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item{nullptr};
interop_factory->CreateForWindow(
hwnd,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
@@ -182,10 +175,11 @@ auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
}
auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
auto interop_factory =
winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>()
.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item{nullptr};
interop_factory->CreateForMonitor(
hmonitor,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
@@ -198,13 +192,10 @@ HRESULT WgcSessionImpl::CreateMappedTexture(
unsigned int height) {
D3D11_TEXTURE2D_DESC src_desc;
src_texture->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC map_desc;
map_desc.Width = width == 0 ? src_desc.Width : width;
map_desc.Height = height == 0 ? src_desc.Height : height;
map_desc.MipLevels = src_desc.MipLevels;
map_desc.ArraySize = src_desc.ArraySize;
map_desc.Format = src_desc.Format;
map_desc.SampleDesc = src_desc.SampleDesc;
D3D11_TEXTURE2D_DESC map_desc = src_desc;
map_desc.Width = width ? width : src_desc.Width;
map_desc.Height = height ? height : src_desc.Height;
map_desc.Usage = D3D11_USAGE_STAGING;
map_desc.BindFlags = 0;
map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
@@ -220,162 +211,99 @@ HRESULT WgcSessionImpl::CreateMappedTexture(
void WgcSessionImpl::OnFrame(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender,
[[maybe_unused]] winrt::Windows::Foundation::IInspectable const& args) {
std::lock_guard locker(lock_);
if (!is_running_ || is_paused_) return;
std::scoped_lock locker(lock_);
auto is_new_size = false;
if (!observer_) return;
{
auto frame = sender.TryGetNextFrame();
auto frame_size = frame.ContentSize();
auto frame = sender.TryGetNextFrame();
if (!frame) return;
if (frame_size.Width != capture_frame_size_.Width ||
frame_size.Height != capture_frame_size_.Height) {
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
is_new_size = true;
capture_frame_size_ = frame_size;
}
// copy to mapped texture
{
if (is_paused_) {
return;
}
auto frame_captured =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
if (!d3d11_texture_mapped_ || is_new_size)
CreateMappedTexture(frame_captured);
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
frame_captured.get());
D3D11_MAPPED_SUBRESOURCE map_result;
HRESULT hr = d3d11_device_context_->Map(
d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
0 /*coz we use CreateFreeThreaded, so we cant use flags
D3D11_MAP_FLAG_DO_NOT_WAIT*/
,
&map_result);
if (FAILED(hr)) {
OutputDebugStringW(
(L"map resource failed: " + std::to_wstring(hr)).c_str());
}
// copy data from map_result.pData
if (map_result.pData && observer_) {
observer_->OnFrame(
wgc_session_frame{static_cast<unsigned int>(frame_size.Width),
static_cast<unsigned int>(frame_size.Height),
map_result.RowPitch,
const_cast<const unsigned char*>(
(unsigned char*)map_result.pData)},
id_);
}
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
}
}
if (is_new_size) {
auto frame_size = frame.ContentSize();
bool size_changed = (frame_size.Width != capture_frame_size_.Width ||
frame_size.Height != capture_frame_size_.Height);
if (size_changed) {
capture_frame_size_ = frame_size;
capture_framepool_.Recreate(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, capture_frame_size_);
}
auto frame_surface =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
if (!d3d11_texture_mapped_ || size_changed)
CreateMappedTexture(frame_surface, frame_size.Width, frame_size.Height);
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
frame_surface.get());
D3D11_MAPPED_SUBRESOURCE map_result;
HRESULT hr = d3d11_device_context_->Map(d3d11_texture_mapped_.get(), 0,
D3D11_MAP_READ, 0, &map_result);
if (SUCCEEDED(hr)) {
wgc_session_frame frame_info{
static_cast<unsigned int>(frame_size.Width),
static_cast<unsigned int>(frame_size.Height), map_result.RowPitch,
reinterpret_cast<const unsigned char*>(map_result.pData)};
observer_->OnFrame(frame_info, id_);
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
}
}
void WgcSessionImpl::OnClosed(
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
winrt::Windows::Foundation::IInspectable const&) {
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
Stop();
}
int WgcSessionImpl::Initialize() {
if (is_initialized_) return 0;
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
d3d11_direct_device_ = CreateD3D11Device();
if (!d3d11_direct_device_) {
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl;
return 1;
}
try {
if (target_.is_window)
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
else
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
capture_item_ = target_.is_window
? CreateCaptureItemForWindow(target_.hwnd)
: CreateCaptureItemForMonitor(target_.hmonitor);
// Set up
auto d3d11_device =
auto d3d_device =
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
} catch (winrt::hresult_error) {
std::cout << "AE_WGC_CREATE_CAPTURER_FAILED" << std::endl;
return 86;
d3d_device->GetImmediateContext(d3d11_device_context_.put());
} catch (...) {
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
return 86;
}
is_initialized_ = true;
return 0;
}
void WgcSessionImpl::CleanUp() {
std::lock_guard locker(lock_);
auto expected = false;
if (cleaned_.compare_exchange_strong(expected, true)) {
capture_close_trigger_.revoke();
capture_framepool_trigger_.revoke();
std::scoped_lock locker(lock_);
if (cleaned_.exchange(true)) return;
try {
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
if (capture_close_trigger_) capture_close_trigger_.revoke();
if (capture_framepool_) capture_framepool_.Close();
if (capture_session_) capture_session_.Close();
capture_framepool_ = nullptr;
capture_session_ = nullptr;
capture_item_ = nullptr;
is_initialized_ = false;
} catch (...) {
}
capture_framepool_ = nullptr;
capture_session_ = nullptr;
capture_item_ = nullptr;
d3d11_texture_mapped_ = nullptr;
d3d11_device_context_ = nullptr;
d3d11_direct_device_ = nullptr;
is_initialized_ = false;
is_running_ = false;
}
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
LPARAM l_param) {
return DefWindowProc(window, message, w_param, l_param);
}
// void WgcSessionImpl::message_func() {
// const std::wstring kClassName = L"am_fake_window";
// WNDCLASS wc = {};
// wc.style = CS_HREDRAW | CS_VREDRAW;
// wc.lpfnWndProc = DefWindowProc;
// wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
// wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
// wc.lpszClassName = kClassName.c_str();
// if (!::RegisterClassW(&wc)) return;
// hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW,
// 0,
// 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
// MSG msg;
// while (is_running_) {
// while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// if (!is_running_) break;
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }
// Sleep(10);
// }
// ::CloseWindow(hwnd_);
// ::DestroyWindow(hwnd_);
// }
} // namespace crossdesk

View File

@@ -0,0 +1,380 @@
#include "wgc_session_impl.h"
#include <Windows.Graphics.Capture.Interop.h>
#include <atomic>
#include <functional>
#include <iostream>
#include <memory>
#include "rd_log.h"
#define CHECK_INIT \
if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \
return 4; \
}
#define CHECK_CLOSED \
if (cleaned_.load() == true) { \
throw winrt::hresult_error(RO_E_CLOSED); \
}
extern "C" {
HRESULT __stdcall CreateDirect3D11DeviceFromDXGIDevice(
::IDXGIDevice* dxgiDevice, ::IInspectable** graphicsDevice);
}
WgcSessionImpl::WgcSessionImpl(int id) : id_(id) {}
WgcSessionImpl::~WgcSessionImpl() {
Stop();
CleanUp();
}
void WgcSessionImpl::Release() { delete this; }
int WgcSessionImpl::Initialize(HWND hwnd) {
std::lock_guard locker(lock_);
target_.hwnd = hwnd;
target_.is_window = true;
return Initialize();
}
int WgcSessionImpl::Initialize(HMONITOR hmonitor) {
std::lock_guard locker(lock_);
target_.hmonitor = hmonitor;
target_.is_window = false;
return Initialize();
}
void WgcSessionImpl::RegisterObserver(wgc_session_observer* observer) {
std::lock_guard locker(lock_);
observer_ = observer;
}
int WgcSessionImpl::Start() {
std::lock_guard locker(lock_);
if (is_running_) return 0;
int error = 1;
CHECK_INIT;
try {
if (!capture_session_) {
auto current_size = capture_item_.Size();
capture_framepool_ =
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::
CreateFreeThreaded(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, current_size);
capture_session_ = capture_framepool_.CreateCaptureSession(capture_item_);
capture_frame_size_ = current_size;
capture_framepool_trigger_ = capture_framepool_.FrameArrived(
winrt::auto_revoke, {this, &WgcSessionImpl::OnFrame});
capture_close_trigger_ = capture_item_.Closed(
winrt::auto_revoke, {this, &WgcSessionImpl::OnClosed});
}
if (!capture_framepool_) throw std::exception();
is_running_ = true;
// we do not need to crate a thread to enter a message loop coz we use
// CreateFreeThreaded instead of Create to create a capture frame pool,
// we need to test the performance later
// loop_ = std::thread(std::bind(&WgcSessionImpl::message_func, this));
capture_session_.StartCapture();
capture_session_.IsCursorCaptureEnabled(false);
error = 0;
} catch (winrt::hresult_error) {
LOG_ERROR("Create WGC Capture Failed");
return 86;
} catch (...) {
return 86;
}
return error;
}
int WgcSessionImpl::Stop() {
std::lock_guard locker(lock_);
CHECK_INIT;
is_running_ = false;
// if (loop_.joinable()) loop_.join();
if (capture_framepool_trigger_) capture_framepool_trigger_.revoke();
if (capture_session_) {
capture_session_.Close();
capture_session_ = nullptr;
}
return 0;
}
int WgcSessionImpl::Pause() {
std::lock_guard locker(lock_);
is_paused_ = true;
CHECK_INIT;
return 0;
}
int WgcSessionImpl::Resume() {
std::lock_guard locker(lock_);
is_paused_ = false;
CHECK_INIT;
return 0;
}
auto WgcSessionImpl::CreateD3D11Device() {
winrt::com_ptr<ID3D11Device> d3d_device;
HRESULT hr;
WINRT_ASSERT(!d3d_device);
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE;
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr);
if (DXGI_ERROR_UNSUPPORTED == hr) {
// change D3D_DRIVER_TYPE
type = D3D_DRIVER_TYPE_WARP;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr,
nullptr);
}
winrt::check_hresult(hr);
winrt::com_ptr<::IInspectable> d3d11_device;
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(
d3d_device.as<IDXGIDevice>().get(), d3d11_device.put()));
return d3d11_device
.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
}
auto WgcSessionImpl::CreateCaptureItemForWindow(HWND hwnd) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForWindow(
hwnd,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void**>(winrt::put_abi(item)));
return item;
}
auto WgcSessionImpl::CreateCaptureItemForMonitor(HMONITOR hmonitor) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForMonitor(
hmonitor,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void**>(winrt::put_abi(item)));
return item;
}
HRESULT WgcSessionImpl::CreateMappedTexture(
winrt::com_ptr<ID3D11Texture2D> src_texture, unsigned int width,
unsigned int height) {
D3D11_TEXTURE2D_DESC src_desc;
src_texture->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC map_desc;
map_desc.Width = width == 0 ? src_desc.Width : width;
map_desc.Height = height == 0 ? src_desc.Height : height;
map_desc.MipLevels = src_desc.MipLevels;
map_desc.ArraySize = src_desc.ArraySize;
map_desc.Format = src_desc.Format;
map_desc.SampleDesc = src_desc.SampleDesc;
map_desc.Usage = D3D11_USAGE_STAGING;
map_desc.BindFlags = 0;
map_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
map_desc.MiscFlags = 0;
auto d3dDevice =
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
return d3dDevice->CreateTexture2D(&map_desc, nullptr,
d3d11_texture_mapped_.put());
}
void WgcSessionImpl::OnFrame(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const& sender,
[[maybe_unused]] winrt::Windows::Foundation::IInspectable const& args) {
std::lock_guard locker(lock_);
auto is_new_size = false;
{
auto frame = sender.TryGetNextFrame();
auto frame_size = frame.ContentSize();
if (frame_size.Width != capture_frame_size_.Width ||
frame_size.Height != capture_frame_size_.Height) {
// The thing we have been capturing has changed size.
// We need to resize our swap chain first, then blit the pixels.
// After we do that, retire the frame and then recreate our frame pool.
is_new_size = true;
capture_frame_size_ = frame_size;
}
// copy to mapped texture
{
if (is_paused_) {
return;
}
auto frame_captured =
GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
if (!d3d11_texture_mapped_ || is_new_size)
CreateMappedTexture(frame_captured);
d3d11_device_context_->CopyResource(d3d11_texture_mapped_.get(),
frame_captured.get());
D3D11_MAPPED_SUBRESOURCE map_result;
HRESULT hr = d3d11_device_context_->Map(
d3d11_texture_mapped_.get(), 0, D3D11_MAP_READ,
0 /*coz we use CreateFreeThreaded, so we cant use flags
D3D11_MAP_FLAG_DO_NOT_WAIT*/
,
&map_result);
if (FAILED(hr)) {
OutputDebugStringW(
(L"map resource failed: " + std::to_wstring(hr)).c_str());
}
// copy data from map_result.pData
if (map_result.pData && observer_) {
observer_->OnFrame(
wgc_session_frame{static_cast<unsigned int>(frame_size.Width),
static_cast<unsigned int>(frame_size.Height),
map_result.RowPitch,
const_cast<const unsigned char*>(
(unsigned char*)map_result.pData)},
id_);
}
d3d11_device_context_->Unmap(d3d11_texture_mapped_.get(), 0);
}
}
if (is_new_size) {
capture_framepool_.Recreate(d3d11_direct_device_,
winrt::Windows::Graphics::DirectX::
DirectXPixelFormat::B8G8R8A8UIntNormalized,
2, capture_frame_size_);
}
}
void WgcSessionImpl::OnClosed(
winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
winrt::Windows::Foundation::IInspectable const&) {
OutputDebugStringW(L"WgcSessionImpl::OnClosed");
}
int WgcSessionImpl::Initialize() {
if (is_initialized_) return 0;
if (!(d3d11_direct_device_ = CreateD3D11Device())) {
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl;
return 1;
}
try {
if (target_.is_window)
capture_item_ = CreateCaptureItemForWindow(target_.hwnd);
else
capture_item_ = CreateCaptureItemForMonitor(target_.hmonitor);
// Set up
auto d3d11_device =
GetDXGIInterfaceFromObject<ID3D11Device>(d3d11_direct_device_);
d3d11_device->GetImmediateContext(d3d11_device_context_.put());
} catch (winrt::hresult_error) {
LOG_ERROR("AE_WGC_CREATE_CAPTURER_FAILED");
return 86;
} catch (...) {
return 86;
}
is_initialized_ = true;
return 0;
}
void WgcSessionImpl::CleanUp() {
std::lock_guard locker(lock_);
auto expected = false;
if (cleaned_.compare_exchange_strong(expected, true)) {
capture_close_trigger_.revoke();
capture_framepool_trigger_.revoke();
if (capture_framepool_) capture_framepool_.Close();
if (capture_session_) capture_session_.Close();
capture_framepool_ = nullptr;
capture_session_ = nullptr;
capture_item_ = nullptr;
is_initialized_ = false;
}
}
LRESULT CALLBACK WindowProc(HWND window, UINT message, WPARAM w_param,
LPARAM l_param) {
return DefWindowProc(window, message, w_param, l_param);
}
// void WgcSessionImpl::message_func() {
// const std::wstring kClassName = L"am_fake_window";
// WNDCLASS wc = {};
// wc.style = CS_HREDRAW | CS_VREDRAW;
// wc.lpfnWndProc = DefWindowProc;
// wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
// wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
// wc.lpszClassName = kClassName.c_str();
// if (!::RegisterClassW(&wc)) return;
// hwnd_ = ::CreateWindowW(kClassName.c_str(), nullptr, WS_OVERLAPPEDWINDOW,
// 0,
// 0, 0, 0, nullptr, nullptr, nullptr, nullptr);
// MSG msg;
// while (is_running_) {
// while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
// if (!is_running_) break;
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }
// Sleep(10);
// }
// ::CloseWindow(hwnd_);
// ::DestroyWindow(hwnd_);
// }

View File

@@ -10,17 +10,15 @@
#include "wgc_session.h"
namespace crossdesk {
class WgcSessionImpl : public WgcSession {
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
IDirect3DDxgiInterfaceAccess : ::IUnknown {
virtual HRESULT __stdcall GetInterface(GUID const& id, void** object) = 0;
IDirect3DDxgiInterfaceAccess : ::IUnknown {
virtual HRESULT __stdcall GetInterface(GUID const &id, void **object) = 0;
};
template <typename T>
inline auto GetDXGIInterfaceFromObject(
winrt::Windows::Foundation::IInspectable const& object) {
winrt::Windows::Foundation::IInspectable const &object) {
auto access = object.as<IDirect3DDxgiInterfaceAccess>();
winrt::com_ptr<T> result;
winrt::check_hresult(
@@ -46,7 +44,7 @@ class WgcSessionImpl : public WgcSession {
int Initialize(HWND hwnd) override;
int Initialize(HMONITOR hmonitor) override;
void RegisterObserver(wgc_session_observer* observer) override;
void RegisterObserver(wgc_session_observer *observer) override;
int Start() override;
int Stop() override;
@@ -62,11 +60,11 @@ class WgcSessionImpl : public WgcSession {
HRESULT CreateMappedTexture(winrt::com_ptr<ID3D11Texture2D> src_texture,
unsigned int width = 0, unsigned int height = 0);
void OnFrame(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const&
sender,
winrt::Windows::Foundation::IInspectable const& args);
void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&,
winrt::Windows::Foundation::IInspectable const&);
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const
&sender,
winrt::Windows::Foundation::IInspectable const &args);
void OnClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const &,
winrt::Windows::Foundation::IInspectable const &);
int Initialize();
void CleanUp();
@@ -80,7 +78,7 @@ class WgcSessionImpl : public WgcSession {
bool is_running_ = false;
bool is_paused_ = false;
wgc_session_observer* observer_ = nullptr;
wgc_session_observer *observer_ = nullptr;
// wgc
winrt::Windows::Graphics::Capture::GraphicsCaptureItem capture_item_{nullptr};
@@ -115,5 +113,5 @@ class WgcSessionImpl : public WgcSession {
// access->GetInterface(winrt::guid_of<T>(), result.put_void()));
// return result;
// }
} // namespace crossdesk
#endif

View File

@@ -9,8 +9,6 @@
#include "rd_log.h"
namespace crossdesk {
constexpr int kSampleRate = 48000;
constexpr pa_sample_format_t kFormat = PA_SAMPLE_S16LE;
constexpr int kChannels = 1;
@@ -267,5 +265,4 @@ int SpeakerCapturerLinux::Pause() {
int SpeakerCapturerLinux::Resume() {
paused_ = false;
return 0;
}
} // namespace crossdesk
}

View File

@@ -18,8 +18,6 @@
#include "speaker_capturer.h"
namespace crossdesk {
class SpeakerCapturerLinux : public SpeakerCapturer {
public:
SpeakerCapturerLinux();
@@ -52,5 +50,5 @@ class SpeakerCapturerLinux : public SpeakerCapturer {
std::mutex state_mtx_;
std::vector<uint8_t> frame_cache_;
};
} // namespace crossdesk
#endif

View File

@@ -12,8 +12,6 @@
#include "speaker_capturer.h"
namespace crossdesk {
class SpeakerCapturerMacosx : public SpeakerCapturer {
public:
SpeakerCapturerMacosx();
@@ -35,5 +33,5 @@ class SpeakerCapturerMacosx : public SpeakerCapturer {
class Impl;
Impl* impl_ = nullptr;
};
} // namespace crossdesk
#endif

View File

@@ -5,17 +5,13 @@
#include "rd_log.h"
#include "speaker_capturer_macosx.h"
namespace crossdesk {
class SpeakerCapturerMacosx;
}
@interface SpeakerCaptureDelegate : NSObject <SCStreamDelegate, SCStreamOutput>
@property(nonatomic, assign) crossdesk::SpeakerCapturerMacosx* owner;
- (instancetype)initWithOwner:(crossdesk::SpeakerCapturerMacosx*)owner;
@property(nonatomic, assign) SpeakerCapturerMacosx* owner;
- (instancetype)initWithOwner:(SpeakerCapturerMacosx*)owner;
@end
@implementation SpeakerCaptureDelegate
- (instancetype)initWithOwner:(crossdesk::SpeakerCapturerMacosx*)owner {
- (instancetype)initWithOwner:(SpeakerCapturerMacosx*)owner {
self = [super init];
if (self) {
_owner = owner;
@@ -26,32 +22,72 @@ class SpeakerCapturerMacosx;
- (void)stream:(SCStream*)stream
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
ofType:(SCStreamOutputType)type {
if (type != SCStreamOutputTypeAudio) return;
if (type == SCStreamOutputTypeAudio) {
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
size_t length = CMBlockBufferGetDataLength(blockBuffer);
char* dataPtr = NULL;
CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, NULL, &dataPtr);
CMAudioFormatDescriptionRef formatDesc = CMSampleBufferGetFormatDescription(sampleBuffer);
const AudioStreamBasicDescription* asbd =
CMAudioFormatDescriptionGetStreamBasicDescription(formatDesc);
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
size_t length = CMBlockBufferGetDataLength(blockBuffer);
char* dataPtr = NULL;
CMBlockBufferGetDataPointer(blockBuffer, 0, NULL, NULL, &dataPtr);
CMAudioFormatDescriptionRef formatDesc = CMSampleBufferGetFormatDescription(sampleBuffer);
const AudioStreamBasicDescription* asbd =
CMAudioFormatDescriptionGetStreamBasicDescription(formatDesc);
if (_owner->cb_ && dataPtr && length > 0 && asbd) {
std::vector<short> out_pcm16;
if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) {
int channels = asbd->mChannelsPerFrame;
int samples = (int)(length / sizeof(float));
float* floatData = (float*)dataPtr;
std::vector<short> pcm16(samples);
for (int i = 0; i < samples; ++i) {
float v = floatData[i];
if (v > 1.0f) v = 1.0f;
if (v < -1.0f) v = -1.0f;
pcm16[i] = (short)(v * 32767.0f);
}
if (_owner->cb_ && dataPtr && length > 0 && asbd) {
std::vector<short> out_pcm16;
// ... 数据转换逻辑保持不变 ...
// 调用回调
size_t frame_bytes = 960; // 480 * 2
size_t total_bytes = out_pcm16.size() * sizeof(short);
unsigned char* p = (unsigned char*)out_pcm16.data();
for (size_t offset = 0; offset + frame_bytes <= total_bytes; offset += frame_bytes) {
_owner->cb_(p + offset, frame_bytes, "audio");
if (channels > 1) {
int mono_samples = samples / channels;
out_pcm16.resize(mono_samples);
for (int i = 0; i < mono_samples; ++i) {
int sum = 0;
for (int c = 0; c < channels; ++c) {
sum += pcm16[i * channels + c];
}
out_pcm16[i] = sum / channels;
}
} else {
out_pcm16 = std::move(pcm16);
}
} else if (asbd->mBitsPerChannel == 16) {
int channels = asbd->mChannelsPerFrame;
int samples = (int)(length / 2);
short* src = (short*)dataPtr;
if (channels > 1) {
int mono_samples = samples / channels;
out_pcm16.resize(mono_samples);
for (int i = 0; i < mono_samples; ++i) {
int sum = 0;
for (int c = 0; c < channels; ++c) {
sum += src[i * channels + c];
}
out_pcm16[i] = sum / channels;
}
} else {
out_pcm16.assign(src, src + samples);
}
}
size_t frame_bytes = 960; // 480 * 2
size_t total_bytes = out_pcm16.size() * sizeof(short);
unsigned char* p = (unsigned char*)out_pcm16.data();
for (size_t offset = 0; offset + frame_bytes <= total_bytes; offset += frame_bytes) {
_owner->cb_(p + offset, frame_bytes, "audio");
}
}
}
}
@end
namespace crossdesk {
class SpeakerCapturerMacosx::Impl {
public:
SCStreamConfiguration* config = nil;
@@ -226,4 +262,3 @@ int SpeakerCapturerMacosx::Destroy() {
int SpeakerCapturerMacosx::Pause() { return 0; }
int SpeakerCapturerMacosx::Resume() { return Start(); }
} // namespace crossdesk

View File

@@ -9,11 +9,9 @@
#include <functional>
namespace crossdesk {
class SpeakerCapturer {
public:
typedef std::function<void(unsigned char*, size_t, const char*)>
typedef std::function<void(unsigned char *, size_t, const char *)>
speaker_data_cb;
public:
@@ -25,5 +23,5 @@ class SpeakerCapturer {
virtual int Start() = 0;
virtual int Stop() = 0;
};
} // namespace crossdesk
#endif

View File

@@ -15,8 +15,6 @@
#include "speaker_capturer_macosx.h"
#endif
namespace crossdesk {
class SpeakerCapturerFactory {
public:
virtual ~SpeakerCapturerFactory() {}
@@ -34,5 +32,5 @@ class SpeakerCapturerFactory {
#endif
}
};
} // namespace crossdesk
#endif

View File

@@ -7,8 +7,6 @@
#define SAVE_AUDIO_FILE 0
namespace crossdesk {
static ma_device_config device_config_;
static ma_device device_;
static ma_format format_ = ma_format_s16;
@@ -101,4 +99,3 @@ int SpeakerCapturerWasapi::Destroy() {
}
int SpeakerCapturerWasapi::Pause() { return 0; }
} // namespace crossdesk

View File

@@ -9,8 +9,6 @@
#include "speaker_capturer.h"
namespace crossdesk {
class SpeakerCapturerWasapi : public SpeakerCapturer {
public:
SpeakerCapturerWasapi();
@@ -33,5 +31,5 @@ class SpeakerCapturerWasapi : public SpeakerCapturer {
private:
bool inited_ = false;
};
} // namespace crossdesk
#endif

View File

@@ -21,7 +21,7 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
namespace crossdesk {
static std::string test;
bool LoadTextureFromMemory(const void* data, size_t data_size,
SDL_Renderer* renderer, SDL_Texture** out_texture,
@@ -430,4 +430,3 @@ std::string Thumbnail::AES_decrypt(const std::string& ciphertext,
return std::string(reinterpret_cast<char*>(plaintext), plaintext_len);
}
} // namespace crossdesk

View File

@@ -14,8 +14,6 @@
#include <unordered_map>
#include <vector>
namespace crossdesk {
class Thumbnail {
public:
struct RecentConnection {
@@ -85,5 +83,5 @@ class Thumbnail {
unsigned char ciphertext_[64];
unsigned char decryptedtext_[64];
};
} // namespace crossdesk
#endif

194
thirdparty/imgui/port/xmake.lua vendored Normal file
View File

@@ -0,0 +1,194 @@
add_rules("mode.debug", "mode.release")
add_rules("utils.install.cmake_importfiles")
set_languages("cxx14")
option("dx9", {showmenu = true, default = false})
option("dx10", {showmenu = true, default = false})
option("dx11", {showmenu = true, default = false})
option("dx12", {showmenu = true, default = false})
option("glfw", {showmenu = true, default = false})
option("opengl2", {showmenu = true, default = false})
option("opengl3", {showmenu = true, default = false})
option("glad", {showmenu = true, default = false})
option("sdl2", {showmenu = true, default = false})
option("sdl2_renderer", {showmenu = true, default = false})
option("sdl3", {showmenu = true, default = false})
option("sdl3_renderer", {showmenu = true, default = false})
option("sdl3_gpu", {showmenu = true, default = false})
option("vulkan", {showmenu = true, default = false})
option("win32", {showmenu = true, default = false})
option("osx", {showmenu = true, default = false})
option("wgpu", {showmenu = true, default = false})
option("freetype", {showmenu = true, default = false})
option("user_config", {showmenu = true, default = nil, type = "string"})
option("wchar32", {showmenu = true, default = false})
if has_config("glfw") then
add_requires("glfw")
end
if has_config("glad") then
add_requires("glad")
end
if has_config("sdl2_renderer") then
add_requires("libsdl2 >=2.0.17")
elseif has_config("sdl2") then
add_requires("libsdl2")
end
if has_config("sdl3") or has_config("sdl3_renderer") or has_config("sdl3_gpu") then
add_requires("libsdl3")
end
if has_config("vulkan") then
add_requires("vulkan-headers")
end
if has_config("wgpu") then
add_requires("wgpu-native")
end
if has_config("freetype") then
add_requires("freetype")
end
target("imgui")
set_kind("$(kind)")
add_files("*.cpp", "misc/cpp/*.cpp")
add_headerfiles("*.h", "(misc/cpp/*.h)")
add_includedirs(".", "misc/cpp")
if is_kind("shared") and is_plat("windows", "mingw") then
add_defines("IMGUI_API=__declspec(dllexport)")
end
if has_config("dx9") then
add_files("backends/imgui_impl_dx9.cpp")
add_headerfiles("(backends/imgui_impl_dx9.h)")
end
if has_config("dx10") then
add_files("backends/imgui_impl_dx10.cpp")
add_headerfiles("(backends/imgui_impl_dx10.h)")
end
if has_config("dx11") then
add_files("backends/imgui_impl_dx11.cpp")
add_headerfiles("(backends/imgui_impl_dx11.h)")
end
if has_config("dx12") then
add_files("backends/imgui_impl_dx12.cpp")
add_headerfiles("(backends/imgui_impl_dx12.h)")
end
if has_config("glfw") then
add_files("backends/imgui_impl_glfw.cpp")
add_headerfiles("(backends/imgui_impl_glfw.h)")
add_packages("glfw")
end
if has_config("opengl2") then
add_files("backends/imgui_impl_opengl2.cpp")
add_headerfiles("(backends/imgui_impl_opengl2.h)")
end
if has_config("opengl3") then
add_files("backends/imgui_impl_opengl3.cpp")
add_headerfiles("(backends/imgui_impl_opengl3.h)")
if has_config("glad") then
add_defines("IMGUI_IMPL_OPENGL_LOADER_GLAD")
add_packages("glad")
else
add_headerfiles("(backends/imgui_impl_opengl3_loader.h)")
end
end
if has_config("sdl2") then
if os.exists("backends/imgui_impl_sdl2.cpp") then
add_files("backends/imgui_impl_sdl2.cpp")
add_headerfiles("(backends/imgui_impl_sdl2.h)")
else
add_files("backends/imgui_impl_sdl.cpp")
add_headerfiles("(backends/imgui_impl_sdl.h)")
end
add_packages("libsdl2")
end
if has_config("sdl2_renderer") then
if os.exists("backends/imgui_impl_sdlrenderer2.cpp") then
add_files("backends/imgui_impl_sdlrenderer2.cpp")
add_headerfiles("(backends/imgui_impl_sdlrenderer2.h)")
else
add_files("backends/imgui_impl_sdlrenderer.cpp")
add_headerfiles("(backends/imgui_impl_sdlrenderer.h)")
end
add_packages("libsdl2")
end
if has_config("sdl3") then
add_files("backends/imgui_impl_sdl3.cpp")
add_headerfiles("(backends/imgui_impl_sdl3.h)")
add_packages("libsdl3")
end
if has_config("sdl3_renderer") then
add_files("backends/imgui_impl_sdlrenderer3.cpp")
add_headerfiles("(backends/imgui_impl_sdlrenderer3.h)")
add_packages("libsdl3")
end
if has_config("sdl3_gpu") then
add_files("backends/imgui_impl_sdlgpu3.cpp")
add_headerfiles("backends/imgui_impl_sdlgpu3.h","backends/imgui_impl_sdlgpu3_shaders.h")
add_packages("libsdl3")
end
if has_config("vulkan") then
add_files("backends/imgui_impl_vulkan.cpp")
add_headerfiles("(backends/imgui_impl_vulkan.h)")
add_packages("vulkan-headers")
end
if has_config("win32") then
add_files("backends/imgui_impl_win32.cpp")
add_headerfiles("(backends/imgui_impl_win32.h)")
end
if has_config("osx") then
add_frameworks("Cocoa", "Carbon", "GameController")
add_files("backends/imgui_impl_osx.mm")
add_headerfiles("(backends/imgui_impl_osx.h)")
end
if has_config("wgpu") then
add_files("backends/imgui_impl_wgpu.cpp")
add_headerfiles("(backends/imgui_impl_wgpu.h)")
add_packages("wgpu-native")
end
if has_config("freetype") then
add_files("misc/freetype/imgui_freetype.cpp")
add_headerfiles("misc/freetype/imgui_freetype.h")
add_packages("freetype")
add_defines("IMGUI_ENABLE_FREETYPE")
end
if has_config("user_config") then
local user_config = get_config("user_config")
add_defines("IMGUI_USER_CONFIG=\"".. user_config .."\"")
end
if has_config("wchar32") then
add_defines("IMGUI_USE_WCHAR32")
end
after_install(function (target)
local config_file = path.join(target:installdir(), "include/imconfig.h")
if has_config("wchar32") then
io.gsub(config_file, "//#define IMGUI_USE_WCHAR32", "#define IMGUI_USE_WCHAR32")
end
if has_config("freetype") then
io.gsub(config_file, "//#define IMGUI_ENABLE_FREETYPE", "#define IMGUI_ENABLE_FREETYPE")
end
end)

227
thirdparty/imgui/xmake.lua vendored Normal file
View File

@@ -0,0 +1,227 @@
package("imgui")
set_homepage("https://github.com/ocornut/imgui")
set_description("Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies")
set_license("MIT")
add_urls("https://github.com/ocornut/imgui/archive/refs/tags/$(version).tar.gz")
add_urls("https://github.com/ocornut/imgui.git", {alias = "git"})
-- don't forget to add the docking versions as well
add_versions("v1.92.0", "42250c45df2736bcef867ae4ff404d138e5135cd36466c63143b1ea3b1c81091")
add_versions("v1.91.9", "3872a5f90df78fced023c1945f4466b654fd74573370b77b17742149763a7a7c")
add_versions("v1.91.8", "db3a2e02bfd6c269adf0968950573053d002f40bdfb9ef2e4a90bce804b0f286")
add_versions("v1.91.7", "2001dab4bdd7d178d8277d3b17c40aa1ff1e76e2ccac5e7ab8c6daf9756312c2")
add_versions("v1.91.6", "c5fbc5dcab1d46064001c3b84d7a88812985cde7e0e9ced03f5677bec1ba502a")
add_versions("v1.91.5", "2aa2d169c569368439e5d5667e0796d09ca5cc6432965ce082e516937d7db254")
add_versions("v1.91.4", "a455c28d987c78ddf56aab98ce0ff0fda791a23a2ec88ade46dd106b837f0923")
add_versions("v1.91.3", "29949d7b300c30565fbcd66398100235b63aa373acfee0b76853a7aeacd1be28")
add_versions("v1.91.2", "a3c4fd857a0a48f6edad3e25de68fa1e96d2437f1665039714d1de9ad579b8d0")
add_versions("v1.91.1", "2c13a8909f75222c836abc9b3f60cef31c445f3f41f95d8242118ea789d145ca")
add_versions("v1.91.0", "6e62c87252e6b3725ba478a1c04dc604aa0aaeec78fedcf4011f1e52548f4cc9")
add_versions("v1.90.9", "04943919721e874ac75a2f45e6eb6c0224395034667bf508923388afda5a50bf")
add_versions("v1.90.8", "f606b4fb406aa0f8dad36d4a9dd3d6f0fd39f5f0693e7468abc02d545fb505ae")
add_versions("v1.90.7", "872574217643d4ad7e9e6df420bb8d9e0d468fb90641c2bf50fd61745e05de99")
add_versions("v1.90.6", "70b4b05ac0938e82b4d5b8d59480d3e2ca63ca570dfb88c55023831f387237ad")
add_versions("v1.90.5", "e94b48dba7311c85ba8e3e6fe7c734d76a0eed21b2b42c5180fd5706d1562241")
add_versions("v1.90.4", "5d9dc738af74efa357f2a9fc39fe4a28d29ef1dfc725dd2977ccf3f3194e996e")
add_versions("v1.90.3", "40b302d01092c9393373b372fe07ea33ac69e9491893ebab3bf952b2c1f5fd23")
add_versions("v1.90.2", "452d1c11e5c4b4dfcca272915644a65f1c076498e8318b141ca75cd30470dd68")
add_versions("v1.90.1", "21dcc985bb2ae8fe48047c86135dbc438d6980a8f2e08babbda5be820592f282")
add_versions("v1.90", "170986e6a4b83d165bfc1d33c2c5a5bc2d67e5b97176287485c51a2299249296")
add_versions("v1.89.9", "1acc27a778b71d859878121a3f7b287cd81c29d720893d2b2bf74455bf9d52d6")
add_versions("v1.89.8", "6680ccc32430009a8204291b1268b2367d964bd6d1b08a4e0358a017eb8e8c9e")
add_versions("v1.89.7", "115ee9e242af98a884302ac0f6ca3b2b26b1f10c660205f5e7ad9f1d1c96d269")
add_versions("v1.89.6", "e95d1cba1481e66386acda3e7da19cd738da86c6c2a140a48fa55046e5f6e208")
add_versions("v1.89.5", "eab371005c86dd029523a0c4ba757840787163740d45c1f4e5a110eb21820546")
add_versions("v1.89.4", "69f1e83adcab3fdd27b522f5075f407361b0d3875e3522b13d33bc2ae2c7d48c")
add_versions("v1.89.3", "3b665fadd5580b7ef494d5d8bb1c12b2ec53ee723034caf43332956381f5d631")
add_versions("v1.89", "4038b05bd44c889cf40be999656d3871a0559916708cb52a6ae2fa6fa35c5c60")
add_versions("v1.88", "9f14c788aee15b777051e48f868c5d4d959bd679fc5050e3d2a29de80d8fd32e")
add_versions("v1.87", "b54ceb35bda38766e36b87c25edf7a1cd8fd2cb8c485b245aedca6fb85645a20")
add_versions("v1.86", "6ba6ae8425a19bc52c5e067702c48b70e4403cd339cba02073a462730a63e825")
add_versions("v1.85", "7ed49d1f4573004fa725a70642aaddd3e06bb57fcfe1c1a49ac6574a3e895a77")
add_versions("v1.84.2", "35cb5ca0fb42cb77604d4f908553f6ef3346ceec4fcd0189675bdfb764f62b9b")
add_versions("v1.84.1", "292ab54cfc328c80d63a3315a242a4785d7c1cf7689fbb3d70da39b34db071ea")
add_versions("v1.83", "ccf3e54b8d1fa30dd35682fc4f50f5d2fe340b8e29e08de71287d0452d8cc3ff")
add_versions("v1.82", "fefa2804bd55f3d25b134af08c0e1f86d4d059ac94cef3ee7bd21e2f194e5ce5")
add_versions("v1.81", "f7c619e03a06c0f25e8f47262dbc32d61fd033d2c91796812bf0f8c94fca78fb")
add_versions("v1.80", "d7e4e1c7233409018437a646680316040e6977b9a635c02da93d172baad94ce9")
add_versions("v1.79", "f1908501f6dc6db8a4d572c29259847f6f882684b10488d3a8d2da31744cd0a4")
add_versions("v1.78", "f70bbb17581ee2bd42fda526d9c3dc1a5165f3847ff047483d4d7980e166f9a3")
add_versions("v1.77", "c0dae830025d4a1a169df97409709f40d9dfa19f8fc96b550052224cbb238fa8")
add_versions("v1.76", "e482dda81330d38c87bd81597cacaa89f05e20ed2c4c4a93a64322e97565f6dc")
add_versions("v1.75", "1023227fae4cf9c8032f56afcaea8902e9bfaad6d9094d6e48fb8f3903c7b866")
add_versions("git:v1.92.0-docking", "v1.92.0-docking")
add_versions("git:v1.91.9-docking", "v1.91.9-docking")
add_versions("git:v1.91.8-docking", "v1.91.8-docking")
add_versions("git:v1.91.7-docking", "v1.91.7-docking")
add_versions("git:v1.91.6-docking", "v1.91.6-docking")
add_versions("git:v1.91.5-docking", "v1.91.5-docking")
add_versions("git:v1.91.4-docking", "v1.91.4-docking")
add_versions("git:v1.91.3-docking", "v1.91.3-docking")
add_versions("git:v1.91.2-docking", "v1.91.2-docking")
add_versions("git:v1.91.1-docking", "v1.91.1-docking")
add_versions("git:v1.91.0-docking", "v1.91.0-docking")
add_versions("git:v1.90.9-docking", "v1.90.9-docking")
add_versions("git:v1.90.8-docking", "v1.90.8-docking")
add_versions("git:v1.90.7-docking", "v1.90.7-docking")
add_versions("git:v1.90.6-docking", "v1.90.6-docking")
add_versions("git:v1.90.5-docking", "v1.90.5-docking")
add_versions("git:v1.90.4-docking", "v1.90.4-docking")
add_versions("git:v1.90.3-docking", "v1.90.3-docking")
add_versions("git:v1.90.2-docking", "v1.90.2-docking")
add_versions("git:v1.90.1-docking", "v1.90.1-docking")
add_versions("git:v1.90-docking", "v1.90-docking")
add_versions("git:v1.89.9-docking", "v1.89.9-docking")
add_versions("git:v1.89.8-docking", "v1.89.8-docking")
add_versions("git:v1.89.7-docking", "v1.89.7-docking")
add_versions("git:v1.89.6-docking", "823a1385a269d923d35b82b2f470f3ae1fa8b5a3")
add_versions("git:v1.89.5-docking", "0ea3b87bd63ecbf359585b7c235839146e84dedb")
add_versions("git:v1.89.4-docking", "9e30fb0ec1b44dc1b041db6bdd53b130b2a18509")
add_versions("git:v1.89.3-docking", "192196711a7d0d7c2d60454d42654cf090498a74")
add_versions("git:v1.89-docking", "94e850fd6ff9eceb98fda3147e3ffd4781ad2dc7")
add_versions("git:v1.88-docking", "9cd9c2eff99877a3f10a7f9c2a3a5b9c15ea36c6")
add_versions("git:v1.87-docking", "1ee252772ae9c0a971d06257bb5c89f628fa696a")
add_versions("git:v1.85-docking", "dc8c3618e8f8e2dada23daa1aa237626af341fd8")
add_versions("git:v1.83-docking", "80b5fb51edba2fd3dea76ec3e88153e2492243d1")
-- Fix conflicting IMGUI_API definitions in v1.92.0 only (https://github.com/ocornut/imgui/pull/8729)
add_patches("v1.92.0", "patches/v1.92.0/fix_imgui_api.patch", "e8ca0502056acf356f83703e7190dda87fde43ed245f65f0fb55b85cd164ed83")
add_patches("v1.92.0-docking", "patches/v1.92.0/fix_imgui_api.patch", "e8ca0502056acf356f83703e7190dda87fde43ed245f65f0fb55b85cd164ed83")
add_configs("dx9", {description = "Enable the dx9 backend", default = false, type = "boolean"})
add_configs("dx10", {description = "Enable the dx10 backend", default = false, type = "boolean"})
add_configs("dx11", {description = "Enable the dx11 backend", default = false, type = "boolean"})
add_configs("dx12", {description = "Enable the dx12 backend", default = false, type = "boolean"})
add_configs("glfw", {description = "Enable the glfw backend", default = false, type = "boolean"})
add_configs("opengl2", {description = "Enable the opengl2 backend", default = false, type = "boolean"})
add_configs("opengl3", {description = "Enable the opengl3 backend", default = false, type = "boolean"})
add_configs("sdl2", {description = "Enable the sdl2 backend with sdl2_renderer", default = false, type = "boolean"})
add_configs("sdl2_no_renderer", {description = "Enable the sdl2 backend without sdl2_renderer", default = false, type = "boolean"})
add_configs("sdl2_renderer", {description = "Enable the sdl2 renderer backend", default = false, type = "boolean"})
add_configs("sdl3", {description = "Enable the sdl3 backend with sdl3_renderer", default = false, type = "boolean"})
add_configs("sdl3_renderer", {description = "Enable the sdl3 renderer backend", default = false, type = "boolean"})
add_configs("sdl3_gpu", {description = "Enable the sdl3 gpu backend", default = false, type = "boolean"})
add_configs("vulkan", {description = "Enable the vulkan backend", default = false, type = "boolean"})
add_configs("win32", {description = "Enable the win32 backend", default = false, type = "boolean"})
add_configs("osx", {description = "Enable the OS X backend", default = false, type = "boolean"})
add_configs("wgpu", {description = "Enable the wgpu backend", default = false, type = "boolean"})
add_configs("freetype", {description = "Use FreeType to build and rasterize the font atlas", default = false, type = "boolean"})
add_configs("user_config", {description = "Use user config (disables test!)", default = nil, type = "string"})
add_configs("wchar32", {description = "Use 32-bit for ImWchar (default is 16-bit)", default = false, type = "boolean"})
-- deprecated configs (kept for backwards compatibility)
add_configs("sdlrenderer", {description = "(deprecated)", default = false, type = "boolean"})
add_configs("glfw_opengl3", {description = "(deprecated)", default = false, type = "boolean"})
add_configs("glfw_vulkan", {description = "(deprecated)", default = false, type = "boolean"})
add_configs("sdl2_opengl3", {description = "(deprecated)", default = false, type = "boolean"})
add_includedirs("include", "include/imgui", "include/backends", "include/misc/cpp")
if is_plat("windows", "mingw") then
add_syslinks("imm32")
end
on_load(function (package)
-- begin: backwards compatibility
if package:config("sdl2") or package:config("sdlrenderer") then
package:config_set("sdl2_renderer", true)
end
if package:config("glfw_opengl3") then
package:config_set("glfw", true)
package:config_set("opengl3", true)
end
if package:config("glfw_vulkan") then
package:config_set("glfw", true)
package:config_set("vulkan", true)
end
if package:config("sdl2_opengl3") then
package:config_set("sdl2", true)
package:config_set("opengl3", true)
end
-- end: backwards compatibility
if package:config("shared") and is_plat("windows", "mingw") then
package:add("defines", "IMGUI_API=__declspec(dllimport)")
end
if package:config("glfw") then
package:add("deps", "glfw")
end
if package:config("opengl3") then
if not package:gitref() and package:version():lt("1.84") then
package:add("deps", "glad")
package:add("defines", "IMGUI_IMPL_OPENGL_LOADER_GLAD")
end
end
if package:config("sdl2_no_renderer") then
package:add("deps", "libsdl2")
end
if package:config("sdl2_renderer") then
package:add("deps", "libsdl2 >=2.0.17")
end
if package:config("sdl3") or package:config("sdl3_renderer") or package:config("sdl3_gpu") then
package:add("deps", "libsdl3")
end
if package:config("vulkan") then
package:add("deps", "vulkan-headers")
end
if package:config("wgpu") then
package:add("deps", "wgpu-native")
end
if package:config("freetype") then
package:add("deps", "freetype")
end
if package:config("osx") then
package:add("frameworks", "Cocoa", "Carbon", "GameController")
end
end)
on_install(function (package)
local configs = {
dx9 = package:config("dx9"),
dx10 = package:config("dx10"),
dx11 = package:config("dx11"),
dx12 = package:config("dx12"),
glfw = package:config("glfw"),
opengl2 = package:config("opengl2"),
opengl3 = package:config("opengl3"),
glad = package:config("opengl3") and (not package:gitref() and package:version():lt("1.84")),
sdl2 = package:config("sdl2") or package:config("sdl2_no_renderer"),
sdl2_renderer = package:config("sdl2_renderer"),
sdl3 = package:config("sdl3"),
sdl3_renderer = package:config("sdl3_renderer"),
sdl3_gpu = package:config("sdl3_gpu"),
vulkan = package:config("vulkan"),
win32 = package:config("win32"),
osx = package:config("osx"),
wgpu = package:config("wgpu"),
freetype = package:config("freetype"),
user_config = package:config("user_config"),
wchar32 = package:config("wchar32")
}
os.cp(path.join(package:scriptdir(), "port", "xmake.lua"), "xmake.lua")
import("package.tools.xmake").install(package, configs)
end)
on_test(function (package)
if package:config("user_config") ~= nil then return end
local includes = {"imgui.h"}
local defines
if package:config("sdl2_renderer") or package:config("sdl2_no_renderer") then
table.insert(includes, "SDL.h")
defines = "SDL_MAIN_HANDLED"
end
assert(package:check_cxxsnippets({test = [[
void test() {
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImGui::NewFrame();
ImGui::Text("Hello, world!");
ImGui::ShowDemoWindow(NULL);
ImGui::Render();
ImGui::DestroyContext();
}
]]}, {configs = {languages = "c++14", defines = defines}, includes = includes}))
end)

View File

@@ -1,11 +1,8 @@
set_project("crossdesk")
set_license("LGPL-3.0")
option("CROSSDESK_VERSION")
set_default("0.0.0")
set_showmenu(true)
set_description("Set CROSSDESK_VERSION for build")
option_end()
set_version("0.0.1")
add_defines("RD_VERSION=\"0.0.1\"");
add_rules("mode.release", "mode.debug")
set_languages("c++17")
@@ -46,7 +43,7 @@ end
add_packages("spdlog", "imgui")
includes("submodules")
includes("thirdparty")
target("rd_log")
set_kind("object")
@@ -146,18 +143,13 @@ target("assets")
target("gui")
set_kind("object")
add_packages("libyuv")
add_defines("CROSSDESK_VERSION=\"" .. (get_config("CROSSDESK_VERSION") or "Unknown") .. "\"")
add_deps("rd_log", "common", "assets", "config_center", "minirtc",
"path_manager", "screen_capturer", "speaker_capturer",
"device_controller", "thumbnail")
add_files("src/gui/*.cpp", "src/gui/panels/*.cpp", "src/gui/toolbars/*.cpp",
add_files("src/gui/*.cpp", "src/gui/panels/*.cpp", "src/gui/toolbars/*.cpp",
"src/gui/windows/*.cpp")
add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",
add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",
"src/gui/windows", {public = true})
if is_os("windows") then
add_files("src/gui/tray/*.cpp")
add_includedirs("src/gui/tray", {public = true})
end
target("crossdesk")
set_kind("binary")