Compare commits

...

47 Commits

Author SHA1 Message Date
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
dijunkun
3d8249bffa [fix] use lock and null pointer checks to prevent crashes 2025-11-28 00:41:29 +08:00
dijunkun
82f32cbe8f [fix] fix incorrect peer reference in AddVideoStream call 2025-11-27 23:53:27 +08:00
dijunkun
56da2f99f3 [chore] update Linux log path configuration 2025-11-27 23:20:14 +08:00
dijunkun
e6c72fe558 [feat] remove screen capture and accessibility permission when reinstall 2025-11-27 17:35:15 +08:00
dijunkun
a964c6bbf5 [fix] call log after log initialzation, refs #36, #29 2025-11-27 16:09:08 +08:00
dijunkun
239da373d0 [feat] attempt to rejoin once per second 2025-11-27 04:20:29 +08:00
dijunkun
217cfb091d [feat] display version info on startup 2025-11-27 04:18:08 +08:00
dijunkun
3c3c7b9ae0 [fix] fix crash when screen recording permission is not granted on macOS, refs #29 2025-11-27 03:32:16 +08:00
dijunkun
f14bdb7fe8 [feat] optimize UpdateNotificationWindow UI appearance 2025-11-27 03:07:55 +08:00
dijunkun
c0a98f97c3 [feat] optimize RequestPermissionWindow UI appearance 2025-11-27 02:40:33 +08:00
dijunkun
0ab6686eb8 [feat] use DrawToggleSwitch to request permission 2025-11-26 23:32:04 +08:00
dijunkun
76b475450b [feat] request macOS system permissions by showing a prompt on startup 2025-11-26 18:18:40 +08:00
dijunkun
5d1e1b5667 [fix] remove permissions on uninstall and request permissions during installation for MacOS 2025-11-26 16:11:49 +08:00
dijunkun
c3b8b1374a [chore] update README 2025-11-25 16:30:14 +08:00
40 changed files with 4199 additions and 3036 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]
**补充信息**
在此添加与问题相关的其他上下文内容。

4
.gitignore vendored
View File

