Compare commits

..

34 Commits

Author SHA1 Message Date
dijunkun
58c24b798e [chore] update README: refresh self-hosted server setup guide 2025-12-09 00:19:25 +08:00
dijunkun
5cc31e5ba3 [fix] fix self-hosted server configuration being reset when disabling self-hosted mode 2025-12-08 18:27:18 +08:00
dijunkun
74fe9bebf5 [fix] fix server settings window height 2025-12-08 17:42:02 +08:00
dijunkun
1f6a2182be [fix] resolve tab bar dragging issue 2025-12-06 18:46:04 +08:00
dijunkun
1a883f0d6c [fix] fix menu BeginPopup & EndPopup pairing 2025-12-05 17:53:17 +08:00
dijunkun
a560b4ca70 [feat] make thumbnail save asynchronous to prevent UI blocking 2025-12-05 17:07:55 +08:00
dijunkun
46f45ed216 [fix] fix tab close button not working in stream window 2025-12-05 15:18:35 +08:00
dijunkun
5c23f1c5e8 [fix] correct tab bar scaling and layout 2025-12-05 15:17:07 +08:00
dijunkun
70ae02549f [fix] correct title bar display 2025-12-05 04:28:33 +08:00
dijunkun
68de995c64 [fix] correct hardware codec setting item display 2025-12-05 00:57:33 +08:00
dijunkun
ed5ddb96fd [refactor] update notification window rendering for high-DPI scaling support 2025-12-04 19:00:37 +08:00
dijunkun
436dfafc2a [refactor] update about window rendering for high-DPI scaling support 2025-12-04 17:51:03 +08:00
dijunkun
5221b193e5 [refactor] update settings window rendering for high-DPI scaling support 2025-12-04 17:23:14 +08:00
dijunkun
fafced23c2 [refactor] update stream window rendering for high-DPI scaling support 2025-12-04 02:11:06 +08:00
dijunkun
1e48b645ca [refactor] update recent connections panel rendering for high-DPI scaling support 2025-12-04 00:14:09 +08:00
dijunkun
49ed0200e7 [refactor] update connection status window rendering for high-DPI scaling support 2025-12-03 21:54:10 +08:00
dijunkun
24873afe64 [refactor] update remote peer panel rendering for high-DPI scaling support 2025-12-03 21:17:11 +08:00
dijunkun
d21e1bd422 [refactor] update remote peer panel rendering for high-DPI scaling support 2025-12-03 17:36:19 +08:00
dijunkun
be044c248b [refactor] update local peer panel rendering for high-DPI scaling support 2025-12-03 17:12:35 +08:00
dijunkun
49cbbc3363 [refactor] update status bar rendering for high-DPI scaling support 2025-12-03 12:45:01 +08:00
dijunkun
1e20cb806b [refactor] update title bar rendering for high-DPI scaling support 2025-12-03 04:20:49 +08:00
dijunkun
2e52818f6f fix: correct array deletion and improve state management in WGC screen capturer 2025-12-01 23:06:46 +08:00
dijunkun
b50f386713 [fix] fix system_chinese_font_ usage to avoid dangling font pointer after closing stream window 2025-12-01 23:03:45 +08:00
dijunkun
280e011ae4 [fix] update RecentConnectionsWindow layout 2025-12-01 17:16:28 +08:00
dijunkun
8d09bf53c3 [fix] fix UpdateNotificationWindow dpi scaling 2025-12-01 13:52:39 +08:00
dijunkun
131b4f1795 [fix] resolve compilation errors on Linux 2025-12-01 13:07:36 +08:00
dijunkun
7d3ecf789d [fix] fix control bar dpi scaling 2025-12-01 11:30:35 +08:00
dijunkun
37797bf873 [fix] fix DPI scaling issues 2025-12-01 04:54:30 +08:00
dijunkun
91d42b6561 [fix] macOS: fix audio capture, refs #29 2025-11-30 17:13:02 +08:00
dijunkun
feb9f2f460 [revert] revert to the pre-lock version 2025-11-28 11:44:08 +08:00
Junkun Di
9c1753c78c [chroe] add issue templates 2025-11-28 11:34:22 +08:00
dijunkun
7370ff5b30 [chore] add HelloGitHub badge 2025-11-28 11:10:41 +08:00
dijunkun
f6eda34dbd [fix] fix dead lock during connecting 2025-11-28 10:02:57 +08:00
dijunkun
5d9a0a3ea5 [fix] fix dead lock during peer init 2025-11-28 09:32:21 +08:00
34 changed files with 4721 additions and 4326 deletions

35
.github/ISSUE_TEMPLATE/问题反馈.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: 问题反馈
about: Create a report to help us improve
title: ''
labels: bug
assignees: kunkundi
---
**描述问题**
清晰简洁地描述遇到的错误。
**复现步骤**
复现该问题的步骤:
1. 前往 '...'
2. 点击 '....'
3. 出现错误
**预期行为**
清晰简洁地描述你期望发生的行为。
**截图**
如果适用,请添加截图以帮助说明问题。
**桌面端信息(请填写以下内容):**
- 操作系统: [例如 Windows 11]
- 版本: [例如 v1.1.10]
**移动端信息(请填写以下内容):**
- 设备: [例如 iPhone 17]
- 操作系统: [例如 iOS 26.1]
- 浏览器: [例如 系统浏览器、Safari]
**补充信息**
在此添加与问题相关的其他上下文内容。

150
README.md
View File

@@ -1,5 +1,6 @@
# CrossDesk # CrossDesk
<a href="https://hellogithub.com/repository/kunkundi/crossdesk" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=55d41367570345f1838e02fd12be7961&claim_uid=cb0OpZRrBuGVAfL&theme=small" alt="FeaturedHelloGitHub" /></a>
[![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-brightgreen.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) [![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/web-client) [![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/web-client)
@@ -178,145 +179,42 @@ sudo docker run -d \
-e COTURN_PORT=xxxx \ -e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \ -e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \ -e MAX_PORT=xxxxx \
-v /path/to/your/certs:/crossdesk-server/certs \ -v /var/lib/crossdesk:/var/lib/crossdesk \
-v /path/to/your/db:/crossdesk-server/db \ -v /var/log/crossdesk:/var/log/crossdesk \
-v /path/to/your/logs:/crossdesk-server/logs \ crossdesk/crossdesk-server:v1.1.2
crossdesk/crossdesk-server:v1.1.1
``` ```
上述命令中,用户需注意的参数如下: 上述命令中,用户需注意的参数如下:
**参数**
- EXTERNAL_IP服务器公网 IP , 对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器地址** - EXTERNAL_IP服务器公网 IP , 对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器地址**
- INTERNAL_IP服务器内网 IP - INTERNAL_IP服务器内网 IP
- CROSSDESK_SERVER_PORT自托管服务使用的端口对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口** - CROSSDESK_SERVER_PORT自托管服务使用的端口对应 CrossDesk 客户端**自托管服务器配置**中填写的**服务器端口**
- COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口** - COTURN_PORT: COTURN 服务使用的端口, 对应 CrossDesk 客户端**自托管服务器配置**中填写的**中继服务端口**
- MIN_PORT/MAX_PORTCOTURN 服务使用的端口范围例如MIN_PORT=50000, MAX_PORT=60000范围可根据客户端数量调整。 - MIN_PORT/MAX_PORTCOTURN 服务使用的端口范围例如MIN_PORT=50000, MAX_PORT=60000范围可根据客户端数量调整。
- `-v /var/lib/crossdesk:/var/lib/crossdesk`:持久化数据库和证书文件到宿主机
- /path/to/your/certs证书文件目录 - `-v /var/log/crossdesk:/var/log/crossdesk`:持久化日志文件到宿主机
-
- /path/to/your/dbCrossDesk Server 设备管理数据库
- /path/to/your/logs日志目录
**注意** **注意**
- **/path/to/your/ 是示例路径,请替换为你自己的实际路径。挂载的目录必须事先创建好,否则容器会报错。**
- **服务器需开放端口3478/udp3478/tcpMIN_PORT-MAX_PORT/udpCROSSDESK_SERVER_PORT/tcp。** - **服务器需开放端口3478/udp3478/tcpMIN_PORT-MAX_PORT/udpCROSSDESK_SERVER_PORT/tcp。**
- 如果不挂载 volume容器删除后数据会丢失
- 证书文件会在首次启动时自动生成并持久化到宿主机的 `/var/lib/crossdesk/certs` 路径下
- 数据库文件会自动创建并持久化到宿主机的 `/var/lib/crossdesk/db/crossdesk-server.db` 路径下
- 日志文件会自动创建并持久化到宿主机的 `/var/log/crossdesk/` 路径下
**权限注意**:如果 Docker 自动创建的目录权限不足(属于 root容器内用户无法写入会导致
- 证书生成失败,容器启动脚本会报错退出
- 数据库目录创建失败,程序会抛出异常并崩溃
- 日志目录创建失败,日志文件无法写入(但程序可能继续运行)
**解决方案**:在启动容器前手动设置权限:
```bash
sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
```
## 证书文件 ## 证书文件
客户端需加载根证书文件,服务端需加载服务器私钥和服务器证书文件 在宿主机的 `/var/lib/crossdesk/certs` 路径下可找到证书文件 `crossdesk.cn_root.crt`,下载到你的客户端主机,并在客户端的**自托管服务器设置**中选择相应的**证书文件路径**
如果已有SSL证书的用户可以忽略下面的证书生成步骤。
对于无证书的用户,可使用下面的脚本自行生成证书文件:
```
# 创建证书生成脚本
vim generate_certs.sh
```
拷贝到脚本中
```
#!/bin/bash
set -e
# 检查参数
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <SERVER_IP>"
exit 1
fi
SERVER_IP="$1"
# 文件名
ROOT_KEY="crossdesk.cn_root.key"
ROOT_CERT="crossdesk.cn_root.crt"
SERVER_KEY="crossdesk.cn.key"
SERVER_CSR="crossdesk.cn.csr"
SERVER_CERT="crossdesk.cn_bundle.crt"
FULLCHAIN_CERT="crossdesk.cn_fullchain.crt"
# 证书主题
SUBJ="/C=CN/ST=Zhejiang/L=Hangzhou/O=CrossDesk/OU=CrossDesk/CN=$SERVER_IP"
# 1. 生成根证书
echo "Generating root private key..."
openssl genrsa -out "$ROOT_KEY" 4096
echo "Generating self-signed root certificate..."
openssl req -x509 -new -nodes -key "$ROOT_KEY" -sha256 -days 3650 -out "$ROOT_CERT" -subj "$SUBJ"
# 2. 生成服务器私钥
echo "Generating server private key..."
openssl genrsa -out "$SERVER_KEY" 2048
# 3. 生成服务器 CSR
echo "Generating server CSR..."
openssl req -new -key "$SERVER_KEY" -out "$SERVER_CSR" -subj "$SUBJ"
# 4. 生成临时 OpenSSL 配置文件,加入 SAN
SAN_CONF="san.cnf"
cat > $SAN_CONF <<EOL
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[ req_distinguished_name ]
C = CN
ST = Zhejiang
L = Hangzhou
O = CrossDesk
OU = CrossDesk
CN = $SERVER_IP
[ req_ext ]
subjectAltName = IP:$SERVER_IP
EOL
# 5. 用根证书签发服务器证书(包含 SAN
echo "Signing server certificate with root certificate..."
openssl x509 -req -in "$SERVER_CSR" -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial \
-out "$SERVER_CERT" -days 3650 -sha256 -extfile "$SAN_CONF" -extensions req_ext
# 6. 生成完整链证书
cat "$SERVER_CERT" "$ROOT_CERT" > "$FULLCHAIN_CERT"
# 7. 清理中间文件
rm -f "$ROOT_CERT.srl" "$SAN_CONF" "$ROOT_KEY" "$SERVER_CSR" "FULLCHAIN_CERT"
echo "Generation complete. Deployment files:"
echo " Client root certificate: $ROOT_CERT"
echo " Server private key: $SERVER_KEY"
echo " Server certificate: $SERVER_CERT"
```
执行
```
chmod +x generate_certs.sh
./generate_certs.sh 服务器公网IP
# 例如 ./generate_certs.sh 111.111.111.111
```
输出如下:
```
Generating root private key...
Generating self-signed root certificate...
Generating server private key...
Generating server CSR...
Signing server certificate with root certificate...
Certificate request self-signature ok
subject=C = CN, ST = Zhejiang, L = Hangzhou, O = CrossDesk, OU = CrossDesk, CN = xxx.xxx.xxx.xxx
cleaning up intermediate files...
Generation complete. Deployment files::
Client root certificate:: crossdesk.cn_root.crt
Server private key: crossdesk.cn.key
Server certificate: crossdesk.cn_bundle.crt
```
### 服务端
**crossdesk.cn.key****crossdesk.cn_bundle.crt** 放置到 **/path/to/your/certs** 目录下。
### 客户端 ### 客户端
1. 点击右上角设置进入设置页面。<br> 1. 点击右上角设置进入设置页面。<br>

View File

@@ -1,5 +1,6 @@
# CrossDesk # CrossDesk
<a href="https://hellogithub.com/repository/kunkundi/crossdesk" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=55d41367570345f1838e02fd12be7961&claim_uid=cb0OpZRrBuGVAfL&theme=small" alt="FeaturedHelloGitHub" /></a>
[![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-brightgreen.svg)]()
[![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) [![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/web-client) [![GitHub last commit](https://img.shields.io/github/last-commit/kunkundi/crossdesk)](https://github.com/kunkundi/crossdesk/commits/web-client)
@@ -186,142 +187,44 @@ sudo docker run -d \
-e COTURN_PORT=xxxx \ -e COTURN_PORT=xxxx \
-e MIN_PORT=xxxxx \ -e MIN_PORT=xxxxx \
-e MAX_PORT=xxxxx \ -e MAX_PORT=xxxxx \
-v /path/to/your/certs:/crossdesk-server/certs \ -v /var/lib/crossdesk:/var/lib/crossdesk \
-v /path/to/your/db:/crossdesk-server/db \ -v /var/log/crossdesk:/var/log/crossdesk \
-v /path/to/your/logs:/crossdesk-server/logs \ crossdesk/crossdesk-server:v1.1.2
crossdesk/crossdesk-server:v1.1.1
``` ```
The parameters you need to pay attention to are as follows: The parameters you need to pay attention to are as follows:
- **EXTERNAL_IP**: The server's public IP, corresponding to the **Server Address** in the CrossDesk client **Self-Hosted Server Configuration**. **Parameters**
- **EXTERNAL_IP**: The servers public IP. This corresponds to **Server Address** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **INTERNAL_IP**: The servers internal IP.
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted service. This corresponds to **Server Port** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **COTURN_PORT**: The port used by the COTURN service. This corresponds to **Relay Service Port** in the CrossDesk clients **Self-Hosted Server Configuration**.
- **MIN_PORT / MAX_PORT**: The port range used by the COTURN service. Example: `MIN_PORT=50000`, `MAX_PORT=60000`. Adjust the range depending on the number of clients.
- `-v /var/lib/crossdesk:/var/lib/crossdesk`: Persists database and certificate files on the host machine.
- `-v /var/log/crossdesk:/var/log/crossdesk`: Persists log files on the host machine.
- **INTERNAL_IP**: The server's internal IP. **Notes**
- **The server must open the following ports: 3478/udp, 3478/tcp, MIN_PORTMAX_PORT/udp, and CROSSDESK_SERVER_PORT/tcp.**
- If you dont mount volumes, all data will be lost when the container is removed.
- Certificate files will be automatically generated on first startup and persisted to the host at `/var/lib/crossdesk/certs`.
- The database file will be automatically created and stored at `/var/lib/crossdesk/db/crossdesk-server.db`.
- Log files will be created and stored at `/var/log/crossdesk/`.
- **CROSSDESK_SERVER_PORT**: The port used by the self-hosted server, corresponding to the **Server Port** in the CrossDesk client **Self-Hosted Server Configuration**. **Permission Notice**
If the directories automatically created by Docker belong to root and have insufficient write permissions, the container user may not be able to write to them. This can cause:
- Certificate generation failure, leading to startup script errors and container exit.
- Database directory creation failure, causing the program to throw exceptions and crash.
- Log directory creation failure, preventing logs from being written (though the program may continue running).
- **COTURN_PORT**: The port used by Coturn, corresponding to the **Relay Server Port** in the CrossDesk client **Self-Hosted Server Configuration**. **Solution:** Manually set permissions before starting the container:
```bash
- **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. sudo mkdir -p /var/lib/crossdesk /var/log/crossdesk
sudo chown -R $(id -u):$(id -g) /var/lib/crossdesk /var/log/crossdesk
- **/path/to/your/certs**: Directory for certificate files.
- **/path/to/your/db**: CrossDesk Server device management database.
- **/path/to/your/logs**: Log directory.
**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.**
## Certificate Files
The client needs to load the root certificate, and the server needs to load the server private key and server certificate.
If you already have an SSL certificate, you can skip the following certificate generation steps.
For users without a certificate, you can use the script below to generate the certificate files:
``` ```
# Create certificate generation script
vim generate_certs.sh
```
Copy the following into the script:
```
#!/bin/bash
set -e
# Check arguments ### Certificate Files
if [ "$#" -ne 1 ]; then You can find the certificate file `crossdesk.cn_root.crt` at `/var/lib/crossdesk/certs` on the host machine.
echo "Usage: $0 <SERVER_IP>" Download it to your client device and select it in the **Certificate File Path** field under the CrossDesk clients **Self-Hosted Server Settings**.
exit 1
fi
SERVER_IP="$1"
# Filenames
ROOT_KEY="crossdesk.cn_root.key"
ROOT_CERT="crossdesk.cn_root.crt"
SERVER_KEY="crossdesk.cn.key"
SERVER_CSR="crossdesk.cn.csr"
SERVER_CERT="crossdesk.cn_bundle.crt"
FULLCHAIN_CERT="crossdesk.cn_fullchain.crt"
# Certificate subject
SUBJ="/C=CN/ST=Zhejiang/L=Hangzhou/O=CrossDesk/OU=CrossDesk/CN=$SERVER_IP"
# 1. Generate root certificate
echo "Generating root private key..."
openssl genrsa -out "$ROOT_KEY" 4096
echo "Generating self-signed root certificate..."
openssl req -x509 -new -nodes -key "$ROOT_KEY" -sha256 -days 3650 -out "$ROOT_CERT" -subj "$SUBJ"
# 2. Generate server private key
echo "Generating server private key..."
openssl genrsa -out "$SERVER_KEY" 2048
# 3. Generate server CSR
echo "Generating server CSR..."
openssl req -new -key "$SERVER_KEY" -out "$SERVER_CSR" -subj "$SUBJ"
# 4. Create temporary OpenSSL config file with SAN
SAN_CONF="san.cnf"
cat > $SAN_CONF <<EOL
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[ req_distinguished_name ]
C = CN
ST = Zhejiang
L = Hangzhou
O = CrossDesk
OU = CrossDesk
CN = $SERVER_IP
[ req_ext ]
subjectAltName = IP:$SERVER_IP
EOL
# 5. Sign server certificate with root certificate (including SAN)
echo "Signing server certificate with root certificate..."
openssl x509 -req -in "$SERVER_CSR" -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial \
-out "$SERVER_CERT" -days 3650 -sha256 -extfile "$SAN_CONF" -extensions req_ext
# 6. Generate full chain certificate
cat "$SERVER_CERT" "$ROOT_CERT" > "$FULLCHAIN_CERT"
# 7. Clean up intermediate files
rm -f "$ROOT_CERT.srl" "$SAN_CONF" "$ROOT_KEY" "$SERVER_CSR" "FULLCHAIN_CERT"
echo "Generation complete. Deployment files:"
echo " Client root certificate: $ROOT_CERT"
echo " Server private key: $SERVER_KEY"
echo " Server certificate: $SERVER_CERT"
```
Execute:
```
chmod +x generate_certs.sh
./generate_certs.sh EXTERNAL_IP
# example ./generate_certs.sh 111.111.111.111
```
Expected output:
```
Generating root private key...
Generating self-signed root certificate...
Generating server private key...
Generating server CSR...
Signing server certificate with root certificate...
Certificate request self-signature ok
subject=C = CN, ST = Zhejiang, L = Hangzhou, O = CrossDesk, OU = CrossDesk, CN = xxx.xxx.xxx.xxx
cleaning up intermediate files...
Generation complete. Deployment files::
Client root certificate:: crossdesk.cn_root.crt
Server private key: crossdesk.cn.key
Server certificate: crossdesk.cn_bundle.crt
```
### Server Side ### Server Side
Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/your/certs** directory. Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/your/certs** directory.

View File

@@ -41,16 +41,43 @@ int ConfigCenter::Load() {
enable_turn_ = ini_.GetBoolValue(section_, "enable_turn", enable_turn_); enable_turn_ = ini_.GetBoolValue(section_, "enable_turn", enable_turn_);
enable_srtp_ = ini_.GetBoolValue(section_, "enable_srtp", enable_srtp_); 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_));
cert_file_path_ =
ini_.GetValue(section_, "cert_file_path", cert_file_path_.c_str());
enable_self_hosted_ = enable_self_hosted_ =
ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); ini_.GetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
const char* signal_server_host_value =
ini_.GetValue(section_, "signal_server_host", nullptr);
if (signal_server_host_value != nullptr &&
strlen(signal_server_host_value) > 0) {
signal_server_host_ = signal_server_host_value;
} else {
signal_server_host_ = "";
}
const char* signal_server_port_value =
ini_.GetValue(section_, "signal_server_port", nullptr);
if (signal_server_port_value != nullptr &&
strlen(signal_server_port_value) > 0) {
signal_server_port_ =
static_cast<int>(ini_.GetLongValue(section_, "signal_server_port", 0));
} else {
signal_server_port_ = 0;
}
const char* coturn_server_port_value =
ini_.GetValue(section_, "coturn_server_port", nullptr);
if (coturn_server_port_value != nullptr &&
strlen(coturn_server_port_value) > 0) {
coturn_server_port_ =
static_cast<int>(ini_.GetLongValue(section_, "coturn_server_port", 0));
} else {
coturn_server_port_ = 0;
}
const char* cert_file_path_value =
ini_.GetValue(section_, "cert_file_path", nullptr);
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
cert_file_path_ = cert_file_path_value;
} else {
cert_file_path_ = "";
}
enable_autostart_ = enable_autostart_ =
ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_); ini_.GetBoolValue(section_, "enable_autostart", enable_autostart_);
enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_); enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_);
@@ -71,11 +98,18 @@ int ConfigCenter::Save() {
ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_); ini_.SetBoolValue(section_, "hardware_video_codec", hardware_video_codec_);
ini_.SetBoolValue(section_, "enable_turn", enable_turn_); ini_.SetBoolValue(section_, "enable_turn", enable_turn_);
ini_.SetBoolValue(section_, "enable_srtp", enable_srtp_); 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_, "cert_file_path", cert_file_path_.c_str());
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
// only save when self hosted
if (enable_self_hosted_) {
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
ini_.SetLongValue(section_, "signal_server_port",
static_cast<long>(signal_server_port_));
ini_.SetLongValue(section_, "coturn_server_port",
static_cast<long>(coturn_server_port_));
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
}
ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_); ini_.SetBoolValue(section_, "enable_autostart", enable_autostart_);
ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_); ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_);
ini_.SetBoolValue(section_, "enable_minimize_to_tray", ini_.SetBoolValue(section_, "enable_minimize_to_tray",
@@ -210,6 +244,43 @@ int ConfigCenter::SetCertFilePath(const std::string& cert_file_path) {
int ConfigCenter::SetSelfHosted(bool enable_self_hosted) { int ConfigCenter::SetSelfHosted(bool enable_self_hosted) {
enable_self_hosted_ = enable_self_hosted; enable_self_hosted_ = enable_self_hosted;
ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_); ini_.SetBoolValue(section_, "enable_self_hosted", enable_self_hosted_);
// load from config if self hosted is enabled
if (enable_self_hosted_) {
const char* signal_server_host_value =
ini_.GetValue(section_, "signal_server_host", nullptr);
if (signal_server_host_value != nullptr &&
strlen(signal_server_host_value) > 0) {
signal_server_host_ = signal_server_host_value;
}
const char* signal_server_port_value =
ini_.GetValue(section_, "signal_server_port", nullptr);
if (signal_server_port_value != nullptr &&
strlen(signal_server_port_value) > 0) {
signal_server_port_ = static_cast<int>(
ini_.GetLongValue(section_, "signal_server_port", 0));
}
const char* coturn_server_port_value =
ini_.GetValue(section_, "coturn_server_port", nullptr);
if (coturn_server_port_value != nullptr &&
strlen(coturn_server_port_value) > 0) {
coturn_server_port_ = static_cast<int>(
ini_.GetLongValue(section_, "coturn_server_port", 0));
}
const char* cert_file_path_value =
ini_.GetValue(section_, "cert_file_path", nullptr);
if (cert_file_path_value != nullptr && strlen(cert_file_path_value) > 0) {
cert_file_path_ = cert_file_path_value;
}
ini_.SetValue(section_, "signal_server_host", signal_server_host_.c_str());
ini_.SetLongValue(section_, "signal_server_port",
static_cast<long>(signal_server_port_));
ini_.SetLongValue(section_, "coturn_server_port",
static_cast<long>(coturn_server_port_));
ini_.SetValue(section_, "cert_file_path", cert_file_path_.c_str());
}
SI_Error rc = ini_.SaveFile(config_path_.c_str()); SI_Error rc = ini_.SaveFile(config_path_.c_str());
if (rc < 0) { if (rc < 0) {
return -1; return -1;

View File

@@ -70,7 +70,6 @@ class ConfigCenter {
private: private:
std::string config_path_; std::string config_path_;
std::string cert_file_path_;
CSimpleIniA ini_; CSimpleIniA ini_;
const char* section_ = "Settings"; const char* section_ = "Settings";
@@ -81,12 +80,13 @@ class ConfigCenter {
bool hardware_video_codec_ = false; bool hardware_video_codec_ = false;
bool enable_turn_ = true; bool enable_turn_ = true;
bool enable_srtp_ = false; bool enable_srtp_ = false;
std::string signal_server_host_ = "api.crossdesk.cn"; std::string signal_server_host_ = "";
std::string signal_server_host_default_ = "api.crossdesk.cn"; std::string signal_server_host_default_ = "api.crossdesk.cn";
int signal_server_port_ = 9099; int signal_server_port_ = 0;
int server_port_default_ = 9099; int server_port_default_ = 9099;
int coturn_server_port_ = 3478; int coturn_server_port_ = 0;
int coturn_server_port_default_ = 3478; int coturn_server_port_default_ = 3478;
std::string cert_file_path_ = "";
std::string cert_file_path_default_ = ""; std::string cert_file_path_default_ = "";
bool enable_self_hosted_ = false; bool enable_self_hosted_ = false;
bool enable_minimize_to_tray_ = false; bool enable_minimize_to_tray_ = false;

File diff suppressed because it is too large Load Diff

View File

@@ -7,85 +7,81 @@
#ifndef _LAYOUT_STYLE_H_ #ifndef _LAYOUT_STYLE_H_
#define _LAYOUT_STYLE_H_ #define _LAYOUT_STYLE_H_
#define MENU_WINDOW_WIDTH_CN 300 #include "render.h"
#define MENU_WINDOW_HEIGHT_CN 280
#define LOCAL_WINDOW_WIDTH_CN 300 #define MENU_WINDOW_WIDTH_CN 300 * dpi_scale_
#define LOCAL_WINDOW_HEIGHT_CN 280 #define MENU_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define REMOTE_WINDOW_WIDTH_CN 300 #define LOCAL_WINDOW_WIDTH_CN 300 * dpi_scale_
#define REMOTE_WINDOW_HEIGHT_CN 280 #define LOCAL_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define MENU_WINDOW_WIDTH_EN 190 #define REMOTE_WINDOW_WIDTH_CN 300 * dpi_scale_
#define MENU_WINDOW_HEIGHT_EN 245 #define REMOTE_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define IPUT_WINDOW_WIDTH 160 #define MENU_WINDOW_WIDTH_EN 190 * dpi_scale_
#define INPUT_WINDOW_PADDING_CN 66 #define MENU_WINDOW_HEIGHT_EN 245 * dpi_scale_
#define INPUT_WINDOW_PADDING_EN 96 #define IPUT_WINDOW_WIDTH 160 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_CN 202 #define INPUT_WINDOW_PADDING_CN 66 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_EN 248 #define INPUT_WINDOW_PADDING_EN 96 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_CN 202 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_EN 248 * dpi_scale_
#if USE_CUDA #if USE_CUDA
#if _WIN32 #if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 405 #define SETTINGS_WINDOW_HEIGHT_CN 405 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 405 #define SETTINGS_WINDOW_HEIGHT_EN 405 * dpi_scale_
#else #else
#define SETTINGS_WINDOW_HEIGHT_CN 375 #define SETTINGS_WINDOW_HEIGHT_CN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 375 #define SETTINGS_WINDOW_HEIGHT_EN 375 * dpi_scale_
#endif #endif
#else #else
#if _WIN32 #if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 375 #define SETTINGS_WINDOW_HEIGHT_CN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 375 #define SETTINGS_WINDOW_HEIGHT_EN 375 * dpi_scale_
#else #else
#define SETTINGS_WINDOW_HEIGHT_CN 345 #define SETTINGS_WINDOW_HEIGHT_CN 345 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 345 #define SETTINGS_WINDOW_HEIGHT_EN 345 * dpi_scale_
#endif #endif
#endif #endif
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228 #define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275 #define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 195 #define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 195 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 195 #define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 195 * dpi_scale_
#define LANGUAGE_SELECT_WINDOW_PADDING_CN 120 #define LANGUAGE_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define LANGUAGE_SELECT_WINDOW_PADDING_EN 167 #define LANGUAGE_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120 #define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN 167 #define VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN 120 #define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN 167 #define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN 120 #define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN 167 #define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN 171 #define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN 218 #define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_TURN_CHECKBOX_PADDING_CN 171 #define ENABLE_TURN_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_TURN_CHECKBOX_PADDING_EN 218 #define ENABLE_TURN_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_SRTP_CHECKBOX_PADDING_CN 171 #define ENABLE_SRTP_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_SRTP_CHECKBOX_PADDING_EN 218 #define ENABLE_SRTP_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171 #define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218 #define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_AUTOSTART_PADDING_CN 171 #define ENABLE_AUTOSTART_PADDING_CN 171 * dpi_scale_
#define ENABLE_AUTOSTART_PADDING_EN 218 #define ENABLE_AUTOSTART_PADDING_EN 218 * dpi_scale_
#define ENABLE_DAEMON_PADDING_CN 171 #define ENABLE_DAEMON_PADDING_CN 171 * dpi_scale_
#define ENABLE_DAEMON_PADDING_EN 218 #define ENABLE_DAEMON_PADDING_EN 218 * dpi_scale_
#define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171 #define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171 * dpi_scale_
#define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218 #define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218 * dpi_scale_
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90 #define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90 * dpi_scale_
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137 #define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137 * dpi_scale_
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90 #define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90 * dpi_scale_
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN 137 #define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN 137 * dpi_scale_
#define SETTINGS_SELECT_WINDOW_WIDTH 73 #define SETTINGS_SELECT_WINDOW_WIDTH 73 * dpi_scale_
#define SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH 130 #define SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH 130 * dpi_scale_
#define SETTINGS_OK_BUTTON_PADDING_CN 65 #define SETTINGS_OK_BUTTON_PADDING_CN 65 * dpi_scale_
#define SETTINGS_OK_BUTTON_PADDING_EN 83 #define SETTINGS_OK_BUTTON_PADDING_EN 83 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN 78 #define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN 78 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN 91 #define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN 91 * dpi_scale_
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN 162 #define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN 162 * dpi_scale_
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN 146 #define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN 146 * dpi_scale_
#ifdef _WIN32 #define UPDATE_NOTIFICATION_RESERVED_HEIGHT 120 * dpi_scale_
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 130 #define REQUEST_PERMISSION_WINDOW_WIDTH_CN 130 * dpi_scale_
#elif __APPLE__ #define REQUEST_PERMISSION_WINDOW_HEIGHT_CN 125 * dpi_scale_
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 100 #define REQUEST_PERMISSION_WINDOW_WIDTH_EN 260 * dpi_scale_
#else #define REQUEST_PERMISSION_WINDOW_HEIGHT_EN 125 * dpi_scale_
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 100 #define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN 90 * dpi_scale_
#endif #define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN 210 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_WIDTH_CN 130
#define REQUEST_PERMISSION_WINDOW_HEIGHT_CN 125
#define REQUEST_PERMISSION_WINDOW_WIDTH_EN 260
#define REQUEST_PERMISSION_WINDOW_HEIGHT_EN 125
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN 90
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN 210
#endif #endif

View File

@@ -0,0 +1,91 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-06-14
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _LAYOUT_STYLE_H_
#define _LAYOUT_STYLE_H_
#include "render.h"
#define TITLE_BAR_HEIGHT 0.0625f
#define TITLE_BAR_BUTTON_WIDTH 0.0625f
#define TITLE_BAR_BUTTON_HEIGHT 0.0625f
#define STATUS_BAR_HEIGHT 0.05f
#define MENU_WINDOW_WIDTH_CN 300
#define MENU_WINDOW_HEIGHT_CN 280
#define LOCAL_WINDOW_WIDTH_CN 300
#define LOCAL_WINDOW_HEIGHT_CN 280
#define REMOTE_WINDOW_WIDTH_CN 300
#define REMOTE_WINDOW_HEIGHT_CN 280
#define MENU_WINDOW_WIDTH_EN 190
#define MENU_WINDOW_HEIGHT_EN 245
#define IPUT_WINDOW_WIDTH 160
#define INPUT_WINDOW_PADDING_CN 66
#define INPUT_WINDOW_PADDING_EN 96
#define SETTINGS_WINDOW_WIDTH_CN 202
#define SETTINGS_WINDOW_WIDTH_EN 248
#if USE_CUDA
#if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 405
#define SETTINGS_WINDOW_HEIGHT_EN 405
#else
#define SETTINGS_WINDOW_HEIGHT_CN 375
#define SETTINGS_WINDOW_HEIGHT_EN 375
#endif
#else
#if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 375
#define SETTINGS_WINDOW_HEIGHT_EN 375
#else
#define SETTINGS_WINDOW_HEIGHT_CN 345
#define SETTINGS_WINDOW_HEIGHT_EN 345
#endif
#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 LANGUAGE_SELECT_WINDOW_PADDING_CN 120
#define LANGUAGE_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN 167
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN 171
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN 218
#define ENABLE_TURN_CHECKBOX_PADDING_CN 171
#define ENABLE_TURN_CHECKBOX_PADDING_EN 218
#define ENABLE_SRTP_CHECKBOX_PADDING_CN 171
#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_AUTOSTART_PADDING_CN 171
#define ENABLE_AUTOSTART_PADDING_EN 218
#define ENABLE_DAEMON_PADDING_CN 171
#define ENABLE_DAEMON_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
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN 137
#define SETTINGS_SELECT_WINDOW_WIDTH 73
#define SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH 130
#define SETTINGS_OK_BUTTON_PADDING_CN 65
#define SETTINGS_OK_BUTTON_PADDING_EN 83
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN 78
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN 91
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN 162
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN 146
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 120
#define REQUEST_PERMISSION_WINDOW_WIDTH_CN 130
#define REQUEST_PERMISSION_WINDOW_HEIGHT_CN 125
#define REQUEST_PERMISSION_WINDOW_WIDTH_EN 260
#define REQUEST_PERMISSION_WINDOW_HEIGHT_EN 125
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN 90
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN 210
#endif

View File

@@ -1,6 +1,6 @@
#include <random> #include <random>
#include "layout.h" #include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
@@ -8,20 +8,27 @@
namespace crossdesk { namespace crossdesk {
int Render::LocalWindow() { int Render::LocalWindow() {
ImGui::SetNextWindowPos(ImVec2(-1.0f, title_bar_height_), ImGuiCond_Always); ImGuiIO& io = ImGui::GetIO();
float local_window_width = io.DisplaySize.x * 0.5f;
float local_window_height =
io.DisplaySize.y * (1 - TITLE_BAR_HEIGHT - STATUS_BAR_HEIGHT);
float local_window_button_width = io.DisplaySize.x * 0.046f;
float local_window_button_height = io.DisplaySize.y * 0.075f;
ImGui::SetNextWindowPos(ImVec2(0.0f, io.DisplaySize.y * TITLE_BAR_HEIGHT),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
ImGui::BeginChild("LocalDesktopWindow", ImGui::BeginChild("LocalDesktopWindow",
ImVec2(local_window_width_, local_window_height_), ImVec2(local_window_width, local_window_height),
ImGuiChildFlags_None, ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_); ImGui::SetCursorPos(
ImGui::Indent(main_child_window_x_padding_); ImVec2(io.DisplaySize.x * 0.045f, io.DisplaySize.y * 0.02f));
ImGui::TextColored( ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s", ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
@@ -30,18 +37,16 @@ int Render::LocalWindow() {
ImGui::Spacing(); ImGui::Spacing();
{ {
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2(main_child_window_x_padding_, ImVec2(io.DisplaySize.x * 0.045f, io.DisplaySize.y * 0.15f),
title_bar_height_ + main_child_window_y_padding_),
ImGuiCond_Always); ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255, ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255,
242.0f / 255, 1.0f)); 242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild( ImGui::BeginChild(
"LocalDesktopWindow_1", "LocalDesktopPanel",
ImVec2(local_child_window_width_, local_child_window_height_), ImVec2(local_window_width * 0.8f, local_window_height * 0.43f),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@@ -52,7 +57,7 @@ int Render::LocalWindow() {
ImGui::Spacing(); ImGui::Spacing();
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH); ImGui::SetNextItemWidth(io.DisplaySize.x * 0.25f);
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
@@ -76,7 +81,8 @@ int Render::LocalWindow() {
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(ICON_FA_COPY, ImVec2(22, 38))) { if (ImGui::Button(ICON_FA_COPY, ImVec2(local_window_button_width,
local_window_button_height))) {
local_id_copied_ = true; local_id_copied_ = true;
ImGui::SetClipboardText(client_id_); ImGui::SetClipboardText(client_id_);
copy_start_time_ = ImGui::GetTime(); copy_start_time_ = ImGui::GetTime();
@@ -86,17 +92,10 @@ int Render::LocalWindow() {
double time_duration = ImGui::GetTime() - copy_start_time_; double time_duration = ImGui::GetTime() - copy_start_time_;
if (local_id_copied_ && time_duration < 1.0f) { if (local_id_copied_ && time_duration < 1.0f) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
notification_window_width_) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
notification_window_height_) /
2));
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(notification_window_width_, notification_window_height_)); ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
ImGui::PushStyleColor( ImGui::PushStyleColor(
ImGuiCol_WindowBg, ImGuiCol_WindowBg,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f - (float)time_duration)); ImVec4(1.0f, 1.0f, 1.0f, 1.0f - (float)time_duration));
@@ -115,7 +114,7 @@ int Render::LocalWindow() {
[localization_language_index_]; [localization_language_index_];
auto text_width = ImGui::CalcTextSize(text.c_str()).x; auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((window_width - text_width) * 0.5f); ImGui::SetCursorPosX((window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.5f); ImGui::SetCursorPosY(window_height * 0.4f);
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::PushStyleColor(ImGuiCol_Text,
ImVec4(0, 0, 0, 1.0f - (float)time_duration)); ImVec4(0, 0, 0, 1.0f - (float)time_duration));
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
@@ -134,7 +133,7 @@ int Render::LocalWindow() {
localization::password[localization_language_index_].c_str()); localization::password[localization_language_index_].c_str());
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH); ImGui::SetNextItemWidth(io.DisplaySize.x * 0.25f);
ImGui::Spacing(); ImGui::Spacing();
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
@@ -156,51 +155,34 @@ int Render::LocalWindow() {
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
auto l_x = ImGui::GetCursorScreenPos().x; auto l_x = ImGui::GetCursorScreenPos().x;
auto l_y = ImGui::GetCursorScreenPos().y; auto l_y = ImGui::GetCursorScreenPos().y;
if (ImGui::Button(ICON_FA_EYE, ImVec2(22, 38))) { if (ImGui::Button(
show_password_ ? ICON_FA_EYE : ICON_FA_EYE_SLASH,
ImVec2(local_window_button_width, local_window_button_height))) {
show_password_ = !show_password_; show_password_ = !show_password_;
} }
if (!show_password_) {
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 12.5f),
ImVec2(l_x + 20.3f, l_y + 26.5f),
IM_COL32(239, 240, 242, 255), 2.0f);
draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 11.0f),
ImVec2(l_x + 20.3f, l_y + 25.0f),
IM_COL32(0, 0, 0, 255), 1.5f);
}
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button(ICON_FA_PEN, ImVec2(22, 38))) { if (ImGui::Button(ICON_FA_PEN, ImVec2(local_window_button_width,
local_window_button_height))) {
show_reset_password_window_ = true; show_reset_password_window_ = true;
} }
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3); ImGui::PopStyleColor(3);
if (show_reset_password_window_) { if (show_reset_password_window_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
connection_status_window_width_) / ImGui::SetNextWindowSize(
2, ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
(viewport->WorkSize.y - viewport->WorkPos.y -
connection_status_window_height_) /
2));
ImGui::SetNextWindowSize(ImVec2(connection_status_window_width_,
connection_status_window_height_));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::Begin("ResetPasswordWindow", nullptr, ImGui::Begin("ResetPasswordWindow", nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings); ImGuiWindowFlags_NoSavedSettings);
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@@ -215,9 +197,9 @@ int Render::LocalWindow() {
ImGui::SetCursorPosY(window_height * 0.2f); ImGui::SetCursorPosY(window_height * 0.2f);
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
ImGui::SetCursorPosX((window_width - IPUT_WINDOW_WIDTH / 2) * 0.5f); ImGui::SetCursorPosX(window_width * 0.33f);
ImGui::SetCursorPosY(window_height * 0.4f); ImGui::SetCursorPosY(window_height * 0.4f);
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH / 2); ImGui::SetNextItemWidth(window_width * 0.33f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);

View File

@@ -1,3 +1,4 @@
#include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
@@ -5,25 +6,25 @@
namespace crossdesk { namespace crossdesk {
int Render::RecentConnectionsWindow() { int Render::RecentConnectionsWindow() {
ImGui::SetNextWindowPos( ImGuiIO& io = ImGui::GetIO();
ImVec2(0, title_bar_height_ + local_window_height_ - 1.0f), float recent_connection_window_width = io.DisplaySize.x;
ImGuiCond_Always); float recent_connection_window_height =
io.DisplaySize.y * (0.46f - STATUS_BAR_HEIGHT);
ImGui::SetNextWindowPos(ImVec2(0, io.DisplaySize.y * 0.55f),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild( ImGui::BeginChild(
"RecentConnectionsWindow", "RecentConnectionsWindow",
ImVec2(main_window_width_default_, ImVec2(recent_connection_window_width, recent_connection_window_height),
main_window_height_default_ - title_bar_height_ -
local_window_height_ - status_bar_height_ + 1.0f),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_); ImGui::SetCursorPos(
ImGui::Indent(main_child_window_x_padding_); ImVec2(io.DisplaySize.x * 0.045f, io.DisplaySize.y * 0.02f));
ImGui::TextColored( ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s", ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
@@ -37,31 +38,40 @@ int Render::RecentConnectionsWindow() {
} }
int Render::ShowRecentConnections() { int Render::ShowRecentConnections() {
ImGui::SetCursorPosX(25.0f); ImGuiIO& io = ImGui::GetIO();
ImVec2 sub_window_pos = ImGui::GetCursorPos(); float recent_connection_panel_width = io.DisplaySize.x * 0.912f;
std::map<std::string, ImVec2> sub_containers_pos; float recent_connection_panel_height = io.DisplaySize.y * 0.29f;
float recent_connection_image_height = recent_connection_panel_height * 0.6f;
float recent_connection_image_width = recent_connection_image_height * 16 / 9;
float recent_connection_sub_container_width = float recent_connection_sub_container_width =
recent_connection_image_width_ + 16.0f; recent_connection_image_width * 1.2f;
float recent_connection_sub_container_height = float recent_connection_sub_container_height =
recent_connection_image_height_ + 36.0f; recent_connection_image_height * 1.4f;
float recent_connection_button_width = recent_connection_image_width * 0.15f;
float recent_connection_button_height =
recent_connection_image_height * 0.25f;
float recent_connection_dummy_button_width =
recent_connection_image_width - 2 * recent_connection_button_width;
ImGui::SetCursorPos(
ImVec2(io.DisplaySize.x * 0.045f, io.DisplaySize.y * 0.1f));
std::map<std::string, ImVec2> sub_containers_pos;
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::PushStyleColor(ImGuiCol_ChildBg,
ImVec4(239.0f / 255, 240.0f / 255, 242.0f / 255, 1.0f)); ImVec4(239.0f / 255, 240.0f / 255, 242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("RecentConnectionsContainer", ImGui::BeginChild(
ImVec2(main_window_width_default_ - 50.0f, 145.0f), "RecentConnectionsContainer",
ImGuiChildFlags_Border, ImVec2(recent_connection_panel_width, recent_connection_panel_height),
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiChildFlags_Border,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
ImGuiWindowFlags_NoScrollWithMouse);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
size_t recent_connections_count = recent_connections_.size(); size_t recent_connections_count = recent_connections_.size();
int count = 0; int count = 0;
float button_width = 22;
float button_height = 22;
for (auto& it : recent_connections_) { for (auto& it : recent_connections_) {
sub_containers_pos[it.first] = ImGui::GetCursorPos(); sub_containers_pos[it.first] = ImGui::GetCursorPos();
std::string recent_connection_sub_window_name = std::string recent_connection_sub_window_name =
@@ -71,11 +81,8 @@ int Render::ShowRecentConnections() {
ImVec2(recent_connection_sub_container_width, ImVec2(recent_connection_sub_container_width,
recent_connection_sub_container_height), recent_connection_sub_container_height),
ImGuiChildFlags_None, ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoScrollbar);
std::string connection_info = it.first; std::string connection_info = it.first;
// remote id length is 9 // remote id length is 9
@@ -114,14 +121,16 @@ int Render::ShowRecentConnections() {
it.second.remote_host_name = "unknown"; it.second.remote_host_name = "unknown";
} }
ImVec2 image_screen_pos = ImVec2(ImGui::GetCursorScreenPos().x + 5.0f, ImVec2 image_screen_pos = ImVec2(
ImGui::GetCursorScreenPos().y + 5.0f); ImGui::GetCursorScreenPos().x + recent_connection_image_width * 0.04f,
ImGui::GetCursorScreenPos().y + recent_connection_image_height * 0.08f);
ImVec2 image_pos = ImVec2 image_pos =
ImVec2(ImGui::GetCursorPosX() + 5.0f, ImGui::GetCursorPosY() + 5.0f); ImVec2(ImGui::GetCursorPosX() + recent_connection_image_width * 0.05f,
ImGui::GetCursorPosY() + recent_connection_image_height * 0.08f);
ImGui::SetCursorPos(image_pos); ImGui::SetCursorPos(image_pos);
ImGui::Image((ImTextureID)(intptr_t)it.second.texture, ImGui::Image(
ImVec2((float)recent_connection_image_width_, (ImTextureID)(intptr_t)it.second.texture,
(float)recent_connection_image_height_)); ImVec2(recent_connection_image_width, recent_connection_image_height));
// remote id display button // remote id display button
{ {
@@ -130,16 +139,17 @@ int Render::ShowRecentConnections() {
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0.2f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0.2f));
ImVec2 dummy_button_pos = ImVec2 dummy_button_pos =
ImVec2(image_pos.x, image_pos.y + recent_connection_image_height_); ImVec2(image_pos.x, image_pos.y + recent_connection_image_height);
std::string dummy_button_name = "##DummyButton" + it.second.remote_id; std::string dummy_button_name = "##DummyButton" + it.second.remote_id;
ImGui::SetCursorPos(dummy_button_pos); ImGui::SetCursorPos(dummy_button_pos);
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.6f);
ImGui::Button(dummy_button_name.c_str(), ImGui::Button(dummy_button_name.c_str(),
ImVec2(recent_connection_image_width_ - 2 * button_width, ImVec2(recent_connection_dummy_button_width,
button_height)); recent_connection_button_height));
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::SetCursorPos( ImGui::SetCursorPos(ImVec2(
ImVec2(dummy_button_pos.x + 2.0f, dummy_button_pos.y + 1.0f)); dummy_button_pos.x + recent_connection_dummy_button_width * 0.05f,
dummy_button_pos.y + recent_connection_button_height * 0.05f));
ImGui::SetWindowFontScale(0.65f); ImGui::SetWindowFontScale(0.65f);
ImGui::Text("%s", it.second.remote_id.c_str()); ImGui::Text("%s", it.second.remote_id.c_str());
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
@@ -162,16 +172,18 @@ int Render::ShowRecentConnections() {
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
// trash button // trash button
{ {
ImVec2 trash_can_button_pos = ImVec2( ImVec2 trash_can_button_pos =
image_pos.x + recent_connection_image_width_ - 2 * button_width, ImVec2(image_pos.x + recent_connection_image_width -
image_pos.y + recent_connection_image_height_); 2 * recent_connection_button_width,
image_pos.y + recent_connection_image_height);
ImGui::SetCursorPos(trash_can_button_pos); ImGui::SetCursorPos(trash_can_button_pos);
std::string trash_can = ICON_FA_TRASH_CAN; std::string trash_can = ICON_FA_TRASH_CAN;
std::string recent_connection_delete_button_name = std::string recent_connection_delete_button_name =
trash_can + "##RecentConnectionDelete" + trash_can + "##RecentConnectionDelete" +
std::to_string(trash_can_button_pos.x); std::to_string(trash_can_button_pos.x);
if (ImGui::Button(recent_connection_delete_button_name.c_str(), if (ImGui::Button(recent_connection_delete_button_name.c_str(),
ImVec2(button_width, button_height))) { ImVec2(recent_connection_button_width,
recent_connection_button_height))) {
show_confirm_delete_connection_ = true; show_confirm_delete_connection_ = true;
delete_connection_name_ = it.first; delete_connection_name_ = it.first;
} }
@@ -187,14 +199,16 @@ int Render::ShowRecentConnections() {
// connect button // connect button
{ {
ImVec2 connect_button_pos = ImVec2 connect_button_pos =
ImVec2(image_pos.x + recent_connection_image_width_ - button_width, ImVec2(image_pos.x + recent_connection_image_width -
image_pos.y + recent_connection_image_height_); recent_connection_button_width,
image_pos.y + recent_connection_image_height);
ImGui::SetCursorPos(connect_button_pos); ImGui::SetCursorPos(connect_button_pos);
std::string connect = ICON_FA_ARROW_RIGHT_LONG; std::string connect = ICON_FA_ARROW_RIGHT_LONG;
std::string connect_to_this_connection_button_name = std::string connect_to_this_connection_button_name =
connect + "##ConnectionTo" + it.first; connect + "##ConnectionTo" + it.first;
if (ImGui::Button(connect_to_this_connection_button_name.c_str(), if (ImGui::Button(connect_to_this_connection_button_name.c_str(),
ImVec2(button_width, button_height))) { ImVec2(recent_connection_button_width,
recent_connection_button_height))) {
ConnectTo(it.second.remote_id, it.second.password.c_str(), ConnectTo(it.second.remote_id, it.second.password.c_str(),
it.second.remember_password); it.second.remember_password);
} }
@@ -206,17 +220,20 @@ int Render::ShowRecentConnections() {
if (count != recent_connections_count - 1) { if (count != recent_connections_count - 1) {
ImVec2 line_start = ImVec2 line_start =
ImVec2(image_screen_pos.x + recent_connection_image_width_ + 20.0f, ImVec2(image_screen_pos.x + recent_connection_image_width * 1.19f,
image_screen_pos.y); image_screen_pos.y);
ImVec2 line_end = ImVec2( ImVec2 line_end =
image_screen_pos.x + recent_connection_image_width_ + 20.0f, ImVec2(image_screen_pos.x + recent_connection_image_width * 1.19f,
image_screen_pos.y + recent_connection_image_height_ + button_height); image_screen_pos.y + recent_connection_image_height +
recent_connection_button_height);
ImGui::GetWindowDrawList()->AddLine(line_start, line_end, ImGui::GetWindowDrawList()->AddLine(line_start, line_end,
IM_COL32(0, 0, 0, 122), 1.0f); IM_COL32(0, 0, 0, 122), 1.0f);
} }
count++; count++;
ImGui::SameLine(0, count != recent_connections_count ? 26.0f : 0.0f); ImGui::SameLine(0, count != recent_connections_count
? (recent_connection_image_width * 0.165f)
: 0.0f);
} }
ImGui::EndChild(); ImGui::EndChild();
@@ -229,32 +246,30 @@ int Render::ShowRecentConnections() {
} }
int Render::ConfirmDeleteConnection() { int Render::ConfirmDeleteConnection() {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGuiIO& io = ImGui::GetIO();
ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImGui::SetNextWindowPos(
connection_status_window_width_) / ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
2, ImGui::SetNextWindowSize(
(viewport->WorkSize.y - viewport->WorkPos.y - ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
connection_status_window_height_) /
2));
ImGui::SetNextWindowSize(ImVec2(connection_status_window_width_,
connection_status_window_height_));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::Begin("ConfirmDeleteConnectionWindow", nullptr, ImGui::Begin("ConfirmDeleteConnectionWindow", nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings); ImGuiWindowFlags_NoSavedSettings);
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
auto connection_status_window_width = ImGui::GetWindowSize().x;
auto connection_status_window_height = ImGui::GetWindowSize().y;
std::string text = std::string text =
localization::confirm_delete_connection[localization_language_index_]; localization::confirm_delete_connection[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 6 / 19); ImGui::SetCursorPosX(connection_status_window_width * 0.33f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
@@ -273,12 +288,9 @@ int Render::ConfirmDeleteConnection() {
show_confirm_delete_connection_ = false; show_confirm_delete_connection_ = false;
} }
auto window_width = ImGui::GetWindowSize().x;
auto window_height = ImGui::GetWindowSize().y;
auto text_width = ImGui::CalcTextSize(text.c_str()).x; auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((window_width - text_width) * 0.5f); ImGui::SetCursorPosX((connection_status_window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.2f); ImGui::SetCursorPosY(connection_status_window_height * 0.2f);
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);

View File

@@ -1,4 +1,4 @@
#include "layout.h" #include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
@@ -8,21 +8,28 @@ namespace crossdesk {
static int InputTextCallback(ImGuiInputTextCallbackData* data); static int InputTextCallback(ImGuiInputTextCallbackData* data);
int Render::RemoteWindow() { int Render::RemoteWindow() {
ImGui::SetNextWindowPos(ImVec2(local_window_width_ + 1.0f, title_bar_height_), ImGuiIO& io = ImGui::GetIO();
ImGuiCond_Always); float remote_window_width = io.DisplaySize.x * 0.5f;
float remote_window_height =
io.DisplaySize.y * (1 - TITLE_BAR_HEIGHT - STATUS_BAR_HEIGHT);
float remote_window_arrow_button_width = io.DisplaySize.x * 0.1f;
float remote_window_arrow_button_height = io.DisplaySize.y * 0.078f;
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * TITLE_BAR_HEIGHT),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
ImGui::BeginChild("RemoteDesktopWindow", ImGui::BeginChild("RemoteDesktopWindow",
ImVec2(remote_window_width_, remote_window_height_), ImVec2(remote_window_width, remote_window_height),
ImGuiChildFlags_None, ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_); ImGui::SetCursorPos(
ImGui::Indent(main_child_window_x_padding_ - 1.0f); ImVec2(io.DisplaySize.x * 0.057f, io.DisplaySize.y * 0.02f));
ImGui::TextColored( ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s", ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
@@ -31,8 +38,7 @@ int Render::RemoteWindow() {
ImGui::Spacing(); ImGui::Spacing();
{ {
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2(local_window_width_ + main_child_window_x_padding_ - 1.0f, ImVec2(io.DisplaySize.x * 0.557f, io.DisplaySize.y * 0.15f),
title_bar_height_ + main_child_window_y_padding_),
ImGuiCond_Always); ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255, ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255,
242.0f / 255, 1.0f)); 242.0f / 255, 1.0f));
@@ -40,10 +46,9 @@ int Render::RemoteWindow() {
ImGui::BeginChild( ImGui::BeginChild(
"RemoteDesktopWindow_1", "RemoteDesktopWindow_1",
ImVec2(remote_child_window_width_, remote_child_window_height_), ImVec2(remote_window_width * 0.8f, remote_window_height * 0.43f),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@@ -53,7 +58,7 @@ int Render::RemoteWindow() {
"%s", localization::remote_id[localization_language_index_].c_str()); "%s", localization::remote_id[localization_language_index_].c_str());
ImGui::Spacing(); ImGui::Spacing();
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH); ImGui::SetNextItemWidth(io.DisplaySize.x * 0.25f);
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
if (re_enter_remote_id_) { if (re_enter_remote_id_) {
@@ -75,28 +80,44 @@ int Render::RemoteWindow() {
remote_id.erase(remove_if(remote_id.begin(), remote_id.end(), remote_id.erase(remove_if(remote_id.begin(), remote_id.end(),
static_cast<int (*)(int)>(&isspace)), static_cast<int (*)(int)>(&isspace)),
remote_id.end()); remote_id.end());
if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG, ImVec2(55, 38)) || if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG,
ImVec2(remote_window_arrow_button_width,
remote_window_arrow_button_height)) ||
enter_pressed) { enter_pressed) {
connect_button_pressed_ = true; connect_button_pressed_ = true;
bool found = false; bool found = false;
std::string target_remote_id;
std::string target_password;
bool should_connect = false;
bool already_connected = false;
for (auto& [id, props] : recent_connections_) { for (auto& [id, props] : recent_connections_) {
if (id.find(remote_id) != std::string::npos) { if (id.find(remote_id) != std::string::npos) {
found = true; found = true;
std::shared_lock lock(client_properties_mutex_); target_remote_id = props.remote_id;
if (client_properties_.find(remote_id) != target_password = props.password;
client_properties_.end()) { {
if (!client_properties_[remote_id]->connection_established_) { // std::shared_lock lock(client_properties_mutex_);
ConnectTo(props.remote_id, props.password.c_str(), false); if (client_properties_.find(remote_id) !=
client_properties_.end()) {
if (!client_properties_[remote_id]->connection_established_) {
should_connect = true;
} else {
already_connected = true;
}
} else { } else {
// todo: show warning message should_connect = true;
LOG_INFO("Already connected to [{}]", remote_id);
} }
} else {
ConnectTo(props.remote_id, props.password.c_str(), false);
} }
if (should_connect) {
ConnectTo(target_remote_id, target_password.c_str(), false);
} else if (already_connected) {
LOG_INFO("Already connected to [{}]", remote_id);
}
break;
} }
} }
if (!found) { if (!found) {
ConnectTo(remote_id, "", false); ConnectTo(remote_id, "", false);
} }
@@ -112,7 +133,7 @@ int Render::RemoteWindow() {
if (elapsed >= 1000) { if (elapsed >= 1000) {
last_rejoin_check_time_ = now; last_rejoin_check_time_ = now;
need_to_rejoin_ = false; need_to_rejoin_ = false;
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (const auto& [_, props] : client_properties_) { for (const auto& [_, props] : client_properties_) {
if (props->rejoin_) { if (props->rejoin_) {
ConnectTo(props->remote_id_, props->remote_password_, ConnectTo(props->remote_id_, props->remote_password_,
@@ -147,49 +168,61 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
LOG_INFO("Connect to [{}]", remote_id); LOG_INFO("Connect to [{}]", remote_id);
focused_remote_id_ = remote_id; focused_remote_id_ = remote_id;
std::shared_lock shared_lock(client_properties_mutex_); // std::shared_lock shared_lock(client_properties_mutex_);
bool exists = bool exists =
(client_properties_.find(remote_id) != client_properties_.end()); (client_properties_.find(remote_id) != client_properties_.end());
shared_lock.unlock(); // shared_lock.unlock();
if (!exists) { if (!exists) {
std::unique_lock unique_lock(client_properties_mutex_); PeerPtr* peer_to_init = nullptr;
if (client_properties_.find(remote_id) == client_properties_.end()) { std::string local_id;
client_properties_[remote_id] =
std::make_shared<SubStreamWindowProperties>();
auto props = client_properties_[remote_id];
props->local_id_ = "C-" + std::string(client_id_);
props->remote_id_ = remote_id;
memcpy(&props->params_, &params_, sizeof(Params));
props->params_.user_id = props->local_id_.c_str();
props->peer_ = CreatePeer(&props->params_);
if (!props->peer_) { {
LOG_INFO("Create peer [{}] instance failed", props->local_id_); // std::unique_lock unique_lock(client_properties_mutex_);
return -1; if (client_properties_.find(remote_id) == client_properties_.end()) {
client_properties_[remote_id] =
std::make_shared<SubStreamWindowProperties>();
auto props = client_properties_[remote_id];
props->local_id_ = "C-" + std::string(client_id_);
props->remote_id_ = remote_id;
memcpy(&props->params_, &params_, sizeof(Params));
props->params_.user_id = props->local_id_.c_str();
props->peer_ = CreatePeer(&props->params_);
props->control_window_width_ = title_bar_height_ * 8.0f;
props->control_window_height_ = title_bar_height_ * 1.3f;
props->control_window_min_width_ = title_bar_height_ * 0.65f;
props->control_window_min_height_ = title_bar_height_ * 1.3f;
props->control_window_max_width_ = title_bar_height_ * 8.0f;
props->control_window_max_height_ = title_bar_height_ * 6.0f;
if (!props->peer_) {
LOG_INFO("Create peer [{}] instance failed", props->local_id_);
return -1;
}
for (auto& display_info : display_info_list_) {
AddVideoStream(props->peer_, display_info.name.c_str());
}
AddAudioStream(props->peer_, props->audio_label_.c_str());
AddDataStream(props->peer_, props->data_label_.c_str());
props->connection_status_ = ConnectionStatus::Connecting;
peer_to_init = props->peer_;
local_id = props->local_id_;
} }
for (auto& display_info : display_info_list_) {
AddVideoStream(props->peer_, display_info.name.c_str());
}
AddAudioStream(props->peer_, props->audio_label_.c_str());
AddDataStream(props->peer_, props->data_label_.c_str());
if (props->peer_) {
LOG_INFO("[{}] Create peer instance successful", props->local_id_);
Init(props->peer_);
LOG_INFO("[{}] Peer init finish", props->local_id_);
} else {
LOG_INFO("Create peer [{}] instance failed", props->local_id_);
}
props->connection_status_ = ConnectionStatus::Connecting;
} }
unique_lock.unlock();
if (peer_to_init) {
LOG_INFO("[{}] Create peer instance successful", local_id);
Init(peer_to_init);
LOG_INFO("[{}] Peer init finish", local_id);
}
} }
int ret = -1; int ret = -1;
std::shared_lock read_lock(client_properties_mutex_); // std::shared_lock read_lock(client_properties_mutex_);
auto props = client_properties_[remote_id]; auto props = client_properties_[remote_id];
if (!props->connection_established_) { if (!props->connection_established_) {
props->remember_password_ = remember_password; props->remember_password_ = remember_password;
@@ -211,7 +244,7 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
} }
} }
} }
read_lock.unlock(); // read_lock.unlock();
return 0; return 0;
} }

View File

@@ -6,12 +6,13 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <thread>
#include "OPPOSans_Regular.h" #include "OPPOSans_Regular.h"
#include "device_controller_factory.h" #include "device_controller_factory.h"
#include "fa_regular_400.h" #include "fa_regular_400.h"
#include "fa_solid_900.h" #include "fa_solid_900.h"
#include "layout.h" #include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "platform.h" #include "platform.h"
#include "rd_log.h" #include "rd_log.h"
@@ -20,8 +21,6 @@
#define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2 #define NV12_BUFFER_SIZE 1280 * 720 * 3 / 2
#define MOUSE_GRAB_PADDING 5
namespace crossdesk { namespace crossdesk {
std::vector<char> Render::SerializeRemoteAction(const RemoteAction& action) { std::vector<char> Render::SerializeRemoteAction(const RemoteAction& action) {
@@ -133,9 +132,39 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
int window_width, window_height; int window_width, window_height;
SDL_GetWindowSize(window, &window_width, &window_height); SDL_GetWindowSize(window, &window_width, &window_height);
if (area->y < 30 && area->y > MOUSE_GRAB_PADDING && // check if curosor is in tab bar
area->x < window_width - 120 && area->x > MOUSE_GRAB_PADDING && if (render->stream_window_inited_ && render->stream_window_created_ &&
!render->is_tab_bar_hovered_) { !render->fullscreen_button_pressed_ && render->stream_ctx_) {
ImGuiContext* prev_ctx = ImGui::GetCurrentContext();
ImGui::SetCurrentContext(render->stream_ctx_);
ImGuiWindow* tab_bar_window = ImGui::FindWindowByName("TabBar");
if (tab_bar_window && tab_bar_window->Active) {
ImGuiIO& io = ImGui::GetIO();
float scale_x = io.DisplayFramebufferScale.x;
float scale_y = io.DisplayFramebufferScale.y;
float tab_bar_x = tab_bar_window->Pos.x * scale_x;
float tab_bar_y = tab_bar_window->Pos.y * scale_y;
float tab_bar_width = tab_bar_window->Size.x * scale_x;
float tab_bar_height = tab_bar_window->Size.y * scale_y;
ImGui::SetCurrentContext(prev_ctx);
if (area->x >= tab_bar_x && area->x <= tab_bar_x + tab_bar_width &&
area->y >= tab_bar_y && area->y <= tab_bar_y + tab_bar_height) {
return SDL_HITTEST_NORMAL;
}
} else {
ImGui::SetCurrentContext(prev_ctx);
}
}
float mouse_grab_padding = render->title_bar_button_width_ * 0.16f;
if (area->y < render->title_bar_button_width_ &&
area->y > mouse_grab_padding &&
area->x < window_width - render->title_bar_button_width_ * 4.0f &&
area->x > mouse_grab_padding) {
return SDL_HITTEST_DRAGGABLE; return SDL_HITTEST_DRAGGABLE;
} }
@@ -143,25 +172,25 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
// return SDL_HITTEST_NORMAL; // return SDL_HITTEST_NORMAL;
// } // }
if (area->y < MOUSE_GRAB_PADDING) { if (area->y < mouse_grab_padding) {
if (area->x < MOUSE_GRAB_PADDING) { if (area->x < mouse_grab_padding) {
return SDL_HITTEST_RESIZE_TOPLEFT; return SDL_HITTEST_RESIZE_TOPLEFT;
} else if (area->x > window_width - MOUSE_GRAB_PADDING) { } else if (area->x > window_width - mouse_grab_padding) {
return SDL_HITTEST_RESIZE_TOPRIGHT; return SDL_HITTEST_RESIZE_TOPRIGHT;
} else { } else {
return SDL_HITTEST_RESIZE_TOP; return SDL_HITTEST_RESIZE_TOP;
} }
} else if (area->y > window_height - MOUSE_GRAB_PADDING) { } else if (area->y > window_height - mouse_grab_padding) {
if (area->x < MOUSE_GRAB_PADDING) { if (area->x < mouse_grab_padding) {
return SDL_HITTEST_RESIZE_BOTTOMLEFT; return SDL_HITTEST_RESIZE_BOTTOMLEFT;
} else if (area->x > window_width - MOUSE_GRAB_PADDING) { } else if (area->x > window_width - mouse_grab_padding) {
return SDL_HITTEST_RESIZE_BOTTOMRIGHT; return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
} else { } else {
return SDL_HITTEST_RESIZE_BOTTOM; return SDL_HITTEST_RESIZE_BOTTOM;
} }
} else if (area->x < MOUSE_GRAB_PADDING) { } else if (area->x < mouse_grab_padding) {
return SDL_HITTEST_RESIZE_LEFT; return SDL_HITTEST_RESIZE_LEFT;
} else if (area->x > window_width - MOUSE_GRAB_PADDING) { } else if (area->x > window_width - mouse_grab_padding) {
return SDL_HITTEST_RESIZE_RIGHT; return SDL_HITTEST_RESIZE_RIGHT;
} }
@@ -207,7 +236,7 @@ int Render::LoadSettingsFromCacheFile() {
memset(aes128_iv_, 0, sizeof(aes128_iv_)); memset(aes128_iv_, 0, sizeof(aes128_iv_));
thumbnail_.reset(); thumbnail_.reset();
thumbnail_ = std::make_unique<Thumbnail>(cache_path_ + "/thumbnails/"); thumbnail_ = std::make_shared<Thumbnail>(cache_path_ + "/thumbnails/");
thumbnail_->GetKeyAndIv(aes128_key_, aes128_iv_); thumbnail_->GetKeyAndIv(aes128_key_, aes128_iv_);
thumbnail_->DeleteAllFilesInDirectory(); thumbnail_->DeleteAllFilesInDirectory();
@@ -248,7 +277,7 @@ int Render::LoadSettingsFromCacheFile() {
memcpy(aes128_iv_, cd_cache_.iv, sizeof(cd_cache_.iv)); memcpy(aes128_iv_, cd_cache_.iv, sizeof(cd_cache_.iv));
thumbnail_.reset(); thumbnail_.reset();
thumbnail_ = std::make_unique<Thumbnail>(cache_path_ + "/thumbnails/", thumbnail_ = std::make_shared<Thumbnail>(cache_path_ + "/thumbnails/",
aes128_key_, aes128_iv_); aes128_key_, aes128_iv_);
language_button_value_ = (int)config_center_->GetLanguage(); language_button_value_ = (int)config_center_->GetLanguage();
@@ -365,13 +394,16 @@ int Render::StartSpeakerCapturer() {
if (speaker_capturer_) { if (speaker_capturer_) {
speaker_capturer_->Start(); speaker_capturer_->Start();
start_speaker_capturer_ = true;
} }
return 0; return 0;
} }
int Render::StopSpeakerCapturer() { int Render::StopSpeakerCapturer() {
if (speaker_capturer_) { if (speaker_capturer_) {
speaker_capturer_->Stop(); speaker_capturer_->Stop();
start_speaker_capturer_ = false;
} }
return 0; return 0;
@@ -459,14 +491,22 @@ int Render::CreateConnectionPeer() {
strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(), strncpy(signal_server_ip_self_, config_center_->GetSignalServerHost().c_str(),
sizeof(signal_server_ip_self_) - 1); sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0'; signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_, int signal_port = config_center_->GetSignalServerPort();
std::to_string(config_center_->GetSignalServerPort()).c_str(), if (signal_port > 0) {
sizeof(signal_server_port_self_) - 1); strncpy(signal_server_port_self_, std::to_string(signal_port).c_str(),
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0'; sizeof(signal_server_port_self_) - 1);
strncpy(coturn_server_port_self_, signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
std::to_string(config_center_->GetCoturnServerPort()).c_str(), } else {
sizeof(coturn_server_port_self_) - 1); signal_server_port_self_[0] = '\0';
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0'; }
int coturn_port = config_center_->GetCoturnServerPort();
if (coturn_port > 0) {
strncpy(coturn_server_port_self_, std::to_string(coturn_port).c_str(),
sizeof(coturn_server_port_self_) - 1);
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
} else {
coturn_server_port_self_[0] = '\0';
}
tls_cert_path_self_ = config_center_->GetCertFilePath(); tls_cert_path_self_ = config_center_->GetCertFilePath();
// peer config // peer config
@@ -612,21 +652,38 @@ int Render::CreateMainWindow() {
ImGui::SetCurrentContext(main_ctx_); ImGui::SetCurrentContext(main_ctx_);
if (!SDL_CreateWindowAndRenderer( if (!SDL_CreateWindowAndRenderer(
"Remote Desk", (int)main_window_width_default_, "Remote Desk", (int)main_window_width_, (int)main_window_height_,
(int)main_window_height_default_,
SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_BORDERLESS |
SDL_WINDOW_HIDDEN, SDL_WINDOW_HIDDEN,
&main_window_, &main_renderer_)) { &main_window_, &main_renderer_)) {
LOG_ERROR("Error creating main_window_ and main_renderer_: {}", LOG_ERROR("Error creating MainWindow and MainRenderer: {}", SDL_GetError());
SDL_GetError());
return -1; return -1;
} }
float dpi_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
if (std::abs(dpi_scale_ - dpi_scale) > 0.01f) {
dpi_scale_ = dpi_scale;
main_window_width_ = (int)(main_window_width_ * dpi_scale_);
main_window_height_ = (int)(main_window_height_ * dpi_scale_);
stream_window_width_ = (int)(stream_window_width_ * dpi_scale_);
stream_window_height_ = (int)(stream_window_height_ * dpi_scale_);
SDL_SetWindowSize(main_window_, (int)main_window_width_,
(int)main_window_height_);
}
SDL_SetWindowResizable(main_window_, false); SDL_SetWindowResizable(main_window_, false);
// for window region action // for window region action
SDL_SetWindowHitTest(main_window_, HitTestCallback, this); SDL_SetWindowHitTest(main_window_, HitTestCallback, this);
SetupFontAndStyle(true);
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(dpi_scale_);
style.FontScaleDpi = dpi_scale_;
#if _WIN32 #if _WIN32
SDL_PropertiesID props = SDL_GetWindowProperties(main_window_); SDL_PropertiesID props = SDL_GetWindowProperties(main_window_);
HWND main_hwnd = (HWND)SDL_GetPointerProperty( HWND main_hwnd = (HWND)SDL_GetPointerProperty(
@@ -638,6 +695,9 @@ int Render::CreateMainWindow() {
localization_language_index_); localization_language_index_);
#endif #endif
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
ImGui_ImplSDLRenderer3_Init(main_renderer_);
return 0; return 0;
} }
@@ -671,8 +731,8 @@ int Render::CreateStreamWindow() {
ImGui::SetCurrentContext(stream_ctx_); ImGui::SetCurrentContext(stream_ctx_);
if (!SDL_CreateWindowAndRenderer( if (!SDL_CreateWindowAndRenderer(
"Stream window", (int)stream_window_width_default_, "Stream window", (int)stream_window_width_,
(int)stream_window_height_default_, (int)stream_window_height_,
SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_BORDERLESS, SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_BORDERLESS,
&stream_window_, &stream_renderer_)) { &stream_window_, &stream_renderer_)) {
LOG_ERROR("Error creating stream_window_ and stream_renderer_: {}", LOG_ERROR("Error creating stream_window_ and stream_renderer_: {}",
@@ -687,6 +747,15 @@ int Render::CreateStreamWindow() {
// for window region action // for window region action
SDL_SetWindowHitTest(stream_window_, HitTestCallback, this); SDL_SetWindowHitTest(stream_window_, HitTestCallback, this);
SetupFontAndStyle(false);
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(dpi_scale_);
style.FontScaleDpi = dpi_scale_;
ImGui_ImplSDL3_InitForSDLRenderer(stream_window_, stream_renderer_);
ImGui_ImplSDLRenderer3_Init(stream_renderer_);
// change props->stream_render_rect_ // change props->stream_render_rect_
SDL_Event event; SDL_Event event;
event.type = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED; event.type = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
@@ -696,6 +765,9 @@ int Render::CreateStreamWindow() {
stream_window_created_ = true; stream_window_created_ = true;
just_created_ = true; just_created_ = true;
stream_window_inited_ = true;
LOG_INFO("Stream window inited");
return 0; return 0;
} }
@@ -720,7 +792,9 @@ int Render::DestroyStreamWindow() {
return 0; return 0;
} }
int Render::SetupFontAndStyle() { int Render::SetupFontAndStyle(bool main_window) {
float font_size = 32.0f;
// Setup Dear ImGui style // Setup Dear ImGui style
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@@ -730,7 +804,7 @@ int Render::SetupFontAndStyle() {
ImFontConfig config; ImFontConfig config;
config.FontDataOwnedByAtlas = false; config.FontDataOwnedByAtlas = false;
io.Fonts->AddFontFromMemoryTTF(OPPOSans_Regular_ttf, OPPOSans_Regular_ttf_len, io.Fonts->AddFontFromMemoryTTF(OPPOSans_Regular_ttf, OPPOSans_Regular_ttf_len,
32.0f, &config, font_size, &config,
io.Fonts->GetGlyphRangesChineseFull()); io.Fonts->GetGlyphRangesChineseFull());
config.MergeMode = true; config.MergeMode = true;
static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0}; static const ImWchar icon_ranges[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
@@ -740,7 +814,11 @@ int Render::SetupFontAndStyle() {
// Load system Chinese font as fallback // Load system Chinese font as fallback
config.MergeMode = false; config.MergeMode = false;
config.FontDataOwnedByAtlas = false; config.FontDataOwnedByAtlas = false;
system_chinese_font_ = nullptr; if (main_window) {
main_windows_system_chinese_font_ = nullptr;
} else {
stream_windows_system_chinese_font_ = nullptr;
}
#if defined(_WIN32) #if defined(_WIN32)
// Windows: Try Microsoft YaHei (微软雅黑) first, then SimSun (宋体) // Windows: Try Microsoft YaHei (微软雅黑) first, then SimSun (宋体)
@@ -766,52 +844,44 @@ int Render::SetupFontAndStyle() {
std::ifstream font_file(font_paths[i], std::ios::binary); std::ifstream font_file(font_paths[i], std::ios::binary);
if (font_file.good()) { if (font_file.good()) {
font_file.close(); font_file.close();
system_chinese_font_ = io.Fonts->AddFontFromFileTTF( if (main_window) {
font_paths[i], 32.0f, &config, io.Fonts->GetGlyphRangesChineseFull()); main_windows_system_chinese_font_ =
if (system_chinese_font_ != nullptr) { io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]); io.Fonts->GetGlyphRangesChineseFull());
break; if (main_windows_system_chinese_font_ != nullptr) {
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
break;
}
} else {
stream_windows_system_chinese_font_ =
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
io.Fonts->GetGlyphRangesChineseFull());
if (stream_windows_system_chinese_font_ != nullptr) {
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
break;
}
} }
} }
} }
// If no system font found, use default font // If no system font found, use default font
if (system_chinese_font_ == nullptr) { if (main_window) {
system_chinese_font_ = io.Fonts->AddFontDefault(&config); if (main_windows_system_chinese_font_ == nullptr) {
LOG_WARN("System Chinese font not found, using default font"); main_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
LOG_WARN("System Chinese font not found, using default font");
}
} else {
if (stream_windows_system_chinese_font_ == nullptr) {
stream_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
LOG_WARN("System Chinese font not found, using default font");
}
} }
io.Fonts->Build();
ImGui::StyleColorsLight(); ImGui::StyleColorsLight();
return 0; return 0;
} }
int Render::SetupMainWindow() {
if (!main_ctx_) {
LOG_ERROR("Main context is null");
return -1;
}
ImGui::SetCurrentContext(main_ctx_);
SetupFontAndStyle();
SDL_GetWindowSizeInPixels(main_window_, &main_window_width_real_,
&main_window_height_real_);
main_window_dpi_scaling_w_ = main_window_width_real_ / main_window_width_;
main_window_dpi_scaling_h_ = main_window_width_real_ / main_window_width_;
SDL_SetRenderScale(main_renderer_, main_window_dpi_scaling_w_,
main_window_dpi_scaling_h_);
LOG_INFO("Use dpi scaling [{}x{}] for main window",
main_window_dpi_scaling_w_, main_window_dpi_scaling_h_);
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
ImGui_ImplSDLRenderer3_Init(main_renderer_);
return 0;
}
int Render::DestroyMainWindowContext() { int Render::DestroyMainWindowContext() {
ImGui::SetCurrentContext(main_ctx_); ImGui::SetCurrentContext(main_ctx_);
ImGui_ImplSDLRenderer3_Shutdown(); ImGui_ImplSDLRenderer3_Shutdown();
@@ -821,42 +891,6 @@ int Render::DestroyMainWindowContext() {
return 0; return 0;
} }
int Render::SetupStreamWindow() {
if (stream_window_inited_) {
return 0;
}
if (!stream_ctx_) {
LOG_ERROR("Stream context is null");
return -1;
}
ImGui::SetCurrentContext(stream_ctx_);
SetupFontAndStyle();
SDL_GetWindowSizeInPixels(stream_window_, &stream_window_width_real_,
&stream_window_height_real_);
stream_window_dpi_scaling_w_ =
stream_window_width_real_ / stream_window_width_;
stream_window_dpi_scaling_h_ =
stream_window_width_real_ / stream_window_width_;
SDL_SetRenderScale(stream_renderer_, stream_window_dpi_scaling_w_,
stream_window_dpi_scaling_h_);
LOG_INFO("Use dpi scaling [{}x{}] for stream window",
stream_window_dpi_scaling_w_, stream_window_dpi_scaling_h_);
ImGui_ImplSDL3_InitForSDLRenderer(stream_window_, stream_renderer_);
ImGui_ImplSDLRenderer3_Init(stream_renderer_);
stream_window_inited_ = true;
LOG_INFO("Stream window inited");
return 0;
}
int Render::DestroyStreamWindowContext() { int Render::DestroyStreamWindowContext() {
stream_window_inited_ = false; stream_window_inited_ = false;
ImGui::SetCurrentContext(stream_ctx_); ImGui::SetCurrentContext(stream_ctx_);
@@ -878,15 +912,15 @@ int Render::DrawMainWindow() {
ImGui_ImplSDL3_NewFrame(); ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame(); ImGui::NewFrame();
ImGuiIO& io = ImGui::GetIO();
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y),
ImVec2(main_window_width_, main_window_height_default_), ImGuiCond_Always);
ImGuiCond_Always);
ImGui::Begin("MainRender", nullptr, ImGui::Begin("MainRender", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
TitleBar(true); TitleBar(true);
@@ -904,7 +938,10 @@ int Render::DrawMainWindow() {
ImGui::End(); ImGui::End();
// Rendering // Rendering
(void)io;
ImGui::Render(); ImGui::Render();
SDL_SetRenderScale(main_renderer_, io.DisplayFramebufferScale.x,
io.DisplayFramebufferScale.y);
SDL_RenderClear(main_renderer_); SDL_RenderClear(main_renderer_);
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), main_renderer_); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), main_renderer_);
SDL_RenderPresent(main_renderer_); SDL_RenderPresent(main_renderer_);
@@ -925,29 +962,38 @@ int Render::DrawStreamWindow() {
StreamWindow(); StreamWindow();
ImGuiIO& io = ImGui::GetIO();
float stream_title_window_height =
fullscreen_button_pressed_ ? 0 : title_bar_height_;
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
// Set minimum window size to 0 to allow exact height control
ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x, stream_title_window_height),
ImGuiCond_Always);
ImGui::Begin("StreamTitleWindow", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoDocking);
ImGui::PopStyleVar(2);
ImGui::PopStyleColor();
if (!fullscreen_button_pressed_) { if (!fullscreen_button_pressed_) {
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(stream_window_width_,
fullscreen_button_pressed_ ? 0 : title_bar_height_),
ImGuiCond_Always);
ImGui::Begin("StreamWindowTitleBar", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor();
TitleBar(false); TitleBar(false);
ImGui::End();
} }
ImGui::End();
// Rendering // Rendering
(void)io;
ImGui::Render(); ImGui::Render();
SDL_SetRenderScale(stream_renderer_, io.DisplayFramebufferScale.x,
io.DisplayFramebufferScale.y);
SDL_RenderClear(stream_renderer_); SDL_RenderClear(stream_renderer_);
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) { for (auto& it : client_properties_) {
auto props = it.second; auto props = it.second;
if (props->tab_selected_) { if (props->tab_selected_) {
@@ -1000,10 +1046,15 @@ int Render::Run() {
config_center_->GetSignalServerHost().c_str(), config_center_->GetSignalServerHost().c_str(),
sizeof(signal_server_ip_self_) - 1); sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0'; signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_, int signal_port_init = config_center_->GetSignalServerPort();
std::to_string(config_center_->GetSignalServerPort()).c_str(), if (signal_port_init > 0) {
sizeof(signal_server_port_self_) - 1); strncpy(signal_server_port_self_,
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0'; std::to_string(signal_port_init).c_str(),
sizeof(signal_server_port_self_) - 1);
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
} else {
signal_server_port_self_[0] = '\0';
}
strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1); strncpy(cert_file_path_, cert_path_.c_str(), sizeof(cert_file_path_) - 1);
cert_file_path_[sizeof(cert_file_path_) - 1] = '\0'; cert_file_path_[sizeof(cert_file_path_) - 1] = '\0';
} else { } else {
@@ -1078,7 +1129,6 @@ void Render::InitializeModules() {
void Render::InitializeMainWindow() { void Render::InitializeMainWindow() {
CreateMainWindow(); CreateMainWindow();
SetupMainWindow();
if (SDL_WINDOW_HIDDEN & SDL_GetWindowFlags(main_window_)) { if (SDL_WINDOW_HIDDEN & SDL_GetWindowFlags(main_window_)) {
SDL_ShowWindow(main_window_); SDL_ShowWindow(main_window_);
} }
@@ -1189,7 +1239,6 @@ void Render::HandleRecentConnections() {
void Render::HandleStreamWindow() { void Render::HandleStreamWindow() {
if (need_to_create_stream_window_) { if (need_to_create_stream_window_) {
CreateStreamWindow(); CreateStreamWindow();
SetupStreamWindow();
need_to_create_stream_window_ = false; need_to_create_stream_window_ = false;
} }
@@ -1230,6 +1279,9 @@ void Render::Cleanup() {
CleanupFactories(); CleanupFactories();
CleanupPeers(); CleanupPeers();
WaitForThumbnailSaveTasks();
AudioDeviceDestroy(); AudioDeviceDestroy();
DestroyMainWindowContext(); DestroyMainWindowContext();
DestroyMainWindow(); DestroyMainWindow();
@@ -1257,10 +1309,29 @@ void Render::CleanupPeer(std::shared_ptr<SubStreamWindowProperties> props) {
SDL_FlushEvent(STREAM_REFRESH_EVENT); SDL_FlushEvent(STREAM_REFRESH_EVENT);
if (props->dst_buffer_) { if (props->dst_buffer_) {
thumbnail_->SaveToThumbnail( size_t buffer_size = props->dst_buffer_capacity_;
(char*)props->dst_buffer_, props->video_width_, props->video_height_, std::vector<unsigned char> buffer_copy(buffer_size);
props->remote_id_, props->remote_host_name_, memcpy(buffer_copy.data(), props->dst_buffer_, buffer_size);
props->remember_password_ ? props->remote_password_ : "");
int video_width = props->video_width_;
int video_height = props->video_height_;
std::string remote_id = props->remote_id_;
std::string remote_host_name = props->remote_host_name_;
std::string password =
props->remember_password_ ? props->remote_password_ : "";
std::thread save_thread([buffer_copy, video_width, video_height, remote_id,
remote_host_name, password,
thumbnail = thumbnail_]() {
thumbnail->SaveToThumbnail((char*)buffer_copy.data(), video_width,
video_height, remote_id, remote_host_name,
password);
});
{
std::lock_guard<std::mutex> lock(thumbnail_save_threads_mutex_);
thumbnail_save_threads_.emplace_back(std::move(save_thread));
}
} }
if (props->peer_) { if (props->peer_) {
@@ -1285,7 +1356,7 @@ void Render::CleanupPeers() {
} }
{ {
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) { for (auto& it : client_properties_) {
auto props = it.second; auto props = it.second;
CleanupPeer(props); CleanupPeer(props);
@@ -1293,11 +1364,30 @@ void Render::CleanupPeers() {
} }
{ {
std::unique_lock lock(client_properties_mutex_); // std::unique_lock lock(client_properties_mutex_);
client_properties_.clear(); client_properties_.clear();
} }
} }
void Render::WaitForThumbnailSaveTasks() {
std::vector<std::thread> threads_to_join;
{
std::lock_guard<std::mutex> lock(thumbnail_save_threads_mutex_);
threads_to_join.swap(thumbnail_save_threads_);
}
if (threads_to_join.empty()) {
return;
}
for (auto& thread : threads_to_join) {
if (thread.joinable()) {
thread.join();
}
}
}
void Render::CleanSubStreamWindowProperties( void Render::CleanSubStreamWindowProperties(
std::shared_ptr<SubStreamWindowProperties> props) { std::shared_ptr<SubStreamWindowProperties> props) {
if (props->stream_texture_) { if (props->stream_texture_) {
@@ -1312,7 +1402,7 @@ void Render::CleanSubStreamWindowProperties(
} }
void Render::UpdateRenderRect() { void Render::UpdateRenderRect() {
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto& [_, props] : client_properties_) { for (auto& [_, props] : client_properties_) {
if (!props->reset_control_bar_pos_) { if (!props->reset_control_bar_pos_) {
props->mouse_diff_control_bar_pos_x_ = 0; props->mouse_diff_control_bar_pos_x_ = 0;
@@ -1388,7 +1478,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
DestroyStreamWindowContext(); DestroyStreamWindowContext();
{ {
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto& [host_name, props] : client_properties_) { for (auto& [host_name, props] : client_properties_) {
thumbnail_->SaveToThumbnail( thumbnail_->SaveToThumbnail(
(char*)props->dst_buffer_, props->video_width_, (char*)props->dst_buffer_, props->video_width_,
@@ -1419,7 +1509,7 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
} }
{ {
std::unique_lock lock(client_properties_mutex_); // std::unique_lock lock(client_properties_mutex_);
client_properties_.clear(); client_properties_.clear();
} }

View File

@@ -18,6 +18,7 @@
#include <shared_mutex> #include <shared_mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include "IconsFontAwesome6.h" #include "IconsFontAwesome6.h"
#include "config_center.h" #include "config_center.h"
@@ -71,10 +72,10 @@ class Render {
float sub_stream_window_height_ = 720; float sub_stream_window_height_ = 720;
float control_window_min_width_ = 20; float control_window_min_width_ = 20;
float control_window_max_width_ = 230; float control_window_max_width_ = 230;
float control_window_min_height_ = 40; float control_window_min_height_ = 38;
float control_window_max_height_ = 170; float control_window_max_height_ = 180;
float control_window_width_ = 230; float control_window_width_ = 230;
float control_window_height_ = 40; float control_window_height_ = 38;
float control_bar_pos_x_ = 0; float control_bar_pos_x_ = 0;
float control_bar_pos_y_ = 30; float control_bar_pos_y_ = 30;
float mouse_diff_control_bar_pos_x_ = 0; float mouse_diff_control_bar_pos_x_ = 0;
@@ -179,10 +180,8 @@ class Render {
int DestroyMainWindow(); int DestroyMainWindow();
int CreateStreamWindow(); int CreateStreamWindow();
int DestroyStreamWindow(); int DestroyStreamWindow();
int SetupFontAndStyle(); int SetupFontAndStyle(bool main_window);
int SetupMainWindow();
int DestroyMainWindowContext(); int DestroyMainWindowContext();
int SetupStreamWindow();
int DestroyStreamWindowContext(); int DestroyStreamWindowContext();
int DrawMainWindow(); int DrawMainWindow();
int DrawStreamWindow(); int DrawStreamWindow();
@@ -295,13 +294,15 @@ class Render {
/* ------ all windows property start ------ */ /* ------ all windows property start ------ */
float title_bar_width_ = 640; float title_bar_width_ = 640;
float title_bar_height_ = 30; float title_bar_height_ = 30;
float title_bar_button_width_ = 30;
float title_bar_button_height_ = 30;
/* ------ all windows property end ------ */ /* ------ all windows property end ------ */
/* ------ main window property start ------ */ /* ------ main window property start ------ */
// thumbnail // thumbnail
unsigned char aes128_key_[16]; unsigned char aes128_key_[16];
unsigned char aes128_iv_[16]; unsigned char aes128_iv_[16];
std::unique_ptr<Thumbnail> thumbnail_; std::shared_ptr<Thumbnail> thumbnail_;
// recent connections // recent connections
std::vector<std::pair<std::string, Thumbnail::RecentConnection>> std::vector<std::pair<std::string, Thumbnail::RecentConnection>>
@@ -314,7 +315,8 @@ class Render {
SDL_Window* main_window_ = nullptr; SDL_Window* main_window_ = nullptr;
SDL_Renderer* main_renderer_ = nullptr; SDL_Renderer* main_renderer_ = nullptr;
ImGuiContext* main_ctx_ = nullptr; ImGuiContext* main_ctx_ = nullptr;
ImFont* system_chinese_font_ = nullptr; // System Chinese font for fallback ImFont* main_windows_system_chinese_font_ = nullptr;
ImFont* stream_windows_system_chinese_font_ = nullptr;
bool exit_ = false; bool exit_ = false;
const int sdl_refresh_ms_ = 16; // ~60 FPS const int sdl_refresh_ms_ = 16; // ~60 FPS
#if _WIN32 #if _WIN32
@@ -342,6 +344,7 @@ class Render {
int main_window_height_real_ = 540; int main_window_height_real_ = 540;
float main_window_dpi_scaling_w_ = 1.0f; float main_window_dpi_scaling_w_ = 1.0f;
float main_window_dpi_scaling_h_ = 1.0f; float main_window_dpi_scaling_h_ = 1.0f;
float dpi_scale_ = 1.0f;
float main_window_width_default_ = 640; float main_window_width_default_ = 640;
float main_window_height_default_ = 480; float main_window_height_default_ = 480;
float main_window_width_ = 640; float main_window_width_ = 640;
@@ -510,6 +513,11 @@ class Render {
void CloseTab(decltype(client_properties_)::iterator& it); void CloseTab(decltype(client_properties_)::iterator& it);
/* ------ stream window property end ------ */ /* ------ stream window property end ------ */
/* ------ async thumbnail save tasks ------ */
std::vector<std::thread> thumbnail_save_threads_;
std::mutex thumbnail_save_threads_mutex_;
void WaitForThumbnailSaveTasks();
/* ------ server mode ------ */ /* ------ server mode ------ */
std::unordered_map<std::string, ConnectionStatus> connection_status_; std::unordered_map<std::string, ConnectionStatus> connection_status_;
}; };

View File

@@ -21,7 +21,7 @@ int Render::SendKeyCommand(int key_code, bool is_down) {
remote_action.k.key_value = key_code; remote_action.k.key_value = key_code;
if (!controlled_remote_id_.empty()) { if (!controlled_remote_id_.empty()) {
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
if (client_properties_.find(controlled_remote_id_) != if (client_properties_.find(controlled_remote_id_) !=
client_properties_.end()) { client_properties_.end()) {
auto props = client_properties_[controlled_remote_id_]; auto props = client_properties_[controlled_remote_id_];
@@ -45,7 +45,7 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
float ratio_x, ratio_y = 0; float ratio_x, ratio_y = 0;
RemoteAction remote_action; RemoteAction remote_action;
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) { for (auto& it : client_properties_) {
auto props = it.second; auto props = it.second;
if (!props->control_mouse_) { if (!props->control_mouse_) {
@@ -162,7 +162,7 @@ void Render::SdlCaptureAudioIn(void* userdata, Uint8* stream, int len) {
} }
if (1) { if (1) {
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
for (const auto& it : render->client_properties_) { for (const auto& it : render->client_properties_) {
auto props = it.second; auto props = it.second;
if (props->connection_status_ == ConnectionStatus::Connected) { if (props->connection_status_ == ConnectionStatus::Connected) {
@@ -218,7 +218,7 @@ void Render::OnReceiveVideoBufferCb(const XVideoFrame* video_frame,
} }
std::string remote_id(user_id, user_id_size); std::string remote_id(user_id, user_id_size);
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) == if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) { render->client_properties_.end()) {
return; return;
@@ -314,7 +314,7 @@ void Render::OnReceiveDataBufferCb(const char* data, size_t size,
} }
std::string remote_id(user_id, user_id_size); std::string remote_id(user_id, user_id_size);
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) != if (render->client_properties_.find(remote_id) !=
render->client_properties_.end()) { render->client_properties_.end()) {
// local // local
@@ -386,7 +386,7 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
} }
std::string remote_id(client_id.begin() + 2, client_id.end()); std::string remote_id(client_id.begin() + 2, client_id.end());
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) == if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) { render->client_properties_.end()) {
return; return;
@@ -416,7 +416,7 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
if (!render) return; if (!render) return;
std::string remote_id(user_id, user_id_size); std::string remote_id(user_id, user_id_size);
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
auto it = render->client_properties_.find(remote_id); auto it = render->client_properties_.find(remote_id);
auto props = (it != render->client_properties_.end()) ? it->second : nullptr; auto props = (it != render->client_properties_.end()) ? it->second : nullptr;
@@ -484,12 +484,12 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
render->need_to_send_host_info_ = true; render->need_to_send_host_info_ = true;
render->start_screen_capturer_ = true; render->start_screen_capturer_ = true;
render->start_speaker_capturer_ = true; render->start_speaker_capturer_ = true;
// #ifdef CROSSDESK_DEBUG #ifdef CROSSDESK_DEBUG
// render->start_mouse_controller_ = false; render->start_mouse_controller_ = false;
// render->start_keyboard_capturer_ = false; render->start_keyboard_capturer_ = false;
// #else #else
render->start_mouse_controller_ = true; render->start_mouse_controller_ = true;
// #endif #endif
if (std::all_of(render->connection_status_.begin(), if (std::all_of(render->connection_status_.begin(),
render->connection_status_.end(), [](const auto& kv) { render->connection_status_.end(), [](const auto& kv) {
return kv.first.find("web") != std::string::npos; return kv.first.find("web") != std::string::npos;
@@ -577,7 +577,7 @@ void Render::NetStatusReport(const char* client_id, size_t client_id_size,
} }
std::string remote_id(user_id, user_id_size); std::string remote_id(user_id, user_id_size);
std::shared_lock lock(render->client_properties_mutex_); // std::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) == if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) { render->client_properties_.end()) {
return; return;

View File

@@ -32,26 +32,30 @@ int LossRateDisplay(float loss_rate) {
} }
int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) { int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); float button_width = title_bar_height_ * 0.8f;
float button_height = title_bar_height_ * 0.8f;
float line_padding = title_bar_height_ * 0.12f;
float line_thickness = title_bar_height_ * 0.07f;
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
if (props->control_bar_expand_) { if (props->control_bar_expand_) {
ImGui::SetCursorPosX(props->is_control_bar_in_left_ ImGui::SetCursorPosX(props->is_control_bar_in_left_
? (props->control_window_width_ + 5.0f) ? props->control_window_width_ * 1.03f
: 38.0f); : props->control_window_width_ * 0.2f);
// mouse control button
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (props->is_control_bar_in_left_) { ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine(ImVec2(ImGui::GetCursorScreenPos().x - 5.0f, if (!props->is_control_bar_in_left_) {
ImGui::GetCursorScreenPos().y - 7.0f), draw_list->AddLine(
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f, ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.56f,
ImGui::GetCursorScreenPos().y - 7.0f + ImGui::GetCursorScreenPos().y + button_height * 0.2f),
props->control_window_height_), ImVec2(ImGui::GetCursorScreenPos().x - button_height * 0.56f,
IM_COL32(178, 178, 178, 255), 1.0f); ImGui::GetCursorScreenPos().y + button_height * 0.8f),
IM_COL32(178, 178, 178, 255), 2.0f);
} }
std::string display = ICON_FA_DISPLAY; std::string display = ICON_FA_DISPLAY;
if (ImGui::Button(display.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(display.c_str(), ImVec2(button_width, button_height))) {
ImGui::OpenPopup("display"); ImGui::OpenPopup("display");
} }
@@ -75,28 +79,29 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
} }
props->display_selectable_hovered_ = ImGui::IsWindowHovered(); props->display_selectable_hovered_ = ImGui::IsWindowHovered();
} }
ImGui::SetWindowFontScale(1.0f);
ImGui::EndPopup(); ImGui::EndPopup();
} }
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.5f);
ImVec2 text_size = ImGui::CalcTextSize( ImVec2 text_size = ImGui::CalcTextSize(
std::to_string(props->selected_display_ + 1).c_str()); std::to_string(props->selected_display_ + 1).c_str());
ImVec2 text_pos = ImVec2 text_pos =
ImVec2(btn_min.x + (btn_size_actual.x - text_size.x) * 0.5f, ImVec2(btn_min.x + (btn_size_actual.x - text_size.x) * 0.5f,
btn_min.y + (btn_size_actual.y - text_size.y) * 0.5f - 2.0f); btn_min.y + (btn_size_actual.y - text_size.y) * 0.35f);
ImGui::GetWindowDrawList()->AddText( ImGui::GetWindowDrawList()->AddText(
text_pos, IM_COL32(0, 0, 0, 255), text_pos, IM_COL32(0, 0, 0, 255),
std::to_string(props->selected_display_ + 1).c_str()); std::to_string(props->selected_display_ + 1).c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::SameLine(); ImGui::SameLine();
float disable_mouse_x = ImGui::GetCursorScreenPos().x + 4.0f; float mouse_x = ImGui::GetCursorScreenPos().x;
float disable_mouse_y = ImGui::GetCursorScreenPos().y + 4.0f; float mouse_y = ImGui::GetCursorScreenPos().y;
float disable_mouse_x = mouse_x + line_padding;
float disable_mouse_y = mouse_y + line_padding;
std::string mouse = props->mouse_control_button_pressed_ std::string mouse = props->mouse_control_button_pressed_
? ICON_FA_COMPUTER_MOUSE ? ICON_FA_COMPUTER_MOUSE
: ICON_FA_COMPUTER_MOUSE; : ICON_FA_COMPUTER_MOUSE;
if (ImGui::Button(mouse.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(mouse.c_str(), ImVec2(button_width, button_height))) {
if (props->connection_established_) { if (props->connection_established_) {
start_keyboard_capturer_ = !start_keyboard_capturer_; start_keyboard_capturer_ = !start_keyboard_capturer_;
props->control_mouse_ = !props->control_mouse_; props->control_mouse_ = !props->control_mouse_;
@@ -108,30 +113,35 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
: localization::control_mouse[localization_language_index_]; : localization::control_mouse[localization_language_index_];
} }
} }
if (!props->mouse_control_button_pressed_) { if (!props->mouse_control_button_pressed_) {
draw_list->AddLine(ImVec2(disable_mouse_x, disable_mouse_y),
ImVec2(mouse_x + button_width - line_padding,
mouse_y + button_height - line_padding),
IM_COL32(0, 0, 0, 255), line_thickness);
draw_list->AddLine( draw_list->AddLine(
ImVec2(disable_mouse_x, disable_mouse_y), ImVec2(disable_mouse_x - line_thickness * 0.7f,
ImVec2(disable_mouse_x + 16.0f, disable_mouse_y + 14.2f), disable_mouse_y + line_thickness * 0.7f),
IM_COL32(0, 0, 0, 255), 2.0f); ImVec2(
draw_list->AddLine( mouse_x + button_width - line_padding - line_thickness * 0.7f,
ImVec2(disable_mouse_x - 1.2f, disable_mouse_y + 1.2f), mouse_y + button_height - line_padding + line_thickness * 0.7f),
ImVec2(disable_mouse_x + 15.3f, disable_mouse_y + 15.4f),
ImGui::IsItemHovered() ? IM_COL32(66, 150, 250, 255) ImGui::IsItemHovered() ? IM_COL32(66, 150, 250, 255)
: IM_COL32(179, 213, 253, 255), : IM_COL32(179, 213, 253, 255),
2.0f); line_thickness);
} }
ImGui::SameLine(); ImGui::SameLine();
// audio capture button // audio capture button
float disable_audio_x = ImGui::GetCursorScreenPos().x + 4; float audio_x = ImGui::GetCursorScreenPos().x;
float disable_audio_y = ImGui::GetCursorScreenPos().y + 4.0f; float audio_y = ImGui::GetCursorScreenPos().y;
// std::string audio = audio_capture_button_pressed_ ? ICON_FA_VOLUME_HIGH float disable_audio_x = audio_x + line_padding;
// : float disable_audio_y = audio_y + line_padding;
// ICON_FA_VOLUME_XMARK;
std::string audio = props->audio_capture_button_pressed_ std::string audio = props->audio_capture_button_pressed_
? ICON_FA_VOLUME_HIGH ? ICON_FA_VOLUME_HIGH
: ICON_FA_VOLUME_HIGH; : ICON_FA_VOLUME_HIGH;
if (ImGui::Button(audio.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(audio.c_str(), ImVec2(button_width, button_height))) {
if (props->connection_established_) { if (props->connection_established_) {
props->audio_capture_button_pressed_ = props->audio_capture_button_pressed_ =
!props->audio_capture_button_pressed_; !props->audio_capture_button_pressed_;
@@ -148,17 +158,21 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
props->data_label_.c_str()); props->data_label_.c_str());
} }
} }
if (!props->audio_capture_button_pressed_) { if (!props->audio_capture_button_pressed_) {
draw_list->AddLine(ImVec2(disable_audio_x, disable_audio_y),
ImVec2(audio_x + button_width - line_padding,
audio_y + button_height - line_padding),
IM_COL32(0, 0, 0, 255), line_thickness);
draw_list->AddLine( draw_list->AddLine(
ImVec2(disable_audio_x, disable_audio_y), ImVec2(disable_audio_x - line_thickness * 0.7f,
ImVec2(disable_audio_x + 16.0f, disable_audio_y + 14.2f), disable_audio_y + line_thickness * 0.7f),
IM_COL32(0, 0, 0, 255), 2.0f); ImVec2(
draw_list->AddLine( audio_x + button_width - line_padding - line_thickness * 0.7f,
ImVec2(disable_audio_x - 1.2f, disable_audio_y + 1.2f), audio_y + button_height - line_padding + line_thickness * 0.7f),
ImVec2(disable_audio_x + 15.3f, disable_audio_y + 15.4f),
ImGui::IsItemHovered() ? IM_COL32(66, 150, 250, 255) ImGui::IsItemHovered() ? IM_COL32(66, 150, 250, 255)
: IM_COL32(179, 213, 253, 255), : IM_COL32(179, 213, 253, 255),
2.0f); line_thickness);
} }
ImGui::SameLine(); ImGui::SameLine();
@@ -170,7 +184,9 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
button_color_style_pushed = true; button_color_style_pushed = true;
} }
std::string net_traffic_stats = ICON_FA_SIGNAL; std::string net_traffic_stats = ICON_FA_SIGNAL;
if (ImGui::Button(net_traffic_stats.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(net_traffic_stats.c_str(),
ImVec2(button_width, button_height))) {
props->net_traffic_stats_button_pressed_ = props->net_traffic_stats_button_pressed_ =
!props->net_traffic_stats_button_pressed_; !props->net_traffic_stats_button_pressed_;
props->control_window_height_is_changing_ = true; props->control_window_height_is_changing_ = true;
@@ -182,6 +198,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
: localization::show_net_traffic_stats : localization::show_net_traffic_stats
[localization_language_index_]; [localization_language_index_];
} }
if (button_color_style_pushed) { if (button_color_style_pushed) {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
button_color_style_pushed = false; button_color_style_pushed = false;
@@ -191,7 +208,9 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
// fullscreen button // fullscreen button
std::string fullscreen = std::string fullscreen =
fullscreen_button_pressed_ ? ICON_FA_COMPRESS : ICON_FA_EXPAND; fullscreen_button_pressed_ ? ICON_FA_COMPRESS : ICON_FA_EXPAND;
if (ImGui::Button(fullscreen.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(fullscreen.c_str(),
ImVec2(button_width, button_height))) {
fullscreen_button_pressed_ = !fullscreen_button_pressed_; fullscreen_button_pressed_ = !fullscreen_button_pressed_;
props->fullscreen_button_label_ = props->fullscreen_button_label_ =
fullscreen_button_pressed_ fullscreen_button_pressed_
@@ -209,25 +228,35 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::SameLine(); ImGui::SameLine();
// close button // close button
std::string close_button = ICON_FA_XMARK; std::string close_button = ICON_FA_XMARK;
if (ImGui::Button(close_button.c_str(), ImVec2(25, 25))) { ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(close_button.c_str(),
ImVec2(button_width, button_height))) {
CleanupPeer(props); CleanupPeer(props);
} }
ImGui::SameLine(); ImGui::SameLine();
if (!props->is_control_bar_in_left_) { if (props->is_control_bar_in_left_) {
draw_list->AddLine(ImVec2(ImGui::GetCursorScreenPos().x - 3.0f, draw_list->AddLine(
ImGui::GetCursorScreenPos().y - 7.0f), ImVec2(ImGui::GetCursorScreenPos().x + button_height * 0.2f,
ImVec2(ImGui::GetCursorScreenPos().x - 3.0f, ImGui::GetCursorScreenPos().y + button_height * 0.2f),
ImGui::GetCursorScreenPos().y - 7.0f + ImVec2(ImGui::GetCursorScreenPos().x + button_height * 0.2f,
props->control_window_height_), ImGui::GetCursorScreenPos().y + button_height * 0.8f),
IM_COL32(178, 178, 178, 255), 1.0f); IM_COL32(178, 178, 178, 255), 2.0f);
} }
ImGui::SameLine();
} }
ImGui::SetCursorPosX(props->is_control_bar_in_left_ float expand_button_pos_x =
? (props->control_window_width_ * 2 - 20.0f) props->control_bar_expand_ ? (props->is_control_bar_in_left_
: 5.0f); ? props->control_window_width_ * 1.91f
: props->control_window_width_ * 0.03f)
: (props->is_control_bar_in_left_
? props->control_window_width_ * 1.02f
: props->control_window_width_ * 0.23f);
ImGui::SetCursorPosX(expand_button_pos_x);
std::string control_bar = std::string control_bar =
props->control_bar_expand_ props->control_bar_expand_
@@ -235,13 +264,14 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
: ICON_FA_ANGLE_RIGHT) : ICON_FA_ANGLE_RIGHT)
: (props->is_control_bar_in_left_ ? ICON_FA_ANGLE_RIGHT : (props->is_control_bar_in_left_ ? ICON_FA_ANGLE_RIGHT
: ICON_FA_ANGLE_LEFT); : ICON_FA_ANGLE_LEFT);
if (ImGui::Button(control_bar.c_str(), ImVec2(15, 25))) { if (ImGui::Button(control_bar.c_str(),
ImVec2(button_height * 0.6f, button_height))) {
props->control_bar_expand_ = !props->control_bar_expand_; props->control_bar_expand_ = !props->control_bar_expand_;
props->control_bar_button_pressed_time_ = ImGui::GetTime(); props->control_bar_button_pressed_time_ = ImGui::GetTime();
props->control_window_width_is_changing_ = true; props->control_window_width_is_changing_ = true;
if (!props->control_bar_expand_) { if (!props->control_bar_expand_) {
props->control_window_height_ = 40; props->control_window_height_ = props->control_window_min_height_;
props->net_traffic_stats_button_pressed_ = false; props->net_traffic_stats_button_pressed_ = false;
} }
} }
@@ -257,13 +287,13 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
int Render::NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props) { int Render::NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::SetCursorPos(ImVec2(props->is_control_bar_in_left_ ImGui::SetCursorPos(ImVec2(props->is_control_bar_in_left_
? (props->control_window_width_ + 5.0f) ? props->control_window_width_ * 1.02f
: 5.0f, : props->control_window_width_ * 0.02f,
40.0f)); props->control_window_min_height_));
ImGui::SetWindowFontScale(0.5f);
if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH, if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH,
ImVec2(props->control_window_max_width_ - 10.0f, ImVec2(props->control_window_max_width_ * 0.9f,
props->control_window_max_height_ - 60.0f))) { props->control_window_max_height_ - 0.9f))) {
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
@@ -322,9 +352,12 @@ int Render::NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::Text("FPS"); ImGui::Text("FPS");
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%d", props->fps_); ImGui::Text("%d", props->fps_);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::SetWindowFontScale(1.0f);
return 0; return 0;
} }

View File

@@ -1,32 +1,38 @@
#include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "render.h" #include "render.h"
namespace crossdesk { namespace crossdesk {
int Render::StatusBar() { int Render::StatusBar() {
ImGuiIO& io = ImGui::GetIO();
float status_bar_width = io.DisplaySize.x;
float status_bar_height = io.DisplaySize.y * STATUS_BAR_HEIGHT;
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
static bool a, b, c, d, e; static bool a, b, c, d, e;
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(ImVec2(0, io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT)),
ImVec2(0, main_window_height_default_ - status_bar_height_ - 1), ImGuiCond_Always);
ImGuiCond_Always);
ImGui::BeginChild( ImGui::BeginChild(
"StatusBar", ImVec2(main_window_width_, status_bar_height_ + 1), "StatusBar", ImVec2(status_bar_width, status_bar_height),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImVec2 dot_pos = ImVec2 dot_pos = ImVec2(status_bar_width * 0.025f,
ImVec2(13, main_window_height_default_ - status_bar_height_ + 11.0f); io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT * 0.5f));
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddCircleFilled(dot_pos, 5.0f, draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.2f,
ImColor(signal_connected_ ? 0.0f : 1.0f, ImColor(signal_connected_ ? 0.0f : 1.0f,
signal_connected_ ? 1.0f : 0.0f, 0.0f), signal_connected_ ? 1.0f : 0.0f, 0.0f),
100); 100);
draw_list->AddCircle(dot_pos, 6.0f, ImColor(1.0f, 1.0f, 1.0f), 100); draw_list->AddCircle(dot_pos, status_bar_height * 0.25f,
ImColor(1.0f, 1.0f, 1.0f), 100);
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.6f);
draw_list->AddText( draw_list->AddText(
ImVec2(25, main_window_height_default_ - status_bar_height_ + 3.0f), ImVec2(status_bar_width * 0.045f,
io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT * 0.9f)),
ImColor(0.0f, 0.0f, 0.0f), ImColor(0.0f, 0.0f, 0.0f),
signal_connected_ signal_connected_
? localization::signal_connected[localization_language_index_].c_str() ? localization::signal_connected[localization_language_index_].c_str()

View File

@@ -1,110 +1,97 @@
#include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
#define BUTTON_PADDING 36.0f
#define NEW_VERSION_ICON_RENDER_TIME_INTERVAL 2000 #define NEW_VERSION_ICON_RENDER_TIME_INTERVAL 2000
namespace crossdesk { namespace crossdesk {
int Render::TitleBar(bool main_window) { int Render::TitleBar(bool main_window) {
ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); ImGuiIO& io = ImGui::GetIO();
float title_bar_width = title_bar_width_;
float title_bar_height = title_bar_height_;
float title_bar_height_padding = title_bar_height_;
float title_bar_button_width = title_bar_button_width_;
float title_bar_button_height = title_bar_button_height_;
if (main_window) {
title_bar_width = io.DisplaySize.x;
title_bar_height = io.DisplaySize.y * TITLE_BAR_HEIGHT;
title_bar_height_padding = io.DisplaySize.y * (TITLE_BAR_HEIGHT + 0.01f);
title_bar_button_width = io.DisplaySize.x * TITLE_BAR_BUTTON_WIDTH;
title_bar_button_height = io.DisplaySize.y * TITLE_BAR_BUTTON_HEIGHT;
title_bar_height_ = title_bar_height;
title_bar_button_width_ = title_bar_button_width;
title_bar_button_height_ = title_bar_button_height;
} else {
title_bar_width = io.DisplaySize.x;
title_bar_height = title_bar_button_height_;
title_bar_button_width = title_bar_button_width_;
title_bar_button_height = title_bar_button_height_;
}
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetWindowFontScale(0.8f); ImGui::BeginChild(main_window ? "MainTitleBar" : "StreamTitleBar",
ImGui::BeginChild( ImVec2(title_bar_width, title_bar_height_padding),
main_window ? "MainTitleBar" : "StreamTitleBar", ImGuiChildFlags_Border,
ImVec2(main_window ? main_window_width_ : stream_window_width_, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
title_bar_height_), ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGuiChildFlags_Border, ImGui::PopStyleVar();
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
// get draw list
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (ImGui::BeginMenuBar()) {
ImGui::SetCursorPosX( ImGui::SetCursorPos(
(main_window ? main_window_width_ : stream_window_width_) - ImVec2(title_bar_width - title_bar_button_width * 3, 0.0f));
(BUTTON_PADDING * 3 - 3)); if (main_window) {
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0, 0, 0, 0.1f)); float bar_pos_x = title_bar_width - title_bar_button_width * 3 +
ImGui::PushStyleColor(ImGuiCol_HeaderActive, title_bar_button_width * 0.33f;
float bar_pos_y = title_bar_button_height * 0.5f;
// draw menu icon
float menu_bar_line_size = title_bar_button_width * 0.33f;
draw_list->AddLine(
ImVec2(bar_pos_x, bar_pos_y - title_bar_button_height * 0.15f),
ImVec2(bar_pos_x + menu_bar_line_size,
bar_pos_y - title_bar_button_height * 0.15f),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(
ImVec2(bar_pos_x, bar_pos_y + title_bar_button_height * 0.15f),
ImVec2(bar_pos_x + menu_bar_line_size,
bar_pos_y + title_bar_button_height * 0.15f),
IM_COL32(0, 0, 0, 255));
std::string title_bar_menu_button = "##title_bar_menu"; // ICON_FA_BARS;
std::string title_bar_menu = "##title_bar_menu";
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (main_window) { if (ImGui::Button(
float bar_pos_x = ImGui::GetCursorPosX() + 6; title_bar_menu_button.c_str(),
float bar_pos_y = ImGui::GetCursorPosY() + 15; ImVec2(title_bar_button_width, title_bar_button_height))) {
std::string menu_button = " "; // ICON_FA_BARS; ImGui::OpenPopup(title_bar_menu.c_str());
if (ImGui::BeginMenu(menu_button.c_str())) { }
ImGui::SetWindowFontScale(0.5f); ImGui::PopStyleColor(3);
if (ImGui::MenuItem(
localization::settings[localization_language_index_].c_str())) {
show_settings_window_ = true;
}
show_new_version_icon_in_menu_ = false; if (ImGui::BeginPopup(title_bar_menu.c_str())) {
ImGui::SetWindowFontScale(0.6f);
std::string about_str = if (ImGui::MenuItem(
localization::about[localization_language_index_]; localization::settings[localization_language_index_].c_str())) {
if (update_available_) { show_settings_window_ = true;
auto now_time =
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
// every 2 seconds
if (now_time - new_version_icon_last_trigger_time_ >=
NEW_VERSION_ICON_RENDER_TIME_INTERVAL) {
show_new_version_icon_ = true;
new_version_icon_render_start_time_ = now_time;
new_version_icon_last_trigger_time_ = now_time;
}
// render for 1 second
if (show_new_version_icon_) {
about_str = about_str + " " + ICON_FA_TRIANGLE_EXCLAMATION;
if (now_time - new_version_icon_render_start_time_ >=
NEW_VERSION_ICON_RENDER_TIME_INTERVAL / 2) {
show_new_version_icon_ = false;
}
} else {
about_str = about_str + " ";
}
}
if (ImGui::MenuItem(about_str.c_str())) {
show_about_window_ = true;
}
if (update_available_ && ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::SetWindowFontScale(0.5f);
std::string new_version_available_str =
localization::new_version_available
[localization_language_index_] +
": " + latest_version_;
ImGui::Text("%s", new_version_available_str.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::EndTooltip();
}
ImGui::SetWindowFontScale(1.0f);
ImGui::EndMenu();
} else {
show_new_version_icon_in_menu_ = true;
} }
float menu_bar_line_size = 15.0f; show_new_version_icon_in_menu_ = false;
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y - 6),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y - 6),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y + 6),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y + 6),
IM_COL32(0, 0, 0, 255));
if (update_available_ && show_new_version_icon_in_menu_) { std::string about_str = localization::about[localization_language_index_];
if (update_available_) {
auto now_time = std::chrono::duration_cast<std::chrono::milliseconds>( auto now_time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch()) std::chrono::steady_clock::now().time_since_epoch())
.count(); .count();
@@ -119,133 +106,198 @@ int Render::TitleBar(bool main_window) {
// render for 1 second // render for 1 second
if (show_new_version_icon_) { if (show_new_version_icon_) {
ImGui::SetWindowFontScale(0.6f); about_str = about_str + " " + ICON_FA_TRIANGLE_EXCLAMATION;
ImGui::SetCursorPos(ImVec2(bar_pos_x + 10, bar_pos_y - 17));
ImGui::Text(ICON_FA_TRIANGLE_EXCLAMATION);
ImGui::SetWindowFontScale(1.0f);
if (now_time - new_version_icon_render_start_time_ >= if (now_time - new_version_icon_render_start_time_ >=
NEW_VERSION_ICON_RENDER_TIME_INTERVAL / 2) { NEW_VERSION_ICON_RENDER_TIME_INTERVAL / 2) {
show_new_version_icon_ = false; show_new_version_icon_ = false;
} }
} else {
about_str = about_str + " ";
} }
} }
{ if (ImGui::MenuItem(about_str.c_str())) {
SettingWindow(); show_about_window_ = true;
SelfHostedServerWindow(); }
AboutWindow();
if (update_available_ && ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::SetWindowFontScale(0.5f);
std::string new_version_available_str =
localization::new_version_available[localization_language_index_] +
": " + latest_version_;
ImGui::Text("%s", new_version_available_str.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::EndTooltip();
}
ImGui::EndPopup();
} else {
show_new_version_icon_in_menu_ = true;
}
if (update_available_ && show_new_version_icon_in_menu_) {
auto now_time = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count();
// every 2 seconds
if (now_time - new_version_icon_last_trigger_time_ >=
NEW_VERSION_ICON_RENDER_TIME_INTERVAL) {
show_new_version_icon_ = true;
new_version_icon_render_start_time_ = now_time;
new_version_icon_last_trigger_time_ = now_time;
}
// render for 1 second
if (show_new_version_icon_) {
ImGui::SetWindowFontScale(0.6f);
ImGui::SetCursorPos(
ImVec2(bar_pos_x + title_bar_button_width * 0.15f,
bar_pos_y - title_bar_button_width * 0.325f));
ImGui::Text(ICON_FA_TRIANGLE_EXCLAMATION);
ImGui::SetWindowFontScale(1.0f);
if (now_time - new_version_icon_render_start_time_ >=
NEW_VERSION_ICON_RENDER_TIME_INTERVAL / 2) {
show_new_version_icon_ = false;
}
} }
} }
ImGui::PopStyleColor(2); {
SettingWindow();
SelfHostedServerWindow();
AboutWindow();
}
} else {
ImGui::SetWindowFontScale(1.2f);
}
ImGui::SetCursorPos(ImVec2(
title_bar_width - title_bar_button_width * (main_window ? 2 : 3), 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
float minimize_pos_x = title_bar_width -
title_bar_button_width * (main_window ? 2 : 3) +
title_bar_button_width * 0.33f;
float minimize_pos_y = title_bar_button_height * 0.5f;
std::string window_minimize_button = "##minimize"; // ICON_FA_MINUS;
if (ImGui::Button(window_minimize_button.c_str(),
ImVec2(title_bar_button_width, title_bar_button_height))) {
SDL_MinimizeWindow(main_window ? main_window_ : stream_window_);
}
draw_list->AddLine(
ImVec2(minimize_pos_x, minimize_pos_y),
ImVec2(minimize_pos_x + title_bar_button_width * 0.33f, minimize_pos_y),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(3);
if (!main_window) {
ImGui::SetCursorPos(
ImVec2(title_bar_width - title_bar_button_width * 2, 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::SetCursorPosX(main_window
? (main_window_width_ - BUTTON_PADDING * 2)
: (stream_window_width_ - BUTTON_PADDING * 3));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
float minimize_pos_x = ImGui::GetCursorPosX() + 12; if (window_maximized_) {
float minimize_pos_y = ImGui::GetCursorPosY() + 15; float pos_x_top = title_bar_width - title_bar_button_width * 1.65f;
std::string window_minimize_button = "##minimize"; // ICON_FA_MINUS; float pos_y_top = title_bar_button_height * 0.36f;
if (ImGui::Button(window_minimize_button.c_str(), float pos_x_bottom = title_bar_width - title_bar_button_width * 1.6f;
ImVec2(BUTTON_PADDING, 30))) { float pos_y_bottom = title_bar_button_height * 0.28f;
SDL_MinimizeWindow(main_window ? main_window_ : stream_window_); std::string window_restore_button =
} "##restore"; // ICON_FA_WINDOW_RESTORE;
draw_list->AddLine(ImVec2(minimize_pos_x, minimize_pos_y), if (ImGui::Button(
ImVec2(minimize_pos_x + 12, minimize_pos_y), window_restore_button.c_str(),
IM_COL32(0, 0, 0, 255)); ImVec2(title_bar_button_width, title_bar_button_height))) {
ImGui::PopStyleColor(2); SDL_RestoreWindow(stream_window_);
window_maximized_ = false;
if (!main_window) {
ImGui::SetCursorPosX(stream_window_width_ - BUTTON_PADDING * 2);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (window_maximized_) {
float pos_x_top = ImGui::GetCursorPosX() + 11;
float pos_y_top = ImGui::GetCursorPosY() + 11;
float pos_x_bottom = ImGui::GetCursorPosX() + 13;
float pos_y_bottom = ImGui::GetCursorPosY() + 9;
std::string window_restore_button =
"##restore"; // ICON_FA_WINDOW_RESTORE;
if (ImGui::Button(window_restore_button.c_str(),
ImVec2(BUTTON_PADDING, 30))) {
SDL_RestoreWindow(stream_window_);
window_maximized_ = false;
}
draw_list->AddRect(ImVec2(pos_x_top, pos_y_top),
ImVec2(pos_x_top + 12, pos_y_top + 12),
IM_COL32(0, 0, 0, 255));
draw_list->AddRect(ImVec2(pos_x_bottom, pos_y_bottom),
ImVec2(pos_x_bottom + 12, pos_y_bottom + 12),
IM_COL32(0, 0, 0, 255));
draw_list->AddRectFilled(ImVec2(pos_x_top + 1, pos_y_top + 1),
ImVec2(pos_x_top + 11, pos_y_top + 11),
IM_COL32(255, 255, 255, 255));
} else {
float maximize_pos_x = ImGui::GetCursorPosX() + 12;
float maximize_pos_y = ImGui::GetCursorPosY() + 10;
std::string window_maximize_button =
"##maximize"; // ICON_FA_SQUARE_FULL;
if (ImGui::Button(window_maximize_button.c_str(),
ImVec2(BUTTON_PADDING, 30))) {
SDL_MaximizeWindow(stream_window_);
window_maximized_ = !window_maximized_;
}
draw_list->AddRect(ImVec2(maximize_pos_x, maximize_pos_y),
ImVec2(maximize_pos_x + 12, maximize_pos_y + 12),
IM_COL32(0, 0, 0, 255));
} }
ImGui::PopStyleColor(2); draw_list->AddRect(ImVec2(pos_x_top, pos_y_top),
} ImVec2(pos_x_top + title_bar_button_height * 0.33f,
pos_y_top + title_bar_button_height * 0.33f),
ImGui::SetCursorPosX( IM_COL32(0, 0, 0, 255));
(main_window ? main_window_width_ : stream_window_width_) - draw_list->AddRect(ImVec2(pos_x_bottom, pos_y_bottom),
BUTTON_PADDING); ImVec2(pos_x_bottom + title_bar_button_height * 0.33f,
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f)); pos_y_bottom + title_bar_button_height * 0.33f),
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f)); IM_COL32(0, 0, 0, 255));
if (ImGui::IsItemHovered()) {
float xmark_pos_x = ImGui::GetCursorPosX() + 18; draw_list->AddRectFilled(
float xmark_pos_y = ImGui::GetCursorPosY() + 16; ImVec2(pos_x_top + title_bar_button_height * 0.02f,
float xmark_size = 12.0f; pos_y_top + title_bar_button_height * 0.01f),
std::string close_button = "##xmark"; // ICON_FA_XMARK; ImVec2(pos_x_top + title_bar_button_height * 0.32f,
if (ImGui::Button(close_button.c_str(), ImVec2(BUTTON_PADDING, 30))) { pos_y_top + title_bar_button_height * 0.31f),
#if _WIN32 IM_COL32(229, 229, 229, 255));
if (enable_minimize_to_tray_) {
tray_->MinimizeToTray();
} else { } else {
#endif draw_list->AddRectFilled(
SDL_Event event; ImVec2(pos_x_top + title_bar_button_height * 0.02f,
event.type = SDL_EVENT_QUIT; pos_y_top + title_bar_button_height * 0.01f),
SDL_PushEvent(&event); ImVec2(pos_x_top + title_bar_button_height * 0.32f,
#if _WIN32 pos_y_top + title_bar_button_height * 0.31f),
IM_COL32(255, 255, 255, 255));
} }
#endif } else {
float maximize_pos_x = title_bar_width - title_bar_button_width * 1.5f -
title_bar_button_height * 0.165f;
float maximize_pos_y = title_bar_button_height * 0.33f;
std::string window_maximize_button =
"##maximize"; // ICON_FA_SQUARE_FULL;
if (ImGui::Button(
window_maximize_button.c_str(),
ImVec2(title_bar_button_width, title_bar_button_height))) {
SDL_MaximizeWindow(stream_window_);
window_maximized_ = !window_maximized_;
}
draw_list->AddRect(
ImVec2(maximize_pos_x, maximize_pos_y),
ImVec2(maximize_pos_x + title_bar_button_height * 0.33f,
maximize_pos_y + title_bar_button_height * 0.33f),
IM_COL32(0, 0, 0, 255));
} }
draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f, ImGui::PopStyleColor(3);
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x + xmark_size / 2 - 1.5f,
xmark_pos_y + xmark_size / 2 - 0.5f),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(ImVec2(xmark_pos_x + xmark_size / 2 - 1.75f,
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x - xmark_size / 2,
xmark_pos_y + xmark_size / 2 - 1.0f),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(2);
ImGui::PopStyleColor();
} }
ImGui::EndMenuBar(); float xmark_button_pos_x = title_bar_width - title_bar_button_width;
ImGui::SetCursorPos(ImVec2(xmark_button_pos_x, 0.0f));
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f));
float xmark_pos_x = xmark_button_pos_x + title_bar_button_width * 0.5f;
float xmark_pos_y = title_bar_button_height * 0.5f;
float xmark_size = title_bar_button_width * 0.33f;
std::string close_button = "##xmark"; // ICON_FA_XMARK;
if (ImGui::Button(close_button.c_str(),
ImVec2(title_bar_button_width, title_bar_button_height))) {
#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
}
draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f,
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x + xmark_size / 2 - 1.5f,
xmark_pos_y + xmark_size / 2 - 0.5f),
IM_COL32(0, 0, 0, 255));
draw_list->AddLine(
ImVec2(xmark_pos_x + xmark_size / 2 - 1.75f,
xmark_pos_y - xmark_size / 2 + 0.75f),
ImVec2(xmark_pos_x - xmark_size / 2, xmark_pos_y + xmark_size / 2 - 1.0f),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(3);
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleColor();
return 0; return 0;
} }
} // namespace crossdesk } // namespace crossdesk

View File

@@ -37,17 +37,18 @@ void Render::Hyperlink(const std::string& label, const std::string& url,
int Render::AboutWindow() { int Render::AboutWindow() {
if (show_about_window_) { if (show_about_window_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); float about_window_width = title_bar_button_width_ * 7.5f;
float about_window_height = latest_version_.empty() float about_window_height = latest_version_.empty()
? about_window_height_ ? title_bar_button_width_ * 4.0f
: about_window_height_ + 20.0f; : title_bar_button_width_ * 4.6f;
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2( ImGui::SetNextWindowPos(ImVec2(
(viewport->WorkSize.x - viewport->WorkPos.x - about_window_width_) / 2, (viewport->WorkSize.x - viewport->WorkPos.x - about_window_width) / 2,
(viewport->WorkSize.y - viewport->WorkPos.y - about_window_height) / (viewport->WorkSize.y - viewport->WorkPos.y - about_window_height) /
2)); 2));
ImGui::SetNextWindowSize(ImVec2(about_window_width_, about_window_height)); ImGui::SetNextWindowSize(ImVec2(about_window_width, about_window_height));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
@@ -70,7 +71,7 @@ int Render::AboutWindow() {
std::string text = localization::version[localization_language_index_] + std::string text = localization::version[localization_language_index_] +
": CrossDesk " + version; ": CrossDesk " + version;
ImGui::SetCursorPosX(about_window_width_ * 0.1f); ImGui::SetCursorPosX(about_window_width * 0.1f);
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
if (update_available_) { if (update_available_) {
@@ -79,19 +80,19 @@ int Render::AboutWindow() {
": " + latest_version_; ": " + latest_version_;
std::string access_website = std::string access_website =
localization::access_website[localization_language_index_]; localization::access_website[localization_language_index_];
Hyperlink(latest_version, "https://crossdesk.cn", about_window_width_); Hyperlink(latest_version, "https://crossdesk.cn", about_window_width);
} }
ImGui::Text(""); ImGui::Text("");
std::string copyright_text = "© 2025 by JUNKUN DI. All rights reserved."; std::string copyright_text = "© 2025 by JUNKUN DI. All rights reserved.";
std::string license_text = "Licensed under GNU LGPL v3."; std::string license_text = "Licensed under GNU LGPL v3.";
ImGui::SetCursorPosX(about_window_width_ * 0.1f); ImGui::SetCursorPosX(about_window_width * 0.1f);
ImGui::Text("%s", copyright_text.c_str()); ImGui::Text("%s", copyright_text.c_str());
ImGui::SetCursorPosX(about_window_width_ * 0.1f); ImGui::SetCursorPosX(about_window_width * 0.1f);
ImGui::Text("%s", license_text.c_str()); ImGui::Text("%s", license_text.c_str());
ImGui::SetCursorPosX(about_window_width_ * 0.42f); ImGui::SetCursorPosX(about_window_width * 0.445f);
ImGui::SetCursorPosY(about_window_height * 0.75f); ImGui::SetCursorPosY(about_window_height * 0.75f);
// OK // OK
if (ImGui::Button(localization::ok[localization_language_index_].c_str())) { if (ImGui::Button(localization::ok[localization_language_index_].c_str())) {

View File

@@ -7,42 +7,39 @@ namespace crossdesk {
bool Render::ConnectionStatusWindow( bool Render::ConnectionStatusWindow(
std::shared_ptr<SubStreamWindowProperties>& props) { std::shared_ptr<SubStreamWindowProperties>& props) {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGuiIO& io = ImGui::GetIO();
bool ret_flag = false; bool ret_flag = false;
ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x -
connection_status_window_width_) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
connection_status_window_height_) /
2));
ImGui::SetNextWindowSize(ImVec2(connection_status_window_width_, ImGui::SetNextWindowPos(
connection_status_window_height_)); ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.33f, io.DisplaySize.y * 0.33f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::Begin("ConnectionStatusWindow", nullptr, ImGui::Begin("ConnectionStatusWindow", nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings); ImGuiWindowFlags_NoSavedSettings);
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
auto connection_status_window_width = ImGui::GetWindowSize().x;
auto connection_status_window_height = ImGui::GetWindowSize().y;
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
std::string text; std::string text;
if (ConnectionStatus::Connecting == props->connection_status_) { if (ConnectionStatus::Connecting == props->connection_status_) {
text = localization::p2p_connecting[localization_language_index_]; text = localization::p2p_connecting[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
} else if (ConnectionStatus::Connected == props->connection_status_) { } else if (ConnectionStatus::Connected == props->connection_status_) {
text = localization::p2p_connected[localization_language_index_]; text = localization::p2p_connected[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) || if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter) ||
@@ -51,8 +48,8 @@ bool Render::ConnectionStatusWindow(
} }
} else if (ConnectionStatus::Disconnected == props->connection_status_) { } else if (ConnectionStatus::Disconnected == props->connection_status_) {
text = localization::p2p_disconnected[localization_language_index_]; text = localization::p2p_disconnected[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) || if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter) ||
@@ -61,8 +58,8 @@ bool Render::ConnectionStatusWindow(
} }
} else if (ConnectionStatus::Failed == props->connection_status_) { } else if (ConnectionStatus::Failed == props->connection_status_) {
text = localization::p2p_failed[localization_language_index_]; text = localization::p2p_failed[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) || if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter) ||
@@ -71,8 +68,8 @@ bool Render::ConnectionStatusWindow(
} }
} else if (ConnectionStatus::Closed == props->connection_status_) { } else if (ConnectionStatus::Closed == props->connection_status_) {
text = localization::p2p_closed[localization_language_index_]; text = localization::p2p_closed[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) || if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter) ||
@@ -87,11 +84,9 @@ bool Render::ConnectionStatusWindow(
text = localization::reinput_password[localization_language_index_]; text = localization::reinput_password[localization_language_index_];
} }
auto window_width = ImGui::GetWindowSize().x; ImGui::SetCursorPosX(connection_status_window_width * 0.336f);
auto window_height = ImGui::GetWindowSize().y; ImGui::SetCursorPosY(connection_status_window_height * 0.4f);
ImGui::SetCursorPosX((window_width - IPUT_WINDOW_WIDTH / 2) * 0.5f); ImGui::SetNextItemWidth(connection_status_window_width * 0.33f);
ImGui::SetCursorPosY(window_height * 0.4f);
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH / 2);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
@@ -109,15 +104,16 @@ bool Render::ConnectionStatusWindow(
ImVec2 text_size = ImGui::CalcTextSize( ImVec2 text_size = ImGui::CalcTextSize(
localization::remember_password[localization_language_index_] localization::remember_password[localization_language_index_]
.c_str()); .c_str());
ImGui::SetCursorPosX((window_width - text_size.x) * 0.5f - 13.0f); ImGui::SetCursorPosX((connection_status_window_width - text_size.x) *
0.45f);
ImGui::Checkbox( ImGui::Checkbox(
localization::remember_password[localization_language_index_].c_str(), localization::remember_password[localization_language_index_].c_str(),
&(props->remember_password_)); &(props->remember_password_));
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::SetCursorPosX(window_width * 0.315f); ImGui::SetCursorPosX(connection_status_window_width * 0.325f);
ImGui::SetCursorPosY(window_height * 0.75f); ImGui::SetCursorPosY(connection_status_window_height * 0.75f);
// ok // ok
if (ImGui::Button( if (ImGui::Button(
localization::ok[localization_language_index_].c_str()) || localization::ok[localization_language_index_].c_str()) ||
@@ -140,14 +136,14 @@ bool Render::ConnectionStatusWindow(
} }
} else if (password_validating_) { } else if (password_validating_) {
text = localization::validate_password[localization_language_index_]; text = localization::validate_password[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
} }
} else if (ConnectionStatus::NoSuchTransmissionId == } else if (ConnectionStatus::NoSuchTransmissionId ==
props->connection_status_) { props->connection_status_) {
text = localization::no_such_id[localization_language_index_]; text = localization::no_such_id[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7); ImGui::SetCursorPosX(connection_status_window_width * 0.43f);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3); ImGui::SetCursorPosY(connection_status_window_height * 0.67f);
// ok // ok
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) || if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter)) { ImGui::IsKeyPressed(ImGuiKey_Enter)) {
@@ -158,11 +154,9 @@ bool Render::ConnectionStatusWindow(
} }
} }
auto window_width = ImGui::GetWindowSize().x;
auto window_height = ImGui::GetWindowSize().y;
auto text_width = ImGui::CalcTextSize(text.c_str()).x; auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((window_width - text_width) * 0.5f); ImGui::SetCursorPosX((connection_status_window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.2f); ImGui::SetCursorPosY(connection_status_window_height * 0.2f);
ImGui::Text("%s", text.c_str()); ImGui::Text("%s", text.c_str());
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);

View File

@@ -53,11 +53,11 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
ImVec2(props->control_window_width_, props->control_window_height_), ImVec2(props->control_window_width_, props->control_window_height_),
ImGuiCond_Always); ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_ + 1), ImGuiCond_Once); ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Once);
float pos_x = 0; float pos_x = 0;
float pos_y = 0; float pos_y = 0;
float y_boundary = fullscreen_button_pressed_ ? 0 : (title_bar_height_ + 1); float y_boundary = fullscreen_button_pressed_ ? 0 : title_bar_height_;
if (props->reset_control_bar_pos_) { if (props->reset_control_bar_pos_) {
float new_cursor_pos_x = 0; float new_cursor_pos_x = 0;
@@ -94,7 +94,7 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
} else if (!props->reset_control_bar_pos_ && } else if (!props->reset_control_bar_pos_ &&
ImGui::IsMouseReleased(ImGuiMouseButton_Left) || ImGui::IsMouseReleased(ImGuiMouseButton_Left) ||
props->control_window_width_is_changing_) { props->control_window_width_is_changing_) {
if (props->control_window_pos_.x <= stream_window_width_ / 2) { if (props->control_window_pos_.x <= stream_window_width_ * 0.5f) {
if (props->control_window_pos_.y + props->control_window_height_ > if (props->control_window_pos_.y + props->control_window_height_ >
stream_window_height_) { stream_window_height_) {
pos_y = stream_window_height_ - props->control_window_height_; pos_y = stream_window_height_ - props->control_window_height_;
@@ -118,18 +118,16 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
} }
} }
props->is_control_bar_in_left_ = true; props->is_control_bar_in_left_ = true;
} else if (props->control_window_pos_.x > stream_window_width_ / 2) { } else if (props->control_window_pos_.x > stream_window_width_ * 0.5f) {
pos_x = 0; pos_x = 0;
pos_y = pos_y =
(props->control_window_pos_.y >= y_boundary && (props->control_window_pos_.y >= y_boundary &&
props->control_window_pos_.y <= props->control_window_pos_.y <=
stream_window_height_ - props->control_window_height_) stream_window_height_ - props->control_window_height_)
? props->control_window_pos_.y ? props->control_window_pos_.y
: (props->control_window_pos_.y < (fullscreen_button_pressed_ : (props->control_window_pos_.y <
? 0 (fullscreen_button_pressed_ ? 0 : title_bar_height_)
: (title_bar_height_ + 1)) ? (fullscreen_button_pressed_ ? 0 : title_bar_height_)
? (fullscreen_button_pressed_ ? 0
: (title_bar_height_ + 1))
: (stream_window_height_ - props->control_window_height_)); : (stream_window_height_ - props->control_window_height_));
if (props->control_bar_expand_) { if (props->control_bar_expand_) {
@@ -202,15 +200,13 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
: props->control_window_pos_.x, : props->control_window_pos_.x,
props->control_window_pos_.y), props->control_window_pos_.y),
ImGuiCond_Always); ImGuiCond_Always);
ImGui::SetWindowFontScale(0.5f);
std::string control_child_window_title = std::string control_child_window_title =
props->remote_id_ + "ControlChildWindow"; props->remote_id_ + "ControlChildWindow";
ImGui::BeginChild( ImGui::BeginChild(control_child_window_title.c_str(),
control_child_window_title.c_str(), ImVec2(props->control_window_width_ * 2.0f,
ImVec2(props->control_window_width_ * 2, props->control_window_height_), props->control_window_height_),
ImGuiChildFlags_Border, ImGuiWindowFlags_NoDecoration); ImGuiChildFlags_Border, ImGuiWindowFlags_NoDecoration);
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ControlBar(props); ControlBar(props);

View File

@@ -6,31 +6,38 @@
namespace crossdesk { namespace crossdesk {
int Render::SettingWindow() { int Render::SettingWindow() {
ImGuiIO& io = ImGui::GetIO();
if (show_settings_window_) { if (show_settings_window_) {
if (settings_window_pos_reset_) { if (settings_window_pos_reset_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); const ImGuiViewport* viewport = ImGui::GetMainViewport();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
!defined(__arm__) && USE_CUDA) || \
defined(__APPLE__))
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.07f));
SETTINGS_WINDOW_WIDTH_CN) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
SETTINGS_WINDOW_HEIGHT_CN) /
2));
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(SETTINGS_WINDOW_WIDTH_CN, SETTINGS_WINDOW_HEIGHT_CN)); ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.85f));
#else
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.1f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.8f));
#endif
} else { } else {
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
!defined(__arm__) && USE_CUDA) || \
defined(__APPLE__))
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.07f));
SETTINGS_WINDOW_WIDTH_EN) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
SETTINGS_WINDOW_HEIGHT_EN) /
2));
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(SETTINGS_WINDOW_WIDTH_EN, SETTINGS_WINDOW_HEIGHT_EN)); ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.85f));
#else
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.1f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.8f));
#endif
} }
settings_window_pos_reset_ = false; settings_window_pos_reset_ = false;
@@ -38,10 +45,9 @@ int Render::SettingWindow() {
// Settings // Settings
{ {
static int settings_items_padding = 30; static int settings_items_padding = title_bar_button_width_ * 0.75f;
int settings_items_offset = 0; int settings_items_offset = 0;
ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
@@ -50,7 +56,6 @@ int Render::SettingWindow() {
nullptr, nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoSavedSettings); ImGuiWindowFlags_NoSavedSettings);
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
{ {
@@ -59,19 +64,29 @@ int Render::SettingWindow() {
localization::language_en[localization_language_index_].c_str()}; localization::language_en[localization_language_index_].c_str()};
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", localization::language[localization_language_index_].c_str()); "%s", localization::language[localization_language_index_].c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(LANGUAGE_SELECT_WINDOW_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else { } else {
ImGui::SetCursorPosX(LANGUAGE_SELECT_WINDOW_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
ImGui::Combo("##language", &language_button_value_, language_items, ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
IM_ARRAYSIZE(language_items)); if (ImGui::BeginCombo("##language",
language_items[language_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(language_items); i++) {
bool selected = (i == language_button_value_);
if (ImGui::Selectable(language_items[i], selected))
language_button_value_ = i;
}
ImGui::EndCombo();
}
} }
ImGui::Separator(); ImGui::Separator();
@@ -90,21 +105,31 @@ int Render::SettingWindow() {
.c_str()}; .c_str()};
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::video_quality[localization_language_index_].c_str()); localization::video_quality[localization_language_index_].c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else { } else {
ImGui::SetCursorPosX(VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
ImGui::Combo("##video_quality", &video_quality_button_value_, ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
video_quality_items, IM_ARRAYSIZE(video_quality_items)); if (ImGui::BeginCombo(
"##video_quality",
video_quality_items[video_quality_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_quality_items); i++) {
bool selected = (i == video_quality_button_value_);
if (ImGui::Selectable(video_quality_items[i], selected))
video_quality_button_value_ = i;
}
ImGui::EndCombo();
}
} }
ImGui::Separator(); ImGui::Separator();
@@ -113,22 +138,31 @@ int Render::SettingWindow() {
const char* video_frame_rate_items[] = {"30 fps", "60 fps"}; const char* video_frame_rate_items[] = {"30 fps", "60 fps"};
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", ImGui::Text("%s",
localization::video_frame_rate[localization_language_index_] localization::video_frame_rate[localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else { } else {
ImGui::SetCursorPosX(VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
ImGui::Combo("##video_frame_rate", &video_frame_rate_button_value_, ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
video_frame_rate_items, if (ImGui::BeginCombo(
IM_ARRAYSIZE(video_frame_rate_items)); "##video_frame_rate",
video_frame_rate_items[video_frame_rate_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_frame_rate_items); i++) {
bool selected = (i == video_frame_rate_button_value_);
if (ImGui::Selectable(video_frame_rate_items[i], selected))
video_frame_rate_button_value_ = i;
}
ImGui::EndCombo();
}
} }
ImGui::Separator(); ImGui::Separator();
@@ -139,41 +173,53 @@ int Render::SettingWindow() {
localization::av1[localization_language_index_].c_str()}; localization::av1[localization_language_index_].c_str()};
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::video_encode_format[localization_language_index_] localization::video_encode_format[localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else { } else {
ImGui::SetCursorPosX(VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
ImGui::Combo( ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
"##video_encode_format", &video_encode_format_button_value_, if (ImGui::BeginCombo(
video_encode_format_items, IM_ARRAYSIZE(video_encode_format_items)); "##video_encode_format",
video_encode_format_items[video_encode_format_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_encode_format_items); i++) {
bool selected = (i == video_encode_format_button_value_);
if (ImGui::Selectable(video_encode_format_items[i], selected))
video_encode_format_button_value_ = i;
}
ImGui::EndCombo();
}
} }
#if USE_CUDA && !defined(__aarch64__) && !defined(__arm__) #if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
!defined(__arm__) && USE_CUDA) || \
defined(__APPLE__))
ImGui::Separator(); ImGui::Separator();
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", localization::enable_hardware_video_codec ImGui::Text("%s", localization::enable_hardware_video_codec
[localization_language_index_] [localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_hardware_video_codec", ImGui::Checkbox("##enable_hardware_video_codec",
&enable_hardware_video_codec_); &enable_hardware_video_codec_);
} }
@@ -183,17 +229,18 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::enable_turn[localization_language_index_].c_str()); localization::enable_turn[localization_language_index_].c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_TURN_CHECKBOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_TURN_CHECKBOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_turn", &enable_turn_); ImGui::Checkbox("##enable_turn", &enable_turn_);
} }
@@ -201,17 +248,18 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::enable_srtp[localization_language_index_].c_str()); localization::enable_srtp[localization_language_index_].c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_SRTP_CHECKBOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_SRTP_CHECKBOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_srtp", &enable_srtp_); ImGui::Checkbox("##enable_srtp", &enable_srtp_);
} }
@@ -220,19 +268,19 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 1); ImGui::SetCursorPosY(settings_items_offset + 1);
ImGui::AlignTextToFramePadding();
if (ImGui::Button(localization::self_hosted_server_config if (ImGui::Button(localization::self_hosted_server_config
[localization_language_index_] [localization_language_index_]
.c_str())) { .c_str())) {
show_self_hosted_server_config_window_ = true; show_self_hosted_server_config_window_ = true;
} }
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_self_hosted", &enable_self_hosted_); ImGui::Checkbox("##enable_self_hosted", &enable_self_hosted_);
} }
@@ -240,18 +288,18 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", ImGui::Text("%s",
localization::enable_autostart[localization_language_index_] localization::enable_autostart[localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_AUTOSTART_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_AUTOSTART_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_autostart_", &enable_autostart_); ImGui::Checkbox("##enable_autostart_", &enable_autostart_);
} }
@@ -259,18 +307,18 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::enable_daemon[localization_language_index_].c_str()); localization::enable_daemon[localization_language_index_].c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_DAEMON_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_DAEMON_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_daemon_", &enable_daemon_); ImGui::Checkbox("##enable_daemon_", &enable_daemon_);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
@@ -287,18 +335,18 @@ int Render::SettingWindow() {
{ {
settings_items_offset += settings_items_padding; settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4); ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", ImGui::Text("%s",
localization::minimize_to_tray[localization_language_index_] localization::minimize_to_tray[localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else { } else {
ImGui::SetCursorPosX(ENABLE_MINIZE_TO_TRAY_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
} }
ImGui::SetCursorPosY(settings_items_offset);
ImGui::Checkbox("##enable_minimize_to_tray_", ImGui::Checkbox("##enable_minimize_to_tray_",
&enable_minimize_to_tray_); &enable_minimize_to_tray_);
} }
@@ -308,13 +356,15 @@ int Render::SettingWindow() {
} }
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SETTINGS_OK_BUTTON_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 1.59f);
} else { } else {
ImGui::SetCursorPosX(SETTINGS_OK_BUTTON_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.22f);
} }
settings_items_offset += settings_items_padding + 10; settings_items_offset +=
settings_items_padding + title_bar_button_width_ * 0.3f;
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetCursorPosY(settings_items_offset);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
// OK // OK
@@ -468,12 +518,10 @@ int Render::SettingWindow() {
settings_window_pos_reset_ = true; settings_window_pos_reset_ = true;
} }
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
ImGui::End(); ImGui::End();
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::SetWindowFontScale(1.0f);
} }
} }

View File

@@ -1,3 +1,4 @@
#include "layout_relative.h"
#include "localization.h" #include "localization.h"
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
@@ -5,25 +6,30 @@
namespace crossdesk { namespace crossdesk {
int Render::MainWindow() { int Render::MainWindow() {
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Always); ImGuiIO& io = ImGui::GetIO();
float local_remote_window_width = io.DisplaySize.x;
float local_remote_window_height =
io.DisplaySize.y * (0.56f - TITLE_BAR_HEIGHT);
ImGui::SetNextWindowPos(ImVec2(0.0f, io.DisplaySize.y * (TITLE_BAR_HEIGHT)),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild("DeskWindow", ImGui::BeginChild(
ImVec2(main_window_width_default_, local_window_height_), "DeskWindow",
ImGuiChildFlags_Border, ImVec2(local_remote_window_width, local_remote_window_height),
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiChildFlags_Border,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
LocalWindow(); LocalWindow();
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine( draw_list->AddLine(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.1f),
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 15.0f), ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.53f),
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 225.0f), IM_COL32(0, 0, 0, 122), 1.0f);
IM_COL32(0, 0, 0, 122), 1.0f);
RemoteWindow(); RemoteWindow();
ImGui::EndChild(); ImGui::EndChild();
@@ -32,7 +38,7 @@ int Render::MainWindow() {
StatusBar(); StatusBar();
if (show_connection_status_window_) { if (show_connection_status_window_) {
std::unique_lock lock(client_properties_mutex_); // std::unique_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin(); for (auto it = client_properties_.begin();
it != client_properties_.end();) { it != client_properties_.end();) {
auto& props = it->second; auto& props = it->second;

View File

@@ -138,8 +138,8 @@ int Render::RequestPermissionWindow() {
ImGui::SetWindowFontScale(0.3f); ImGui::SetWindowFontScale(0.3f);
// use system font // use system font
if (system_chinese_font_ != nullptr) { if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PushFont(system_chinese_font_); ImGui::PushFont(main_windows_system_chinese_font_);
} }
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() + 5.0f); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() + 5.0f);
@@ -191,7 +191,7 @@ int Render::RequestPermissionWindow() {
ImGui::SetWindowFontScale(0.45f); ImGui::SetWindowFontScale(0.45f);
// pop system font // pop system font
if (system_chinese_font_ != nullptr) { if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PopFont(); ImGui::PopFont();
} }

View File

@@ -54,12 +54,13 @@ int Render::ShowSimpleFileBrowser() {
if (show_file_browser_) { if (show_file_browser_) {
ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false); ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
float fixed_width = 130.0f; float fixed_width = title_bar_button_width_ * 3.8f;
ImGui::SetNextItemWidth(fixed_width); ImGui::SetNextItemWidth(fixed_width);
ImGui::SetNextWindowSizeConstraints(ImVec2(fixed_width, 0), ImGui::SetNextWindowSizeConstraints(ImVec2(fixed_width, 0),
ImVec2(fixed_width, 100.0f)); ImVec2(fixed_width, 100.0f));
if (ImGui::BeginCombo("##select_a_file", display_text.c_str(), 0)) { if (ImGui::BeginCombo("##select_a_file", display_text.c_str(), 0)) {
ImGui::SetWindowFontScale(0.5f);
bool file_selected = false; bool file_selected = false;
auto roots = GetRootEntries(); auto roots = GetRootEntries();
@@ -120,33 +121,19 @@ int Render::ShowSimpleFileBrowser() {
} }
int Render::SelfHostedServerWindow() { int Render::SelfHostedServerWindow() {
ImGuiIO& io = ImGui::GetIO();
if (show_self_hosted_server_config_window_) { if (show_self_hosted_server_config_window_) {
if (self_hosted_server_config_window_pos_reset_) { if (self_hosted_server_config_window_pos_reset_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.298f, io.DisplaySize.y * 0.25f));
SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN) /
2));
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN, ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.41f));
SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN));
} else { } else {
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - ImVec2(io.DisplaySize.x * 0.27f, io.DisplaySize.y * 0.3f));
SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN) /
2));
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN, ImVec2(io.DisplaySize.x * 0.465f, io.DisplaySize.y * 0.41f));
SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN));
} }
self_hosted_server_config_window_pos_reset_ = false; self_hosted_server_config_window_pos_reset_ = false;
@@ -154,9 +141,6 @@ int Render::SelfHostedServerWindow() {
// Settings // Settings
{ {
static int settings_items_padding = 30;
int settings_items_offset = 0;
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
@@ -172,18 +156,17 @@ int Render::SelfHostedServerWindow() {
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
{ {
settings_items_offset += settings_items_padding; ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s", localization::self_hosted_server_address ImGui::Text("%s", localization::self_hosted_server_address
[localization_language_index_] [localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.5f);
} else { } else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
} }
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##signal_server_ip_self_", signal_server_ip_self_, ImGui::InputText("##signal_server_ip_self_", signal_server_ip_self_,
IM_ARRAYSIZE(signal_server_ip_self_), IM_ARRAYSIZE(signal_server_ip_self_),
@@ -193,20 +176,18 @@ int Render::SelfHostedServerWindow() {
ImGui::Separator(); ImGui::Separator();
{ {
settings_items_offset += settings_items_padding; ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::self_hosted_server_port[localization_language_index_] localization::self_hosted_server_port[localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.5f);
} else { } else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
} }
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##signal_server_port_self_", signal_server_port_self_, ImGui::InputText("##signal_server_port_self_", signal_server_port_self_,
IM_ARRAYSIZE(signal_server_port_self_)); IM_ARRAYSIZE(signal_server_port_self_));
@@ -215,19 +196,17 @@ int Render::SelfHostedServerWindow() {
ImGui::Separator(); ImGui::Separator();
{ {
settings_items_offset += settings_items_padding; ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s", localization::self_hosted_server_coturn_server_port ImGui::Text("%s", localization::self_hosted_server_coturn_server_port
[localization_language_index_] [localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.5f);
} else { } else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
} }
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ImGui::InputText("##coturn_server_port_self_", coturn_server_port_self_, ImGui::InputText("##coturn_server_port_self_", coturn_server_port_self_,
IM_ARRAYSIZE(coturn_server_port_self_)); IM_ARRAYSIZE(coturn_server_port_self_));
@@ -236,19 +215,17 @@ int Render::SelfHostedServerWindow() {
ImGui::Separator(); ImGui::Separator();
{ {
settings_items_offset += settings_items_padding; ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosY(settings_items_offset + 2);
ImGui::Text("%s", localization::self_hosted_server_certificate_path ImGui::Text("%s", localization::self_hosted_server_certificate_path
[localization_language_index_] [localization_language_index_]
.c_str()); .c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.5f);
} else { } else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 3.43f);
} }
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetNextItemWidth(title_bar_button_width_ * 3.8f);
ImGui::SetNextItemWidth(SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH);
ShowSimpleFileBrowser(); ShowSimpleFileBrowser();
} }
@@ -257,14 +234,14 @@ int Render::SelfHostedServerWindow() {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
ImGui::Dummy(ImVec2(0.0f, title_bar_button_width_ * 0.25f));
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.32f);
} else { } else {
ImGui::SetCursorPosX(SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN); ImGui::SetCursorPosX(title_bar_button_width_ * 2.7f);
} }
settings_items_offset += settings_items_padding + 10;
ImGui::SetCursorPosY(settings_items_offset);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
// OK // OK
@@ -298,16 +275,27 @@ int Render::SelfHostedServerWindow() {
localization::cancel[localization_language_index_].c_str())) { localization::cancel[localization_language_index_].c_str())) {
show_self_hosted_server_config_window_ = false; show_self_hosted_server_config_window_ = false;
self_hosted_server_config_window_pos_reset_ = true; self_hosted_server_config_window_pos_reset_ = true;
strncpy(signal_server_ip_self_,
strncpy(signal_server_ip_self_, signal_server_ip_, config_center_->GetSignalServerHost().c_str(),
sizeof(signal_server_ip_self_) - 1); sizeof(signal_server_ip_self_) - 1);
signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0'; signal_server_ip_self_[sizeof(signal_server_ip_self_) - 1] = '\0';
strncpy(signal_server_port_self_, signal_server_port_, int signal_port = config_center_->GetSignalServerPort();
sizeof(signal_server_port_self_) - 1); if (signal_port > 0) {
signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0'; strncpy(signal_server_port_self_, std::to_string(signal_port).c_str(),
config_center_->SetServerHost(signal_server_ip_self_); sizeof(signal_server_port_self_) - 1);
config_center_->SetServerPort(atoi(signal_server_port_self_)); signal_server_port_self_[sizeof(signal_server_port_self_) - 1] = '\0';
tls_cert_path_self_.clear(); } else {
signal_server_port_self_[0] = '\0';
}
int coturn_port = config_center_->GetCoturnServerPort();
if (coturn_port > 0) {
strncpy(coturn_server_port_self_, std::to_string(coturn_port).c_str(),
sizeof(coturn_server_port_self_) - 1);
coturn_server_port_self_[sizeof(coturn_server_port_self_) - 1] = '\0';
} else {
coturn_server_port_self_[0] = '\0';
}
tls_cert_path_self_ = config_center_->GetCertFilePath();
} }
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);