@@ -1,10 +1,10 @@
# Xmake cache # Xmake cache
.xmake/ .xmake/
build/ build/
certs/
# MacOS Cache # MacOS Cache
.DS_Store .DS_Store
# VSCode cache # VSCode cache
.vscode .vscode
continuous-desk.code-workspace

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)
@@ -315,10 +316,10 @@ Generation complete. Deployment files::
Server certificate: crossdesk.cn_bundle.crt Server certificate: crossdesk.cn_bundle.crt
``` ```
#### 服务端 ### 服务端
**crossdesk.cn.key****crossdesk.cn_bundle.crt** 放置到 **/path/to/your/certs** 目录下。 **crossdesk.cn.key****crossdesk.cn_bundle.crt** 放置到 **/path/to/your/certs** 目录下。
#### 客户端 ### 客户端
1. 点击右上角设置进入设置页面。<br> 1. 点击右上角设置进入设置页面。<br>
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br> <img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br>
@@ -331,5 +332,8 @@ Generation complete. Deployment files::
7. 勾选使用**自托管服务器配置**,点击确认配置生效。<br><br> 7. 勾选使用**自托管服务器配置**,点击确认配置生效。<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br> <img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br>
### Web 客户端
详情见项目 [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
# 常见问题 # 常见问题
见 [常见问题](https://github.com/kunkundi/crossdesk/blob/self-hosted-server/docs/FAQ.md) 。 见 [常见问题](https://github.com/kunkundi/crossdesk/blob/self-hosted-server/docs/FAQ.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)
@@ -323,10 +324,10 @@ Generation complete. Deployment files::
Server certificate: crossdesk.cn_bundle.crt 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.
#### Client Side ### Client Side
1. Click the settings icon in the top-right corner to enter the settings page.<br> 1. Click the settings icon in the top-right corner to enter the settings page.<br>
<img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br> <img width="600" height="210" alt="image" src="https://github.com/user-attachments/assets/6431131d-b32a-4726-8783-6788f47baa3b" /><br><br>
@@ -339,5 +340,8 @@ Place **crossdesk.cn.key** and **crossdesk.cn_bundle.crt** into the **/path/to/y
4. Check the option to use **Self-Hosted Server Configuration**.<br><br> 4. Check the option to use **Self-Hosted Server Configuration**.<br><br>
<img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br> <img width="600" height="160" alt="image" src="https://github.com/user-attachments/assets/1e455dc3-4087-4f37-a544-1ff9f8789383" /><br><br>
### Web Client
See [CrossDesk Web Client](https://github.com/kunkundi/crossdesk-web-client)。
# FAQ # FAQ
See [FAQ](https://github.com/kunkundi/crosssesk/blob/self-hosted-server/docs/FAQ.md) . See [FAQ](https://github.com/kunkundi/crosssesk/blob/self-hosted-server/docs/FAQ.md) .

49
scripts/macosx/pkg_arm64.sh Normal file → Executable file
View File

@@ -86,29 +86,66 @@ pkgbuild \
--component "${APP_BUNDLE}" \ --component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p scripts mkdir -p build_pkg_scripts
cat > scripts/postinstall <<'EOF' cat > build_pkg_scripts/postinstall <<'EOF'
#!/bin/bash #!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console ) USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' ) HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 复制证书文件
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs" DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
mkdir -p "$DEST" mkdir -p "$DEST"
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
if command -v tccutil >/dev/null 2>&1; then
# 重置录屏权限
tccutil reset ScreenCapture "$IDENTIFIER" 2>/dev/null || true
# 重置辅助功能权限
tccutil reset Accessibility "$IDENTIFIER" 2>/dev/null || true
# 重置摄像头权限(如果需要)
tccutil reset Camera "$IDENTIFIER" 2>/dev/null || true
# 重置麦克风权限(如果需要)
tccutil reset Microphone "$IDENTIFIER" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi
done
exit 0 exit 0
EOF EOF
chmod +x scripts/postinstall chmod +x build_pkg_scripts/postinstall
pkgbuild \ pkgbuild \
--root "${CERTS_SOURCE}" \ --root "${CERTS_SOURCE}" \
--identifier "${IDENTIFIER}.certs" \ --identifier "${IDENTIFIER}.certs" \
--version "${APP_VERSION}" \ --version "${APP_VERSION}" \
--install-location "/Library/Application Support/CrossDesk/certs" \ --install-location "/Library/Application Support/CrossDesk/certs" \
--scripts scripts \ --scripts build_pkg_scripts \
build_pkg_temp/${APP_NAME}-certs.pkg build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \ productbuild \
@@ -118,7 +155,7 @@ productbuild \
echo "PKG package created: ${PKG_NAME}" echo "PKG package created: ${PKG_NAME}"
rm -rf build_pkg_temp scripts ${APP_BUNDLE} rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE}
echo "PKG package created successfully." echo "PKG package created successfully."
echo "package ${APP_BUNDLE}" echo "package ${APP_BUNDLE}"

49
scripts/macosx/pkg_x64.sh Normal file → Executable file
View File

@@ -86,29 +86,66 @@ pkgbuild \
--component "${APP_BUNDLE}" \ --component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p scripts mkdir -p build_pkg_scripts
cat > scripts/postinstall <<'EOF' cat > build_pkg_scripts/postinstall <<'EOF'
#!/bin/bash #!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console ) USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' ) HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 复制证书文件
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs" DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
mkdir -p "$DEST" mkdir -p "$DEST"
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
if command -v tccutil >/dev/null 2>&1; then
# 重置录屏权限
tccutil reset ScreenCapture "$IDENTIFIER" 2>/dev/null || true
# 重置辅助功能权限
tccutil reset Accessibility "$IDENTIFIER" 2>/dev/null || true
# 重置摄像头权限(如果需要)
tccutil reset Camera "$IDENTIFIER" 2>/dev/null || true
# 重置麦克风权限(如果需要)
tccutil reset Microphone "$IDENTIFIER" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi
done
exit 0 exit 0
EOF EOF
chmod +x scripts/postinstall chmod +x build_pkg_scripts/postinstall
pkgbuild \ pkgbuild \
--root "${CERTS_SOURCE}" \ --root "${CERTS_SOURCE}" \
--identifier "${IDENTIFIER}.certs" \ --identifier "${IDENTIFIER}.certs" \
--version "${APP_VERSION}" \ --version "${APP_VERSION}" \
--install-location "/Library/Application Support/CrossDesk/certs" \ --install-location "/Library/Application Support/CrossDesk/certs" \
--scripts scripts \ --scripts build_pkg_scripts \
build_pkg_temp/${APP_NAME}-certs.pkg build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \ productbuild \
@@ -118,7 +155,7 @@ productbuild \
echo "PKG package created: ${PKG_NAME}" echo "PKG package created: ${PKG_NAME}"
rm -rf build_pkg_temp scripts ${APP_BUNDLE} rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE}
echo "PKG package created successfully." echo "PKG package created successfully."
echo "package ${APP_BUNDLE}" echo "package ${APP_BUNDLE}"

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,73 +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_
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 120 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_WIDTH_CN 130 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_HEIGHT_CN 125 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_WIDTH_EN 260 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_HEIGHT_EN 125 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN 90 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN 210 * dpi_scale_
#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

@@ -188,6 +188,19 @@ static std::vector<std::string> minimize_to_tray = {
"Minimize to system tray when exit:"}; "Minimize to system tray when exit:"};
static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"}; static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"};
#endif #endif
#ifdef __APPLE__
static std::vector<std::string> request_permissions = {
reinterpret_cast<const char*>(u8"权限请求"), "Request Permissions"};
static std::vector<std::string> screen_recording_permission = {
reinterpret_cast<const char*>(u8"屏幕录制权限"),
"Screen Recording Permission"};
static std::vector<std::string> accessibility_permission = {
reinterpret_cast<const char*>(u8"辅助功能权限"),
"Accessibility Permission"};
static std::vector<std::string> permission_required_message = {
reinterpret_cast<const char*>(u8"该应用需要授权以下权限:"),
"The application requires the following permissions:"};
#endif
} // namespace localization } // namespace localization
} // namespace crossdesk } // namespace crossdesk
#endif #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,38 +80,65 @@ 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;
if (client_properties_.find(remote_id) != target_remote_id = props.remote_id;
client_properties_.end()) { target_password = props.password;
if (!client_properties_[remote_id]->connection_established_) { {
ConnectTo(props.remote_id, props.password.c_str(), false); // std::shared_lock lock(client_properties_mutex_);
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);
} }
} }
// check every 1 second for rejoin
if (need_to_rejoin_) { if (need_to_rejoin_) {
need_to_rejoin_ = false; auto now = std::chrono::steady_clock::now();
for (const auto& [_, props] : client_properties_) { auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
if (props->rejoin_) { now - last_rejoin_check_time_)
ConnectTo(props->remote_id_, props->remote_password_, .count();
props->remember_password_);
if (elapsed >= 1000) {
last_rejoin_check_time_ = now;
need_to_rejoin_ = false;
// std::shared_lock lock(client_properties_mutex_);
for (const auto& [_, props] : client_properties_) {
if (props->rejoin_) {
ConnectTo(props->remote_id_, props->remote_password_,
props->remember_password_);
}
} }
} }
} }
@@ -136,33 +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;
if (client_properties_.find(remote_id) == client_properties_.end()) { // std::shared_lock shared_lock(client_properties_mutex_);
client_properties_[remote_id] = bool exists =
std::make_shared<SubStreamWindowProperties>(); (client_properties_.find(remote_id) != client_properties_.end());
auto props = client_properties_[remote_id]; // shared_lock.unlock();
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_);
for (auto& display_info : display_info_list_) { if (!exists) {
AddVideoStream(peer_, display_info.name.c_str()); PeerPtr* peer_to_init = nullptr;
} std::string local_id;
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_); // std::unique_lock unique_lock(client_properties_mutex_);
Init(props->peer_); if (client_properties_.find(remote_id) == client_properties_.end()) {
LOG_INFO("[{}] Peer init finish", props->local_id_); client_properties_[remote_id] =
} else { std::make_shared<SubStreamWindowProperties>();
LOG_INFO("Create peer [{}] instance failed", props->local_id_); 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_;
}
} }
props->connection_status_ = ConnectionStatus::Connecting; 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_);
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;
@@ -174,14 +234,17 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
} }
std::string remote_id_with_pwd = remote_id + "@" + password; std::string remote_id_with_pwd = remote_id + "@" + password;
ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str()); if (props->peer_) {
if (0 == ret) { ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str());
props->rejoin_ = false; if (0 == ret) {
} else { props->rejoin_ = false;
props->rejoin_ = true; } else {
need_to_rejoin_ = true; props->rejoin_ = true;
need_to_rejoin_ = true;
}
} }
} }
// 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,32 +172,32 @@ 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;
} }
return SDL_HITTEST_NORMAL; return SDL_HITTEST_NORMAL;
} }
Render::Render() {} Render::Render() : last_rejoin_check_time_(std::chrono::steady_clock::now()) {}
Render::~Render() {} Render::~Render() {}
@@ -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);
@@ -895,10 +929,19 @@ int Render::DrawMainWindow() {
UpdateNotificationWindow(); UpdateNotificationWindow();
#ifdef __APPLE__
if (show_request_permission_window_) {
RequestPermissionWindow();
}
#endif
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_);
@@ -919,28 +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_);
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_) {
@@ -993,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 {
@@ -1005,6 +1063,8 @@ int Render::Run() {
} }
InitializeLogger(); InitializeLogger();
LOG_INFO("CrossDesk version: {}", CROSSDESK_VERSION);
InitializeSettings(); InitializeSettings();
InitializeSDL(); InitializeSDL();
InitializeModules(); InitializeModules();
@@ -1069,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_);
} }
@@ -1180,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;
} }
@@ -1221,6 +1279,9 @@ void Render::Cleanup() {
CleanupFactories(); CleanupFactories();
CleanupPeers(); CleanupPeers();
WaitForThumbnailSaveTasks();
AudioDeviceDestroy(); AudioDeviceDestroy();
DestroyMainWindowContext(); DestroyMainWindowContext();
DestroyMainWindow(); DestroyMainWindow();
@@ -1248,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_) {
@@ -1275,12 +1355,37 @@ void Render::CleanupPeers() {
DestroyPeer(&peer_); DestroyPeer(&peer_);
} }
for (auto& it : client_properties_) { {
auto props = it.second; // std::shared_lock lock(client_properties_mutex_);
CleanupPeer(props); for (auto& it : client_properties_) {
auto props = it.second;
CleanupPeer(props);
}
} }
client_properties_.clear(); {
// std::unique_lock lock(client_properties_mutex_);
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(
@@ -1297,6 +1402,7 @@ void Render::CleanSubStreamWindowProperties(
} }
void Render::UpdateRenderRect() { void Render::UpdateRenderRect() {
// 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;
@@ -1371,34 +1477,41 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
DestroyStreamWindow(); DestroyStreamWindow();
DestroyStreamWindowContext(); DestroyStreamWindowContext();
for (auto& [host_name, props] : client_properties_) { {
thumbnail_->SaveToThumbnail( // std::shared_lock lock(client_properties_mutex_);
(char*)props->dst_buffer_, props->video_width_, for (auto& [host_name, props] : client_properties_) {
props->video_height_, host_name, props->remote_host_name_, thumbnail_->SaveToThumbnail(
props->remember_password_ ? props->remote_password_ : ""); (char*)props->dst_buffer_, props->video_width_,
props->video_height_, host_name, props->remote_host_name_,
props->remember_password_ ? props->remote_password_ : "");
if (props->peer_) { if (props->peer_) {
std::string client_id = (host_name == client_id_) std::string client_id = (host_name == client_id_)
? "C-" + std::string(client_id_) ? "C-" + std::string(client_id_)
: client_id_; : client_id_;
LOG_INFO("[{}] Leave connection [{}]", client_id, host_name); LOG_INFO("[{}] Leave connection [{}]", client_id, host_name);
LeaveConnection(props->peer_, host_name.c_str()); LeaveConnection(props->peer_, host_name.c_str());
LOG_INFO("Destroy peer [{}]", client_id); LOG_INFO("Destroy peer [{}]", client_id);
DestroyPeer(&props->peer_); DestroyPeer(&props->peer_);
}
props->streaming_ = false;
props->remember_password_ = false;
props->connection_established_ = false;
props->audio_capture_button_pressed_ = false;
memset(&props->net_traffic_stats_, 0,
sizeof(props->net_traffic_stats_));
SDL_SetWindowFullscreen(main_window_, false);
SDL_FlushEvents(STREAM_REFRESH_EVENT, STREAM_REFRESH_EVENT);
memset(audio_buffer_, 0, 720);
} }
props->streaming_ = false;
props->remember_password_ = false;
props->connection_established_ = false;
props->audio_capture_button_pressed_ = false;
memset(&props->net_traffic_stats_, 0,
sizeof(props->net_traffic_stats_));
SDL_SetWindowFullscreen(main_window_, false);
SDL_FlushEvents(STREAM_REFRESH_EVENT, STREAM_REFRESH_EVENT);
memset(audio_buffer_, 0, 720);
} }
client_properties_.clear();
{
// std::unique_lock lock(client_properties_mutex_);
client_properties_.clear();
}
rejoin_ = false; rejoin_ = false;
is_client_mode_ = false; is_client_mode_ = false;

View File

@@ -15,8 +15,10 @@
#include <mutex> #include <mutex>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <optional> #include <optional>
#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"
@@ -30,6 +32,7 @@
#include "screen_capturer_factory.h" #include "screen_capturer_factory.h"
#include "speaker_capturer_factory.h" #include "speaker_capturer_factory.h"
#include "thumbnail.h" #include "thumbnail.h"
#if _WIN32 #if _WIN32
#include "win_tray.h" #include "win_tray.h"
#endif #endif
@@ -69,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;
@@ -177,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();
@@ -188,6 +189,14 @@ class Render {
int NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props); int NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props);
void DrawConnectionStatusText( void DrawConnectionStatusText(
std::shared_ptr<SubStreamWindowProperties>& props); std::shared_ptr<SubStreamWindowProperties>& props);
#ifdef __APPLE__
int RequestPermissionWindow();
bool CheckScreenRecordingPermission();
bool CheckAccessibilityPermission();
void OpenScreenRecordingPreferences();
void OpenAccessibilityPreferences();
bool DrawToggleSwitch(const char* id, bool active, bool enabled);
#endif
public: public:
static void OnReceiveVideoBufferCb(const XVideoFrame* video_frame, static void OnReceiveVideoBufferCb(const XVideoFrame* video_frame,
@@ -285,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>>
@@ -304,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
@@ -332,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;
@@ -371,6 +384,7 @@ class Render {
int audio_len_ = 0; int audio_len_ = 0;
bool audio_buffer_fresh_ = false; bool audio_buffer_fresh_ = false;
bool need_to_rejoin_ = false; bool need_to_rejoin_ = false;
std::chrono::steady_clock::time_point last_rejoin_check_time_;
bool just_created_ = false; bool just_created_ = false;
std::string controlled_remote_id_ = ""; std::string controlled_remote_id_ = "";
std::string focused_remote_id_ = ""; std::string focused_remote_id_ = "";
@@ -449,6 +463,9 @@ class Render {
bool show_new_version_icon_in_menu_ = true; bool show_new_version_icon_in_menu_ = true;
uint64_t new_version_icon_last_trigger_time_ = 0; uint64_t new_version_icon_last_trigger_time_ = 0;
uint64_t new_version_icon_render_start_time_ = 0; uint64_t new_version_icon_render_start_time_ = 0;
#ifdef __APPLE__
bool show_request_permission_window_ = true;
#endif
char client_id_[10] = ""; char client_id_[10] = "";
char client_id_display_[12] = ""; char client_id_display_[12] = "";
char client_id_with_password_[17] = ""; char client_id_with_password_[17] = "";
@@ -492,9 +509,15 @@ class Render {
/* ------ sub stream window property start ------ */ /* ------ sub stream window property start ------ */
std::unordered_map<std::string, std::shared_ptr<SubStreamWindowProperties>> std::unordered_map<std::string, std::shared_ptr<SubStreamWindowProperties>>
client_properties_; client_properties_;
std::shared_mutex client_properties_mutex_;
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,13 +21,16 @@ 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_);
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_];
if (props->connection_status_ == ConnectionStatus::Connected) { if (props->connection_status_ == ConnectionStatus::Connected) {
std::string msg = remote_action.to_json(); std::string msg = remote_action.to_json();
SendDataFrame(props->peer_, msg.c_str(), msg.size(), if (props->peer_) {
props->data_label_.c_str()); SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
} }
} }
} }
@@ -42,6 +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_);
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_) {
@@ -94,8 +98,10 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
} }
std::string msg = remote_action.to_json(); std::string msg = remote_action.to_json();
SendDataFrame(props->peer_, msg.c_str(), msg.size(), if (props->peer_) {
props->data_label_.c_str()); SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
} else if (SDL_EVENT_MOUSE_WHEEL == event.type && } else if (SDL_EVENT_MOUSE_WHEEL == event.type &&
last_mouse_event.button.x >= props->stream_render_rect_.x && last_mouse_event.button.x >= props->stream_render_rect_.x &&
last_mouse_event.button.x <= props->stream_render_rect_.x + last_mouse_event.button.x <= props->stream_render_rect_.x +
@@ -139,8 +145,10 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
render_height; render_height;
std::string msg = remote_action.to_json(); std::string msg = remote_action.to_json();
SendDataFrame(props->peer_, msg.c_str(), msg.size(), if (props->peer_) {
props->data_label_.c_str()); SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
} }
} }
@@ -154,11 +162,14 @@ void Render::SdlCaptureAudioIn(void* userdata, Uint8* stream, int len) {
} }
if (1) { if (1) {
for (auto it : render->client_properties_) { // std::shared_lock lock(render->client_properties_mutex_);
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) {
SendAudioFrame(props->peer_, (const char*)stream, len, if (props->peer_) {
render->audio_label_.c_str()); SendAudioFrame(props->peer_, (const char*)stream, len,
render->audio_label_.c_str());
}
} }
} }
@@ -207,6 +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_);
if (render->client_properties_.find(remote_id) == if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) { render->client_properties_.end()) {
return; return;
@@ -302,6 +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_);
if (render->client_properties_.find(remote_id) != if (render->client_properties_.find(remote_id) !=
render->client_properties_.end()) { render->client_properties_.end()) {
// local // local
@@ -373,6 +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_);
if (render->client_properties_.find(remote_id) == if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) { render->client_properties_.end()) {
return; return;
@@ -402,6 +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_);
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;
@@ -428,7 +443,7 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
case ConnectionStatus::Closed: { case ConnectionStatus::Closed: {
props->connection_established_ = false; props->connection_established_ = false;
props->mouse_control_button_pressed_ = false; props->mouse_control_button_pressed_ = false;
if (props->dst_buffer_) { if (props->dst_buffer_ && props->stream_texture_) {
memset(props->dst_buffer_, 0, props->dst_buffer_capacity_); memset(props->dst_buffer_, 0, props->dst_buffer_capacity_);
SDL_UpdateTexture(props->stream_texture_, NULL, props->dst_buffer_, SDL_UpdateTexture(props->stream_texture_, NULL, props->dst_buffer_,
props->texture_width_); props->texture_width_);
@@ -469,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;
@@ -562,6 +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_);
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,6 +38,7 @@ int Render::MainWindow() {
StatusBar(); StatusBar();
if (show_connection_status_window_) { if (show_connection_status_window_) {
// 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

@@ -0,0 +1,205 @@
#include "layout.h"
#include "localization.h"
#include "rd_log.h"
#include "render.h"
#include <ApplicationServices/ApplicationServices.h>
#include <CoreGraphics/CoreGraphics.h>
#import <Foundation/Foundation.h>
#include <unistd.h>
#include <cstdlib>
namespace crossdesk {
bool Render::DrawToggleSwitch(const char* id, bool active, bool enabled) {
const float TRACK_HEIGHT = ImGui::GetFrameHeight();
const float TRACK_WIDTH = TRACK_HEIGHT * 1.8f;
const float TRACK_RADIUS = TRACK_HEIGHT * 0.5f;
const float KNOB_PADDING = 2.0f;
const float KNOB_HEIGHT = TRACK_HEIGHT - 4.0f;
const float KNOB_WIDTH = KNOB_HEIGHT * 1.2f;
const float KNOB_RADIUS = KNOB_HEIGHT * 0.5f;
const float DISABLED_ALPHA = 0.6f;
const float KNOB_ALPHA_DISABLED = 0.9f;
const ImVec4 COLOR_ACTIVE = ImVec4(0.0f, 0.0f, 1.0f, 1.0f);
const ImVec4 COLOR_ACTIVE_HOVER = ImVec4(0.26f, 0.59f, 0.98f, 1.0f);
const ImVec4 COLOR_INACTIVE = ImVec4(0.60f, 0.60f, 0.60f, 1.0f);
const ImVec4 COLOR_INACTIVE_HOVER = ImVec4(0.70f, 0.70f, 0.70f, 1.0f);
const ImVec4 COLOR_KNOB = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 track_pos = ImGui::GetCursorScreenPos();
ImGui::InvisibleButton(id, ImVec2(TRACK_WIDTH, TRACK_HEIGHT));
bool hovered = ImGui::IsItemHovered();
bool clicked = ImGui::IsItemClicked() && enabled;
ImVec4 track_color = active ? (hovered && enabled ? COLOR_ACTIVE_HOVER : COLOR_ACTIVE)
: (hovered && enabled ? COLOR_INACTIVE_HOVER : COLOR_INACTIVE);
if (!enabled) {
track_color.w *= DISABLED_ALPHA;
}
ImVec2 track_min = ImVec2(track_pos.x, track_pos.y + 0.5f);
ImVec2 track_max = ImVec2(track_pos.x + TRACK_WIDTH, track_pos.y + TRACK_HEIGHT - 0.5f);
draw_list->AddRectFilled(track_min, track_max, ImGui::GetColorU32(track_color), TRACK_RADIUS);
float knob_position = active ? 1.0f : 0.0f;
float knob_min_x = track_pos.x + KNOB_PADDING;
float knob_max_x = track_pos.x + TRACK_WIDTH - KNOB_WIDTH - KNOB_PADDING;
float knob_x = knob_min_x + knob_position * (knob_max_x - knob_min_x);
float knob_y = track_pos.y + (TRACK_HEIGHT - KNOB_HEIGHT) * 0.5f;
ImVec4 knob_color = COLOR_KNOB;
if (!enabled) {
knob_color.w = KNOB_ALPHA_DISABLED;
}
ImVec2 knob_min = ImVec2(knob_x, knob_y);
ImVec2 knob_max = ImVec2(knob_x + KNOB_WIDTH, knob_y + KNOB_HEIGHT);
draw_list->AddRectFilled(knob_min, knob_max, ImGui::GetColorU32(knob_color), KNOB_RADIUS);
return clicked;
}
bool Render::CheckScreenRecordingPermission() {
// CGPreflightScreenCaptureAccess is available on macOS 10.15+
if (@available(macOS 10.15, *)) {
bool granted = CGPreflightScreenCaptureAccess();
return granted;
}
// for older macOS versions, assume permission is granted
return true;
}
bool Render::CheckAccessibilityPermission() {
NSDictionary* options = @{(__bridge id)kAXTrustedCheckOptionPrompt : @NO};
bool trusted = AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)options);
return trusted;
}
void Render::OpenAccessibilityPreferences() {
NSDictionary* options = @{(__bridge id)kAXTrustedCheckOptionPrompt : @YES};
AXIsProcessTrustedWithOptions((__bridge CFDictionaryRef)options);
system("open "
"\"x-apple.systempreferences:com.apple.preference.security?Privacy_"
"Accessibility\"");
}
void Render::OpenScreenRecordingPreferences() {
if (@available(macOS 10.15, *)) {
CGRequestScreenCaptureAccess();
}
system("open "
"\"x-apple.systempreferences:com.apple.preference.security?Privacy_"
"ScreenCapture\"");
}
int Render::RequestPermissionWindow() {
bool screen_recording_granted = CheckScreenRecordingPermission();
bool accessibility_granted = CheckAccessibilityPermission();
show_request_permission_window_ = !screen_recording_granted || !accessibility_granted;
if (!show_request_permission_window_) {
return 0;
}
const ImGuiViewport* viewport = ImGui::GetMainViewport();
float window_width = localization_language_index_ == 0 ? REQUEST_PERMISSION_WINDOW_WIDTH_CN
: REQUEST_PERMISSION_WINDOW_WIDTH_EN;
float window_height = localization_language_index_ == 0 ? REQUEST_PERMISSION_WINDOW_HEIGHT_CN
: REQUEST_PERMISSION_WINDOW_HEIGHT_EN;
float checkbox_padding = localization_language_index_ == 0
? REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN
: REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN;
ImVec2 center_pos = ImVec2((viewport->WorkSize.x - window_width) * 0.5f + viewport->WorkPos.x,
(viewport->WorkSize.y - window_height) * 0.5f + viewport->WorkPos.y);
ImGui::SetNextWindowPos(center_pos, ImGuiCond_Once);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height), ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin(
localization::request_permissions[localization_language_index_].c_str(), nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings);
ImGui::SetWindowFontScale(0.3f);
// use system font
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PushFont(main_windows_system_chinese_font_);
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetTextLineHeight() + 5.0f);
ImGui::SetCursorPosX(10.0f);
ImGui::TextWrapped(
"%s", localization::permission_required_message[localization_language_index_].c_str());
ImGui::Spacing();
ImGui::Spacing();
ImGui::Spacing();
// accessibility permission
ImGui::SetCursorPosX(10.0f);
ImGui::AlignTextToFramePadding();
ImGui::Text("1. %s:",
localization::accessibility_permission[localization_language_index_].c_str());
ImGui::SameLine();
ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosX(checkbox_padding);
if (accessibility_granted) {
DrawToggleSwitch("accessibility_toggle_on", true, false);
} else {
if (DrawToggleSwitch("accessibility_toggle", accessibility_granted, !accessibility_granted)) {
OpenAccessibilityPreferences();
}
}
ImGui::Spacing();
// screen recording permission
ImGui::SetCursorPosX(10.0f);
ImGui::AlignTextToFramePadding();
ImGui::Text("2. %s:",
localization::screen_recording_permission[localization_language_index_].c_str());
ImGui::SameLine();
ImGui::AlignTextToFramePadding();
ImGui::SetCursorPosX(checkbox_padding);
if (screen_recording_granted) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.0f);
DrawToggleSwitch("screen_recording_toggle_on", true, false);
} else {
if (DrawToggleSwitch("screen_recording_toggle", screen_recording_granted,
!screen_recording_granted)) {
OpenScreenRecordingPreferences();
}
}
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.45f);
// pop system font
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PopFont();
}
ImGui::End();
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleVar(4);
ImGui::PopStyleColor();
return 0;
}
} // namespace crossdesk

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,12 +32,15 @@ void Render::DrawConnectionStatusText(
} }
void Render::CloseTab(decltype(client_properties_)::iterator& it) { void Render::CloseTab(decltype(client_properties_)::iterator& it) {
CleanupPeer(it->second); // std::unique_lock lock(client_properties_mutex_);
it = client_properties_.erase(it); if (it != client_properties_.end()) {
if (client_properties_.empty()) { CleanupPeer(it->second);
SDL_Event event; it = client_properties_.erase(it);
event.type = SDL_EVENT_QUIT; if (client_properties_.empty()) {
SDL_PushEvent(&event); SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
} }
} }
@@ -50,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,
@@ -79,22 +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_);
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_) {
CloseTab(it); 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; 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_),
@@ -122,12 +142,25 @@ int Render::StreamWindow() {
focused_remote_id_ = props->remote_id_; focused_remote_id_ = props->remote_id_;
if (!props->peer_) { if (!props->peer_) {
it = client_properties_.erase(it); std::string remote_id_to_erase = props->remote_id_;
if (client_properties_.empty()) { // lock.unlock();
SDL_Event event; {
event.type = SDL_EVENT_QUIT; // std::unique_lock unique_lock(client_properties_mutex_);
SDL_PushEvent(&event); auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) {
erase_it = client_properties_.erase(erase_it);
if (client_properties_.empty()) {
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
}
} }
// lock.lock();
ImGui::End();
ImGui::EndTabItem();
it = client_properties_.begin();
continue;
} else { } else {
DrawConnectionStatusText(props); DrawConnectionStatusText(props);
++it; ++it;
@@ -137,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;
} }
} }
@@ -147,11 +193,22 @@ int Render::StreamWindow() {
ImGui::End(); // End TabBar ImGui::End(); // End TabBar
} else { } else {
// 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_) {
CloseTab(it); 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; continue;
} }
@@ -181,12 +238,23 @@ int Render::StreamWindow() {
if (!props->peer_) { if (!props->peer_) {
fullscreen_button_pressed_ = false; fullscreen_button_pressed_ = false;
SDL_SetWindowFullscreen(stream_window_, false); SDL_SetWindowFullscreen(stream_window_, false);
it = client_properties_.erase(it); std::string remote_id_to_erase = props->remote_id_;
if (client_properties_.empty()) { // lock.unlock();
SDL_Event event; {
event.type = SDL_EVENT_QUIT; // std::unique_lock unique_lock(client_properties_mutex_);
SDL_PushEvent(&event); auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) {
client_properties_.erase(erase_it);
if (client_properties_.empty()) {
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
}
} }
// lock.lock();
it = client_properties_.begin();
continue;
} else { } else {
DrawConnectionStatusText(props); DrawConnectionStatusText(props);
++it; ++it;

View File

@@ -55,44 +55,47 @@ 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;
ImGui::SetNextWindowPos( // #ifdef __APPLE__
ImVec2( // float font_scale = 0.3f;
(viewport->WorkSize.x - viewport->WorkPos.x - window_width) / 2, // #else
(viewport->WorkSize.y - viewport->WorkPos.y - window_height) / 2), // float font_scale = 0.5f;
ImGuiCond_FirstUseEver); // #endif
ImGui::SetNextWindowSize(ImVec2(window_width, window_height)); ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x -
update_notification_window_width) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
update_notification_window_height) /
2),
ImGuiCond_FirstUseEver);
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);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::SetWindowFontScale(0.5f);
ImGui::Begin( ImGui::Begin(
localization::notification[localization_language_index_].c_str(), localization::notification[localization_language_index_].c_str(),
nullptr, nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoSavedSettings); ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar);
ImGui::SetWindowFontScale(1.0f); ImGui::SetCursorPosY(ImGui::GetCursorPosY() +
ImGui::SetWindowFontScale(0.5f); update_notification_window_height * 0.05f);
// use system Chinese font
if (system_chinese_font_ != nullptr) {
ImGui::PushFont(system_chinese_font_);
}
// title: new version available // title: new version available
ImGui::SetCursorPosX(window_width * 0.1f); ImGui::SetCursorPosX(update_notification_window_width * 0.1f);
ImGui::SetWindowFontScale(0.7f); 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(0.5f); ImGui::SetWindowFontScale(0.1f);
ImGui::Spacing(); ImGui::Spacing();
@@ -100,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 reserved_height = 140.0f; float scrollable_height =
float scrollable_height = window_height - 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;
@@ -122,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());
@@ -131,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();
@@ -141,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"];
@@ -155,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())) {
@@ -187,15 +203,8 @@ int Render::UpdateNotificationWindow() {
} }
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f);
// 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