View File

@@ -32,7 +32,7 @@ void Render::DrawConnectionStatusText(
} }
void Render::CloseTab(decltype(client_properties_)::iterator& it) { void Render::CloseTab(decltype(client_properties_)::iterator& it) {
std::unique_lock lock(client_properties_mutex_); // std::unique_lock lock(client_properties_mutex_);
if (it != client_properties_.end()) { if (it != client_properties_.end()) {
CleanupPeer(it->second); CleanupPeer(it->second);
it = client_properties_.erase(it); it = client_properties_.erase(it);
@@ -53,21 +53,28 @@ int Render::StreamWindow() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("VideoBg", nullptr, bool video_bg_opened = ImGui::Begin(
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | "VideoBg", nullptr,
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoDocking); ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
if (!video_bg_opened) {
return 0;
}
ImGuiWindowFlags stream_window_flag = ImGuiWindowFlags stream_window_flag =
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoMove; ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoMove;
if (!fullscreen_button_pressed_) { if (!fullscreen_button_pressed_) {
ImGui::SetNextWindowPos(ImVec2(20, 0), ImGuiCond_Always); ImGui::SetNextWindowPos(
ImGui::SetNextWindowSize(ImVec2(0, 20), ImGuiCond_Always); ImVec2(title_bar_button_width_ * 0.8f, title_bar_button_width_ * 0.1f),
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 8.0f)); ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(0, title_bar_button_width_ * 0.8f),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.0f));
ImGui::Begin("TabBar", nullptr, ImGui::Begin("TabBar", nullptr,
@@ -82,33 +89,32 @@ int Render::StreamWindow() {
ImGuiTabBarFlags_AutoSelectNewTabs)) { ImGuiTabBarFlags_AutoSelectNewTabs)) {
is_tab_bar_hovered_ = ImGui::IsWindowHovered(); is_tab_bar_hovered_ = ImGui::IsWindowHovered();
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin(); for (auto it = client_properties_.begin();
it != client_properties_.end();) { it != client_properties_.end();) {
auto& props = it->second; auto& props = it->second;
if (!props->tab_opened_) { if (!props->tab_opened_) {
std::string remote_id_to_close = props->remote_id_; std::string remote_id_to_close = props->remote_id_;
lock.unlock(); // lock.unlock();
{ {
std::unique_lock unique_lock(client_properties_mutex_); // std::unique_lock unique_lock(client_properties_mutex_);
auto close_it = client_properties_.find(remote_id_to_close); auto close_it = client_properties_.find(remote_id_to_close);
if (close_it != client_properties_.end()) { if (close_it != client_properties_.end()) {
CloseTab(close_it); CloseTab(close_it);
} }
} }
lock.lock(); // lock.lock();
it = client_properties_.begin(); it = client_properties_.begin();
continue; continue;
} }
ImGui::SetWindowFontScale(0.6f);
std::string tab_label = std::string tab_label =
enable_srtp_ enable_srtp_
? std::string(ICON_FA_SHIELD_HALVED) + " " + props->remote_id_ ? std::string(ICON_FA_SHIELD_HALVED) + " " + props->remote_id_
: props->remote_id_; : props->remote_id_;
if (ImGui::BeginTabItem(tab_label.c_str(), &props->tab_opened_)) { if (ImGui::BeginTabItem(tab_label.c_str(), &props->tab_opened_)) {
props->tab_selected_ = true; props->tab_selected_ = true;
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(0.6f);
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(stream_window_width_, stream_window_height_), ImVec2(stream_window_width_, stream_window_height_),
@@ -137,9 +143,9 @@ int Render::StreamWindow() {
if (!props->peer_) { if (!props->peer_) {
std::string remote_id_to_erase = props->remote_id_; std::string remote_id_to_erase = props->remote_id_;
lock.unlock(); // lock.unlock();
{ {
std::unique_lock unique_lock(client_properties_mutex_); // std::unique_lock unique_lock(client_properties_mutex_);
auto erase_it = client_properties_.find(remote_id_to_erase); auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) { if (erase_it != client_properties_.end()) {
erase_it = client_properties_.erase(erase_it); erase_it = client_properties_.erase(erase_it);
@@ -150,7 +156,9 @@ int Render::StreamWindow() {
} }
} }
} }
lock.lock(); // lock.lock();
ImGui::End();
ImGui::EndTabItem();
it = client_properties_.begin(); it = client_properties_.begin();
continue; continue;
} else { } else {
@@ -162,7 +170,20 @@ int Render::StreamWindow() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} else { } else {
props->tab_selected_ = false; props->tab_selected_ = false;
ImGui::SetWindowFontScale(1.0f); if (!props->tab_opened_) {
std::string remote_id_to_close = props->remote_id_;
// lock.unlock();
{
// std::unique_lock unique_lock(client_properties_mutex_);
auto close_it = client_properties_.find(remote_id_to_close);
if (close_it != client_properties_.end()) {
CloseTab(close_it);
}
}
// lock.lock();
it = client_properties_.begin();
continue;
}
++it; ++it;
} }
} }
@@ -172,21 +193,21 @@ int Render::StreamWindow() {
ImGui::End(); // End TabBar ImGui::End(); // End TabBar
} else { } else {
std::shared_lock lock(client_properties_mutex_); // std::shared_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin(); for (auto it = client_properties_.begin();
it != client_properties_.end();) { it != client_properties_.end();) {
auto& props = it->second; auto& props = it->second;
if (!props->tab_opened_) { if (!props->tab_opened_) {
std::string remote_id_to_close = props->remote_id_; std::string remote_id_to_close = props->remote_id_;
lock.unlock(); // lock.unlock();
{ {
std::unique_lock unique_lock(client_properties_mutex_); // std::unique_lock unique_lock(client_properties_mutex_);
auto close_it = client_properties_.find(remote_id_to_close); auto close_it = client_properties_.find(remote_id_to_close);
if (close_it != client_properties_.end()) { if (close_it != client_properties_.end()) {
CloseTab(close_it); CloseTab(close_it);
} }
} }
lock.lock(); // lock.lock();
it = client_properties_.begin(); it = client_properties_.begin();
continue; continue;
} }
@@ -218,9 +239,9 @@ int Render::StreamWindow() {
fullscreen_button_pressed_ = false; fullscreen_button_pressed_ = false;
SDL_SetWindowFullscreen(stream_window_, false); SDL_SetWindowFullscreen(stream_window_, false);
std::string remote_id_to_erase = props->remote_id_; std::string remote_id_to_erase = props->remote_id_;
lock.unlock(); // lock.unlock();
{ {
std::unique_lock unique_lock(client_properties_mutex_); // std::unique_lock unique_lock(client_properties_mutex_);
auto erase_it = client_properties_.find(remote_id_to_erase); auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) { if (erase_it != client_properties_.end()) {
client_properties_.erase(erase_it); client_properties_.erase(erase_it);
@@ -231,7 +252,7 @@ int Render::StreamWindow() {
} }
} }
} }
lock.lock(); // lock.lock();
it = client_properties_.begin(); it = client_properties_.begin();
continue; continue;
} else { } else {

View File

@@ -55,22 +55,25 @@ int Render::UpdateNotificationWindow() {
if (show_update_notification_window_ && update_available_) { if (show_update_notification_window_ && update_available_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport(); const ImGuiViewport* viewport = ImGui::GetMainViewport();
float window_width = update_notification_window_width_; float update_notification_window_width = title_bar_button_width_ * 10.0f;
float window_height = update_notification_window_height_; float update_notification_window_height = title_bar_button_width_ * 8.0f;
#ifdef __APPLE__ // #ifdef __APPLE__
float font_scale = 0.3f; // float font_scale = 0.3f;
#else // #else
float font_scale = 0.5f; // float font_scale = 0.5f;
#endif // #endif
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x -
ImVec2( update_notification_window_width) /
(viewport->WorkSize.x - viewport->WorkPos.x - window_width) / 2, 2,
(viewport->WorkSize.y - viewport->WorkPos.y - window_height) / 2), (viewport->WorkSize.y - viewport->WorkPos.y -
ImGuiCond_FirstUseEver); update_notification_window_height) /
2),
ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); ImGui::SetNextWindowSize(ImVec2(update_notification_window_width,
update_notification_window_height));
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
@@ -82,21 +85,17 @@ int Render::UpdateNotificationWindow() {
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar); ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar);
if (system_chinese_font_ != nullptr) { ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
ImGui::PushFont(system_chinese_font_); update_notification_window_height * 0.05f);
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() +
5.0f);
// title: new version available // title: new version available
ImGui::SetCursorPosX(window_width * 0.1f); ImGui::SetCursorPosX(update_notification_window_width * 0.1f);
ImGui::SetWindowFontScale(font_scale + 0.2f); ImGui::SetWindowFontScale(0.55f);
std::string title = std::string title =
localization::new_version_available[localization_language_index_] + localization::new_version_available[localization_language_index_] +
": v" + latest_version_; ": v" + latest_version_;
ImGui::Text("%s", title.c_str()); ImGui::Text("%s", title.c_str());
ImGui::SetWindowFontScale(font_scale); ImGui::SetWindowFontScale(0.1f);
ImGui::Spacing(); ImGui::Spacing();
@@ -104,19 +103,26 @@ int Render::UpdateNotificationWindow() {
std::string download_text = std::string download_text =
localization::access_website[localization_language_index_] + localization::access_website[localization_language_index_] +
"https://crossdesk.cn"; "https://crossdesk.cn";
Hyperlink(download_text, "https://crossdesk.cn", window_width); ImGui::SetWindowFontScale(0.5f);
Hyperlink(download_text, "https://crossdesk.cn",
update_notification_window_width);
ImGui::SetWindowFontScale(1.0f);
ImGui::Spacing(); ImGui::Spacing();
float scrollable_height = float scrollable_height =
window_height - UPDATE_NOTIFICATION_RESERVED_HEIGHT; update_notification_window_height - UPDATE_NOTIFICATION_RESERVED_HEIGHT;
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PushFont(main_windows_system_chinese_font_);
}
// scrollable content area // scrollable content area
ImGui::SetCursorPosX(window_width * 0.05f); ImGui::SetCursorPosX(update_notification_window_width * 0.05f);
ImGui::BeginChild("ScrollableContent", ImGui::BeginChild(
ImVec2(window_width * 0.9f, scrollable_height), "ScrollableContent",
ImGuiChildFlags_Border, ImGuiWindowFlags_None); ImVec2(update_notification_window_width * 0.9f, scrollable_height),
ImGuiChildFlags_Border, ImGuiWindowFlags_None);
ImGui::SetWindowFontScale(0.5f);
// set text wrap position to current available width (accounts for // set text wrap position to current available width (accounts for
// scrollbar) // scrollbar)
float wrap_pos = ImGui::GetContentRegionAvail().x; float wrap_pos = ImGui::GetContentRegionAvail().x;
@@ -126,7 +132,7 @@ int Render::UpdateNotificationWindow() {
if (latest_version_info_.contains("releaseName") && if (latest_version_info_.contains("releaseName") &&
latest_version_info_["releaseName"].is_string() && latest_version_info_["releaseName"].is_string() &&
!latest_version_info_["releaseName"].empty()) { !latest_version_info_["releaseName"].empty()) {
ImGui::SetCursorPosX(window_width * 0.05f); ImGui::SetCursorPosX(update_notification_window_width * 0.05f);
std::string release_name = std::string release_name =
latest_version_info_["releaseName"].get<std::string>(); latest_version_info_["releaseName"].get<std::string>();
ImGui::TextWrapped("%s", release_name.c_str()); ImGui::TextWrapped("%s", release_name.c_str());
@@ -135,7 +141,7 @@ int Render::UpdateNotificationWindow() {
// release notes // release notes
if (!release_notes_.empty()) { if (!release_notes_.empty()) {
ImGui::SetCursorPosX(window_width * 0.05f); ImGui::SetCursorPosX(update_notification_window_width * 0.05f);
std::string cleaned_notes = CleanMarkdown(release_notes_); std::string cleaned_notes = CleanMarkdown(release_notes_);
ImGui::TextWrapped("%s", cleaned_notes.c_str()); ImGui::TextWrapped("%s", cleaned_notes.c_str());
ImGui::Spacing(); ImGui::Spacing();
@@ -145,7 +151,7 @@ int Render::UpdateNotificationWindow() {
if (latest_version_info_.contains("releaseDate") && if (latest_version_info_.contains("releaseDate") &&
latest_version_info_["releaseDate"].is_string() && latest_version_info_["releaseDate"].is_string() &&
!latest_version_info_["releaseDate"].empty()) { !latest_version_info_["releaseDate"].empty()) {
ImGui::SetCursorPosX(window_width * 0.05f); ImGui::SetCursorPosX(update_notification_window_width * 0.05f);
std::string date_label = std::string date_label =
localization::release_date[localization_language_index_]; localization::release_date[localization_language_index_];
std::string release_date = latest_version_info_["releaseDate"]; std::string release_date = latest_version_info_["releaseDate"];
@@ -159,14 +165,20 @@ int Render::UpdateNotificationWindow() {
ImGui::EndChild(); ImGui::EndChild();
// pop system font
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PopFont();
}
ImGui::Spacing(); ImGui::Spacing();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN); ImGui::SetCursorPosX(update_notification_window_width * 0.407f);
} else { } else {
ImGui::SetCursorPosX(UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN); ImGui::SetCursorPosX(update_notification_window_width * 0.367f);
} }
ImGui::SetWindowFontScale(0.5f);
// update button // update button
if (ImGui::Button( if (ImGui::Button(
localization::update[localization_language_index_].c_str())) { localization::update[localization_language_index_].c_str())) {
@@ -191,15 +203,8 @@ int Render::UpdateNotificationWindow() {
} }
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(font_scale);
// pop system font
if (system_chinese_font_ != nullptr) {
ImGui::PopFont();
}
ImGui::End(); ImGui::End();
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleVar(3); ImGui::PopStyleVar(3);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }

View File

@@ -1,6 +1,9 @@
#include "screen_capturer_x11.h" #include "screen_capturer_x11.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xfixes.h> #include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xrandr.h>
#include <chrono> #include <chrono>
#include <thread> #include <thread>

View File

@@ -7,10 +7,14 @@
#ifndef _SCREEN_CAPTURER_X11_H_ #ifndef _SCREEN_CAPTURER_X11_H_
#define _SCREEN_CAPTURER_X11_H_ #define _SCREEN_CAPTURER_X11_H_
#include <X11/Xlib.h> // forward declarations for X11 types
#include <X11/Xutil.h> struct _XDisplay;
#include <X11/extensions/Xrandr.h> typedef struct _XDisplay Display;
#include <X11/extensions/Xfixes.h> typedef unsigned long Window;
struct _XRRScreenResources;
typedef struct _XRRScreenResources XRRScreenResources;
struct _XImage;
typedef struct _XImage XImage;
#include <atomic> #include <atomic>
#include <cstring> #include <cstring>
@@ -43,6 +47,9 @@ class ScreenCapturerX11 : public ScreenCapturer {
void OnFrame(); void OnFrame();
private:
void DrawCursor(XImage* image, int x, int y);
private: private:
Display* display_ = nullptr; Display* display_ = nullptr;
Window root_ = 0; Window root_ = 0;
@@ -60,12 +67,8 @@ class ScreenCapturerX11 : public ScreenCapturer {
cb_desktop_data callback_; cb_desktop_data callback_;
std::vector<DisplayInfo> display_info_list_; std::vector<DisplayInfo> display_info_list_;
// 缓冲区
std::vector<uint8_t> y_plane_; std::vector<uint8_t> y_plane_;
std::vector<uint8_t> uv_plane_; std::vector<uint8_t> uv_plane_;
// 鼠标光标相关
void DrawCursor(XImage* image, int x, int y);
}; };
} // namespace crossdesk } // namespace crossdesk
#endif #endif

View File

@@ -77,12 +77,14 @@ ScreenCapturerWgc::~ScreenCapturerWgc() {
CleanUp(); CleanUp();
if (nv12_frame_) { if (nv12_frame_) {
delete nv12_frame_; delete[] nv12_frame_;
nv12_frame_ = nullptr; nv12_frame_ = nullptr;
nv12_width_ = 0;
nv12_height_ = 0;
} }
if (nv12_frame_scaled_) { if (nv12_frame_scaled_) {
delete nv12_frame_scaled_; delete[] nv12_frame_scaled_;
nv12_frame_scaled_ = nullptr; nv12_frame_scaled_ = nullptr;
} }
} }
@@ -215,13 +217,14 @@ int ScreenCapturerWgc::Resume(int monitor_index) {
} }
int ScreenCapturerWgc::Stop() { int ScreenCapturerWgc::Stop() {
running_ = false;
for (int i = 0; i < sessions_.size(); i++) { for (int i = 0; i < sessions_.size(); i++) {
if (sessions_[i].running_) { if (sessions_[i].running_) {
sessions_[i].session_->Stop(); sessions_[i].session_->Stop();
sessions_[i].running_ = false; sessions_[i].running_ = false;
} }
} }
running_ = false;
return 0; return 0;
} }
@@ -256,18 +259,61 @@ int ScreenCapturerWgc::SwitchTo(int monitor_index) {
void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame, void ScreenCapturerWgc::OnFrame(const WgcSession::wgc_session_frame& frame,
int id) { int id) {
if (!running_ || !on_data_) {
return;
}
std::lock_guard<std::mutex> lock(frame_mutex_);
if (on_data_) { if (on_data_) {
if (!nv12_frame_) { if (id < 0 || id >= static_cast<int>(display_info_list_.size())) {
nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2]; LOG_ERROR("WGC OnFrame invalid display index: {}", id);
return;
} }
libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4, if (!frame.data || frame.row_pitch == 0) {
(uint8_t*)nv12_frame_, frame.width, LOG_ERROR("WGC OnFrame received invalid frame: data={}, row_pitch={}",
(uint8_t*)(nv12_frame_ + frame.width * frame.height), (void*)frame.data, frame.row_pitch);
frame.width, frame.width, frame.height); return;
}
on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width, // calculate the maximum width that can be contained in one row according to
frame.height, display_info_list_[id].name.c_str()); // row_pitch (BGRA: 4 bytes per pixel), and take the minimum with logical
// width to avoid out-of-bounds access.
unsigned int max_width_by_pitch = frame.row_pitch / 4u;
int logical_width = static_cast<int>(
frame.width < max_width_by_pitch ? frame.width : max_width_by_pitch);
// libyuv::ARGBToNV12 requires even width/height
int even_width = logical_width & ~1;
int even_height = static_cast<int>(frame.height) & ~1;
if (even_width <= 0 || even_height <= 0) {
LOG_ERROR(
"WGC OnFrame invalid frame size after adjust: width={} "
"(frame.width={}, max_by_pitch={}), height={}",
logical_width, frame.width, max_width_by_pitch, frame.height);
return;
}
int nv12_size = even_width * even_height * 3 / 2;
if (!nv12_frame_ || nv12_width_ != even_width ||
nv12_height_ != even_height) {
delete[] nv12_frame_;
nv12_frame_ = new unsigned char[nv12_size];
nv12_width_ = even_width;
nv12_height_ = even_height;
}
libyuv::ARGBToNV12((const uint8_t*)frame.data,
static_cast<int>(frame.row_pitch), (uint8_t*)nv12_frame_,
even_width,
(uint8_t*)(nv12_frame_ + even_width * even_height),
even_width, even_width, even_height);
on_data_(nv12_frame_, nv12_size, even_width, even_height,
display_info_list_[id].name.c_str());
} }
} }

View File

@@ -3,6 +3,7 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector> #include <vector>
@@ -65,6 +66,10 @@ class ScreenCapturerWgc : public ScreenCapturer,
unsigned char* nv12_frame_ = nullptr; unsigned char* nv12_frame_ = nullptr;
unsigned char* nv12_frame_scaled_ = nullptr; unsigned char* nv12_frame_scaled_ = nullptr;
int nv12_width_ = 0;
int nv12_height_ = 0;
std::mutex frame_mutex_;
}; };
} // namespace crossdesk } // namespace crossdesk
#endif #endif

View File

@@ -38,8 +38,50 @@ class SpeakerCapturerMacosx;
if (_owner->cb_ && dataPtr && length > 0 && asbd) { if (_owner->cb_ && dataPtr && length > 0 && asbd) {
std::vector<short> out_pcm16; 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 (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 frame_bytes = 960; // 480 * 2
size_t total_bytes = out_pcm16.size() * sizeof(short); size_t total_bytes = out_pcm16.size() * sizeof(short);
unsigned char* p = (unsigned char*)out_pcm16.data(); unsigned char* p = (unsigned char*)out_pcm16.data();
@@ -48,6 +90,7 @@ class SpeakerCapturerMacosx;
} }
} }
} }
@end @end
namespace crossdesk { namespace crossdesk {

View File

@@ -156,6 +156,12 @@ Thumbnail::~Thumbnail() {
} }
} }
int Thumbnail::SetThumbnailDpiScale(float dpi_scale) {
thumbnail_width_ = static_cast<int>(thumbnail_width_ * dpi_scale);
thumbnail_height_ = static_cast<int>(thumbnail_height_ * dpi_scale);
return 0;
}
int Thumbnail::SaveToThumbnail(const char* yuv420p, int width, int height, int Thumbnail::SaveToThumbnail(const char* yuv420p, int width, int height,
const std::string& remote_id, const std::string& remote_id,
const std::string& host_name, const std::string& host_name,

View File

@@ -33,6 +33,8 @@ class Thumbnail {
~Thumbnail(); ~Thumbnail();
public: public:
int SetThumbnailDpiScale(float dpi_scale);
int SaveToThumbnail(const char* yuv420p, int width, int height, int SaveToThumbnail(const char* yuv420p, int width, int height,
const std::string& remote_id, const std::string& remote_id,
const std::string& host_name, const std::string& host_name,

View File

@@ -29,7 +29,7 @@ if is_mode("debug") then
end end
add_requires("spdlog 1.14.1", {system = false}) add_requires("spdlog 1.14.1", {system = false})
add_requires("imgui v1.91.5-docking", {configs = {sdl3 = true, sdl3_renderer = true}}) add_requires("imgui v1.92.1-docking", {configs = {sdl3 = true, sdl3_renderer = true}})
add_requires("openssl3 3.3.2", {system = false}) add_requires("openssl3 3.3.2", {system = false})
add_requires("nlohmann_json 3.11.3") add_requires("nlohmann_json 3.11.3")
add_requires("cpp-httplib v0.26.0", {configs = {ssl = true}}) add_requires("cpp-httplib v0.26.0", {configs = {ssl = true}})