@@ -36,7 +36,7 @@ std::filesystem::path PathManager::GetLogPath() {
#elif __APPLE__ #elif __APPLE__
return GetHome() + "/Library/Logs/" + app_name_; return GetHome() + "/Library/Logs/" + app_name_;
#else #else
return GetCachePath() / app_name_ / "logs"; return GetCachePath() / "logs";
#endif #endif
} }

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

@@ -196,14 +196,26 @@ ScreenCapturerSckImpl::~ScreenCapturerSckImpl() {
int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) { int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
_on_data = cb; _on_data = cb;
fps_ = fps;
if (@available(macOS 10.15, *)) {
bool has_permission = CGPreflightScreenCaptureAccess();
if (!has_permission) {
LOG_ERROR("Screen recording permission not granted");
return -1;
}
}
dispatch_semaphore_t sema = dispatch_semaphore_create(0); dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block SCShareableContent *content = nil; __block SCShareableContent *content = nil;
__block NSError *capture_error = nil;
[SCShareableContent [SCShareableContent
getShareableContentWithCompletionHandler:^(SCShareableContent *result, NSError *error) { getShareableContentWithCompletionHandler:^(SCShareableContent *result, NSError *error) {
if (error) { if (error) {
NSLog(@"Failed to get shareable content: %@", error); capture_error = error;
LOG_ERROR("Failed to get shareable content: {}",
std::string([error.localizedDescription UTF8String]));
} else { } else {
content = result; content = result;
} }
@@ -211,9 +223,10 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
}]; }];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if (!content || content.displays.count == 0) { if (capture_error || !content || content.displays.count == 0) {
LOG_ERROR("Failed to get display info"); LOG_ERROR("Failed to get display info, error: {}",
return 0; std::string([capture_error.localizedDescription UTF8String]));
return -1;
} }
CGDirectDisplayID displays[10]; CGDirectDisplayID displays[10];
@@ -252,6 +265,16 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
} }
int ScreenCapturerSckImpl::Start(bool show_cursor) { int ScreenCapturerSckImpl::Start(bool show_cursor) {
if (permanent_error_) {
LOG_ERROR("Cannot start capturer: permanent error occurred");
return -1;
}
if (display_info_list_.empty()) {
LOG_ERROR("Cannot start capturer: display info not initialized");
return -1;
}
show_cursor_ = show_cursor; show_cursor_ = show_cursor;
StartOrReconfigureCapturer(); StartOrReconfigureCapturer();
return 0; return 0;
@@ -307,17 +330,17 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
return; return;
} }
if (!content.displays.count) { if (!content.displays || content.displays.count == 0) {
LOG_ERROR("getShareableContent returned no displays"); LOG_ERROR("getShareableContent returned no displays");
permanent_error_ = true; permanent_error_ = true;
return; return;
} }
SCDisplay *captured_display; SCDisplay *captured_display = nil;
{ {
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(lock_);
for (SCDisplay *display in content.displays) { for (SCDisplay *display in content.displays) {
if (current_display_ == display.displayID) { if (current_display_ != 0 && current_display_ == display.displayID) {
LOG_WARN("current display: {}, name: {}", current_display_, LOG_WARN("current display: {}, name: {}", current_display_,
display_id_name_map_[current_display_]); display_id_name_map_[current_display_]);
captured_display = display; captured_display = display;
@@ -326,13 +349,33 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
} }
if (!captured_display) { if (!captured_display) {
captured_display = content.displays.firstObject; captured_display = content.displays.firstObject;
current_display_ = captured_display.displayID; if (captured_display) {
current_display_ = captured_display.displayID;
}
} }
} }
if (!captured_display) {
LOG_ERROR("Failed to find valid display");
permanent_error_ = true;
return;
}
SCContentFilter *filter = [[SCContentFilter alloc] initWithDisplay:captured_display SCContentFilter *filter = [[SCContentFilter alloc] initWithDisplay:captured_display
excludingWindows:@[]]; excludingWindows:@[]];
if (!filter) {
LOG_ERROR("Failed to create SCContentFilter");
permanent_error_ = true;
return;
}
SCStreamConfiguration *config = [[SCStreamConfiguration alloc] init]; SCStreamConfiguration *config = [[SCStreamConfiguration alloc] init];
if (!config) {
LOG_ERROR("Failed to create SCStreamConfiguration");
permanent_error_ = true;
return;
}
config.pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; config.pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
config.showsCursor = show_cursor_; config.showsCursor = show_cursor_;
config.width = filter.contentRect.size.width * filter.pointPixelScale; config.width = filter.contentRect.size.width * filter.pointPixelScale;
@@ -423,11 +466,28 @@ void ScreenCapturerSckImpl::OnNewCVPixelBuffer(CVPixelBufferRef pixelBuffer,
} }
void ScreenCapturerSckImpl::StartOrReconfigureCapturer() { void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
// The copy is needed to avoid capturing `this` in the Objective-C block. Accessing `helper_` if (permanent_error_) {
// inside the block is equivalent to `this->helper_` and would crash (UAF) if `this` is LOG_ERROR("Cannot reconfigure capturer: permanent error occurred");
// deleted before the block is executed. return;
}
if (@available(macOS 10.15, *)) {
bool has_permission = CGPreflightScreenCaptureAccess();
if (!has_permission) {
LOG_ERROR("Screen recording permission not granted");
permanent_error_ = true;
return;
}
}
SckHelper *local_helper = helper_; SckHelper *local_helper = helper_;
auto handler = ^(SCShareableContent *content, NSError *error) { auto handler = ^(SCShareableContent *content, NSError *error) {
if (error) {
LOG_ERROR("getShareableContent failed: {}",
std::string([error.localizedDescription UTF8String]));
[local_helper onShareableContentCreated:nil];
return;
}
[local_helper onShareableContentCreated:content]; [local_helper onShareableContentCreated:content];
}; };
[SCShareableContent getShareableContentWithCompletionHandler:handler]; [SCShareableContent getShareableContentWithCompletionHandler:handler];

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}})
@@ -182,6 +182,8 @@ target("gui")
if is_os("windows") then if is_os("windows") then
add_files("src/gui/tray/*.cpp") add_files("src/gui/tray/*.cpp")
add_includedirs("src/gui/tray", {public = true}) add_includedirs("src/gui/tray", {public = true})
elseif is_os("macosx") then
add_files("src/gui/windows/*.mm")
end end
target("crossdesk") target("crossdesk")