Compare commits

..

1 Commits

37 changed files with 2628 additions and 3311 deletions

View File

@@ -1,35 +0,0 @@
---
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,6 +1,5 @@
# 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)

View File

@@ -1,6 +1,5 @@
# 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)

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

@@ -78,6 +78,14 @@ EOF
echo ".app created successfully." echo ".app created successfully."
SIGN_IDENTITY="${CROSSDESK_SIGN_IDENTITY:--}"
if command -v codesign &> /dev/null; then
codesign --force --deep --sign "$SIGN_IDENTITY" "${APP_BUNDLE}" 2>/dev/null || {
echo "Warning: Code signing failed. The app may not work properly."
}
fi
echo "building pkg..." echo "building pkg..."
pkgbuild \ pkgbuild \
--identifier "${IDENTIFIER}" \ --identifier "${IDENTIFIER}" \
@@ -86,66 +94,54 @@ pkgbuild \
--component "${APP_BUNDLE}" \ --component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p build_pkg_scripts mkdir -p scripts
cat > build_pkg_scripts/postinstall <<'EOF' cat > scripts/postinstall <<'EOF'
#!/bin/bash #!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app" IDENTIFIER="cn.crossdesk.app"
APP_NAME="CrossDesk"
APP_PATH="/Applications/${APP_NAME}.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/" if [ -d "/Library/Application Support/CrossDesk/certs" ]; then
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" 2>/dev/null || true
# 清除应用的权限授权,以便重新授权
# 使用 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 fi
# 为所有用户清除权限(可选,如果需要) if [ -d "$APP_PATH" ]; then
# 遍历所有用户目录并清除权限 touch "$APP_PATH"
for USER_DIR in /Users/*; do /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$APP_PATH" 2>/dev/null || true
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR") USER_ID=$(dscl . -read /Users/$USER_HOME UniqueID 2>/dev/null | awk '{print $2}')
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then if [ -n "$USER_ID" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限) sleep 1
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db" launchctl asuser $USER_ID open "$APP_PATH" 2>/dev/null &
if [ -f "$TCC_DB" ]; then APP_PID=$!
# 使用 sqlite3 删除相关权限记录(如果可用) sleep 3
if command -v sqlite3 >/dev/null 2>&1; then kill "$APP_PID" 2>/dev/null || pkill -f "${APP_NAME}" 2>/dev/null || true
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi fi
done
open "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture" 2>/dev/null &
sleep 1
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" 2>/dev/null &
fi
exit 0 exit 0
EOF EOF
chmod +x build_pkg_scripts/postinstall chmod +x 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 build_pkg_scripts \ --scripts scripts \
build_pkg_temp/${APP_NAME}-certs.pkg build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \ productbuild \
@@ -155,7 +151,7 @@ productbuild \
echo "PKG package created: ${PKG_NAME}" echo "PKG package created: ${PKG_NAME}"
rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE} rm -rf build_pkg_temp scripts ${APP_BUNDLE}
echo "PKG package created successfully." echo "PKG package created successfully."
echo "package ${APP_BUNDLE}" echo "package ${APP_BUNDLE}"

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

@@ -78,6 +78,14 @@ EOF
echo ".app created successfully." echo ".app created successfully."
SIGN_IDENTITY="${CROSSDESK_SIGN_IDENTITY:--}"
if command -v codesign &> /dev/null; then
codesign --force --deep --sign "$SIGN_IDENTITY" "${APP_BUNDLE}" 2>/dev/null || {
echo "Warning: Code signing failed. The app may not work properly."
}
fi
echo "building pkg..." echo "building pkg..."
pkgbuild \ pkgbuild \
--identifier "${IDENTIFIER}" \ --identifier "${IDENTIFIER}" \
@@ -86,66 +94,54 @@ pkgbuild \
--component "${APP_BUNDLE}" \ --component "${APP_BUNDLE}" \
build_pkg_temp/${APP_NAME}-component.pkg build_pkg_temp/${APP_NAME}-component.pkg
mkdir -p build_pkg_scripts mkdir -p scripts
cat > build_pkg_scripts/postinstall <<'EOF' cat > scripts/postinstall <<'EOF'
#!/bin/bash #!/bin/bash
set -e
IDENTIFIER="cn.crossdesk.app" IDENTIFIER="cn.crossdesk.app"
APP_NAME="CrossDesk"
APP_PATH="/Applications/${APP_NAME}.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/" if [ -d "/Library/Application Support/CrossDesk/certs" ]; then
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" 2>/dev/null || true
# 清除应用的权限授权,以便重新授权
# 使用 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 fi
# 为所有用户清除权限(可选,如果需要) if [ -d "$APP_PATH" ]; then
# 遍历所有用户目录并清除权限 touch "$APP_PATH"
for USER_DIR in /Users/*; do /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$APP_PATH" 2>/dev/null || true
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR") USER_ID=$(dscl . -read /Users/$USER_HOME UniqueID 2>/dev/null | awk '{print $2}')
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then if [ -n "$USER_ID" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限) sleep 1
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db" launchctl asuser $USER_ID open "$APP_PATH" 2>/dev/null &
if [ -f "$TCC_DB" ]; then APP_PID=$!
# 使用 sqlite3 删除相关权限记录(如果可用) sleep 3
if command -v sqlite3 >/dev/null 2>&1; then kill "$APP_PID" 2>/dev/null || pkill -f "${APP_NAME}" 2>/dev/null || true
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
fi fi
done
open "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture" 2>/dev/null &
sleep 1
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" 2>/dev/null &
fi
exit 0 exit 0
EOF EOF
chmod +x build_pkg_scripts/postinstall chmod +x 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 build_pkg_scripts \ --scripts scripts \
build_pkg_temp/${APP_NAME}-certs.pkg build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \ productbuild \
@@ -155,7 +151,7 @@ productbuild \
echo "PKG package created: ${PKG_NAME}" echo "PKG package created: ${PKG_NAME}"
rm -rf build_pkg_temp build_pkg_scripts ${APP_BUNDLE} rm -rf build_pkg_temp scripts ${APP_BUNDLE}
echo "PKG package created successfully." echo "PKG package created successfully."
echo "package ${APP_BUNDLE}" echo "package ${APP_BUNDLE}"

View File

@@ -0,0 +1,56 @@
#!/bin/bash
# Helper script to sign macOS app with different certificate options
# Usage: ./sign_app.sh <app_path> [certificate_name]
APP_PATH="$1"
CERT_NAME="$2"
if [ -z "$APP_PATH" ]; then
echo "Usage: $0 <app_path> [certificate_name]"
echo ""
echo "Examples:"
echo " $0 CrossDesk.app # Ad-hoc signing"
echo " $0 CrossDesk.app \"CrossDesk Dev\" # Sign with certificate name"
echo " $0 CrossDesk.app \"-\" # Explicit ad-hoc signing"
exit 1
fi
if [ ! -d "$APP_PATH" ]; then
echo "Error: App bundle not found: $APP_PATH"
exit 1
fi
if [ -z "$CERT_NAME" ]; then
# Default to ad-hoc signing
CERT_NAME="-"
echo "Using ad-hoc signing (no certificate specified)"
else
echo "Using certificate: $CERT_NAME"
fi
# Check if codesign is available
if ! command -v codesign &> /dev/null; then
echo "Error: codesign not found. Please install Xcode Command Line Tools."
exit 1
fi
# Sign the app
echo "Signing $APP_PATH..."
codesign --force --deep --sign "$CERT_NAME" "$APP_PATH"
if [ $? -eq 0 ]; then
echo "Signing successful!"
# Verify signature
echo ""
echo "Verifying signature..."
codesign -dv --verbose=4 "$APP_PATH" 2>&1 | head -20
echo ""
echo "Checking entitlements..."
codesign -d --entitlements - "$APP_PATH" 2>&1 || echo "No entitlements found"
else
echo "Error: Signing failed"
exit 1
fi

View File

@@ -0,0 +1,60 @@
#!/bin/bash
# macOS uninstall script for CrossDesk
# This script removes the application and cleans up permissions
APP_NAME="CrossDesk"
IDENTIFIER="cn.crossdesk.app"
echo "Uninstalling ${APP_NAME}..."
# Remove application
if [ -d "/Applications/${APP_NAME}.app" ]; then
echo "Removing application..."
rm -rf "/Applications/${APP_NAME}.app"
fi
# Remove user data
USER_HOME=$(/usr/bin/stat -f "%Su" /dev/console 2>/dev/null)
if [ -n "$USER_HOME" ]; then
HOME_DIR=$(/usr/bin/dscl . -read "/Users/$USER_HOME" NFSHomeDirectory 2>/dev/null | awk '{print $2}')
if [ -n "$HOME_DIR" ]; then
echo "Removing user data..."
rm -rf "$HOME_DIR/Library/Application Support/${APP_NAME}"
rm -rf "$HOME_DIR/Library/Logs/${APP_NAME}"
rm -rf "$HOME_DIR/Library/Caches/${APP_NAME}"
rm -rf "$HOME_DIR/Library/Preferences/${IDENTIFIER}.plist"
rm -rf "$HOME_DIR/Library/LaunchAgents/${APP_NAME}.plist"
fi
fi
# Remove system-wide certificates
if [ -d "/Library/Application Support/${APP_NAME}/certs" ]; then
echo "Removing system certificates..."
rm -rf "/Library/Application Support/${APP_NAME}"
fi
# Clean up permissions using tccutil (macOS 10.14+)
# Note: This requires user interaction and may not work in all cases
if command -v tccutil &> /dev/null; then
echo "Cleaning up permissions..."
# Reset screen recording permission
tccutil reset ScreenCapture "$IDENTIFIER" 2>/dev/null || true
# Reset accessibility permission
tccutil reset Accessibility "$IDENTIFIER" 2>/dev/null || true
# Reset camera permission
tccutil reset Camera "$IDENTIFIER" 2>/dev/null || true
# Reset microphone permission
tccutil reset Microphone "$IDENTIFIER" 2>/dev/null || true
echo "Permissions cleaned up. You may need to manually remove them from System Settings > Privacy & Security if they still appear."
else
echo "tccutil not available. Please manually remove permissions from System Settings > Privacy & Security"
fi
echo "Uninstallation complete."
echo ""
echo "Note: If permissions still appear in System Settings, please remove them manually:"
echo " 1. Open System Settings > Privacy & Security"
echo " 2. Remove ${APP_NAME} from Screen Recording and Accessibility"
exit 0

File diff suppressed because it is too large Load Diff

View File

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

@@ -188,19 +188,6 @@ 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

@@ -76,8 +76,7 @@ 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, if (ImGui::Button(ICON_FA_COPY, ImVec2(22, 38))) {
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
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();
@@ -157,27 +156,23 @@ 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, if (ImGui::Button(ICON_FA_EYE, ImVec2(22, 38))) {
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
show_password_ = !show_password_; show_password_ = !show_password_;
} }
if (!show_password_) { if (!show_password_) {
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine( draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 12.5f),
ImVec2(l_x + 3.0f * dpi_scale_, l_y + 12.5f * dpi_scale_), ImVec2(l_x + 20.3f, l_y + 26.5f),
ImVec2(l_x + 20.3f * dpi_scale_, l_y + 26.5f * dpi_scale_), IM_COL32(239, 240, 242, 255), 2.0f);
IM_COL32(239, 240, 242, 255), 2.0f); draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 11.0f),
draw_list->AddLine( ImVec2(l_x + 20.3f, l_y + 25.0f),
ImVec2(l_x + 3.0f * dpi_scale_, l_y + 11.0f * dpi_scale_), IM_COL32(0, 0, 0, 255), 1.5f);
ImVec2(l_x + 20.3f * dpi_scale_, l_y + 25.0f * dpi_scale_),
IM_COL32(0, 0, 0, 255), 1.5f);
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button(ICON_FA_PEN, if (ImGui::Button(ICON_FA_PEN, ImVec2(22, 38))) {
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
show_reset_password_window_ = true; show_reset_password_window_ = true;
} }
ImGui::SetWindowFontScale(1.0f); ImGui::SetWindowFontScale(1.0f);

View File

@@ -12,9 +12,9 @@ int Render::RecentConnectionsWindow() {
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_, main_window_height_ - title_bar_height_ - ImVec2(main_window_width_default_,
local_window_height_ - status_bar_height_ + main_window_height_default_ - title_bar_height_ -
1.0f), local_window_height_ - status_bar_height_ + 1.0f),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -37,22 +37,18 @@ int Render::RecentConnectionsWindow() {
} }
int Render::ShowRecentConnections() { int Render::ShowRecentConnections() {
float recent_connection_window_padding = 25.0f * dpi_scale_; ImGui::SetCursorPosX(25.0f);
float recent_connection_window_width =
main_window_width_ - 2 * recent_connection_window_padding;
ImGui::SetCursorPosX(recent_connection_window_padding);
ImVec2 sub_window_pos = ImGui::GetCursorPos(); ImVec2 sub_window_pos = ImGui::GetCursorPos();
std::map<std::string, ImVec2> sub_containers_pos; std::map<std::string, ImVec2> sub_containers_pos;
float recent_connection_sub_container_width = float recent_connection_sub_container_width =
recent_connection_image_width_ + 16.0f * dpi_scale_; recent_connection_image_width_ + 16.0f;
float recent_connection_sub_container_height = float recent_connection_sub_container_height =
recent_connection_image_height_ + 36.0f * dpi_scale_; recent_connection_image_height_ + 36.0f;
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("RecentConnectionsContainer",
ImVec2(recent_connection_window_width, ImVec2(main_window_width_default_ - 50.0f, 145.0f),
recent_connection_sub_container_height * 1.1f),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -64,8 +60,8 @@ int Render::ShowRecentConnections() {
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 * dpi_scale_; float button_width = 22;
float button_height = 22 * dpi_scale_; 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 =
@@ -118,11 +114,10 @@ int Render::ShowRecentConnections() {
it.second.remote_host_name = "unknown"; it.second.remote_host_name = "unknown";
} }
ImVec2 image_screen_pos = ImVec2 image_screen_pos = ImVec2(ImGui::GetCursorScreenPos().x + 5.0f,
ImVec2(ImGui::GetCursorScreenPos().x + 5.0f * dpi_scale_, ImGui::GetCursorScreenPos().y + 5.0f);
ImGui::GetCursorScreenPos().y + 5.0f * dpi_scale_); ImVec2 image_pos =
ImVec2 image_pos = ImVec2(ImGui::GetCursorPosX() + 5.0f * dpi_scale_, ImVec2(ImGui::GetCursorPosX() + 5.0f, ImGui::GetCursorPosY() + 5.0f);
ImGui::GetCursorPosY() + 5.0f * dpi_scale_);
ImGui::SetCursorPos(image_pos); ImGui::SetCursorPos(image_pos);
ImGui::Image((ImTextureID)(intptr_t)it.second.texture, ImGui::Image((ImTextureID)(intptr_t)it.second.texture,
ImVec2((float)recent_connection_image_width_, ImVec2((float)recent_connection_image_width_,
@@ -211,20 +206,17 @@ 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_ + ImVec2(image_screen_pos.x + recent_connection_image_width_ + 20.0f,
20.0f * dpi_scale_,
image_screen_pos.y); image_screen_pos.y);
ImVec2 line_end = ImVec2( ImVec2 line_end = ImVec2(
image_screen_pos.x + recent_connection_image_width_ + image_screen_pos.x + recent_connection_image_width_ + 20.0f,
20.0f * dpi_scale_,
image_screen_pos.y + recent_connection_image_height_ + button_height); image_screen_pos.y + recent_connection_image_height_ + 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( ImGui::SameLine(0, count != recent_connections_count ? 26.0f : 0.0f);
0, count != recent_connections_count ? (25.0f * dpi_scale_) : 0.0f);
} }
ImGui::EndChild(); ImGui::EndChild();

View File

@@ -75,64 +75,38 @@ 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, if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG, ImVec2(55, 38)) ||
ImVec2(55 * dpi_scale_, 38 * dpi_scale_)) ||
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;
target_remote_id = props.remote_id; if (client_properties_.find(remote_id) !=
target_password = props.password; client_properties_.end()) {
{ if (!client_properties_[remote_id]->connection_established_) {
// std::shared_lock lock(client_properties_mutex_); ConnectTo(props.remote_id, props.password.c_str(), false);
if (client_properties_.find(remote_id) !=
client_properties_.end()) {
if (!client_properties_[remote_id]->connection_established_) {
should_connect = true;
} else {
already_connected = true;
}
} else { } else {
should_connect = true; // todo: show warning message
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_) {
auto now = std::chrono::steady_clock::now(); need_to_rejoin_ = false;
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( for (const auto& [_, props] : client_properties_) {
now - last_rejoin_check_time_) if (props->rejoin_) {
.count(); ConnectTo(props->remote_id_, props->remote_password_,
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_);
}
} }
} }
} }
@@ -162,68 +136,33 @@ int Render::ConnectTo(const std::string& remote_id, const char* password,
LOG_INFO("Connect to [{}]", remote_id); LOG_INFO("Connect to [{}]", remote_id);
focused_remote_id_ = remote_id; focused_remote_id_ = remote_id;
// std::shared_lock shared_lock(client_properties_mutex_); if (client_properties_.find(remote_id) == client_properties_.end()) {
bool exists = client_properties_[remote_id] =
(client_properties_.find(remote_id) != client_properties_.end()); std::make_shared<SubStreamWindowProperties>();
// shared_lock.unlock(); auto props = client_properties_[remote_id];
props->local_id_ = "C-" + std::string(client_id_);
props->remote_id_ = remote_id;
memcpy(&props->params_, &params_, sizeof(Params));
props->params_.user_id = props->local_id_.c_str();
props->peer_ = CreatePeer(&props->params_);
if (!exists) { for (auto& display_info : display_info_list_) {
PeerPtr* peer_to_init = nullptr; AddVideoStream(peer_, display_info.name.c_str());
std::string local_id; }
AddAudioStream(props->peer_, props->audio_label_.c_str());
AddDataStream(props->peer_, props->data_label_.c_str());
{ if (props->peer_) {
// std::unique_lock unique_lock(client_properties_mutex_); LOG_INFO("[{}] Create peer instance successful", props->local_id_);
if (client_properties_.find(remote_id) == client_properties_.end()) { Init(props->peer_);
client_properties_[remote_id] = LOG_INFO("[{}] Peer init finish", props->local_id_);
std::make_shared<SubStreamWindowProperties>(); } else {
auto props = client_properties_[remote_id]; LOG_INFO("Create peer [{}] instance failed", props->local_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_min_width_ =
props->control_window_min_width_ * dpi_scale_;
props->control_window_min_height_ =
props->control_window_min_height_ * dpi_scale_;
props->control_window_max_width_ =
props->control_window_max_width_ * dpi_scale_;
props->control_window_max_height_ =
props->control_window_max_height_ * dpi_scale_;
props->control_window_width_ =
props->control_window_width_ * dpi_scale_;
props->control_window_height_ =
props->control_window_height_ * dpi_scale_;
// props->control_bar_pos_x_ = props->control_bar_pos_x_ * dpi_scale_;
// props->control_bar_pos_y_ = props->control_bar_pos_y_ * dpi_scale_;
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_;
}
} }
if (peer_to_init) { props->connection_status_ = ConnectionStatus::Connecting;
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;
@@ -235,17 +174,14 @@ 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;
if (props->peer_) { ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str());
ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str()); if (0 == ret) {
if (0 == ret) { props->rejoin_ = false;
props->rejoin_ = false; } else {
} else { props->rejoin_ = true;
props->rejoin_ = true; need_to_rejoin_ = true;
need_to_rejoin_ = true;
}
} }
} }
// read_lock.unlock();
return 0; return 0;
} }

View File

@@ -133,9 +133,9 @@ 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 * render->dpi_scale_ && area->y > MOUSE_GRAB_PADDING && if (area->y < 30 && area->y > MOUSE_GRAB_PADDING &&
area->x < window_width - 120 * render->dpi_scale_ && area->x < window_width - 120 && area->x > MOUSE_GRAB_PADDING &&
area->x > MOUSE_GRAB_PADDING && !render->is_tab_bar_hovered_) { !render->is_tab_bar_hovered_) {
return SDL_HITTEST_DRAGGABLE; return SDL_HITTEST_DRAGGABLE;
} }
@@ -168,7 +168,7 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
return SDL_HITTEST_NORMAL; return SDL_HITTEST_NORMAL;
} }
Render::Render() : last_rejoin_check_time_(std::chrono::steady_clock::now()) {} Render::Render() {}
Render::~Render() {} Render::~Render() {}
@@ -365,16 +365,13 @@ 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;
@@ -605,53 +602,6 @@ void Render::UpdateInteractions() {
} }
} }
int Render::UpdateWindowSizeWithDpiScale(float dpi_scale) {
main_window_width_ = (int)(main_window_width_default_ * dpi_scale);
main_window_height_ = (int)(main_window_height_default_ * dpi_scale);
stream_window_width_ = (int)(stream_window_width_default_ * dpi_scale);
stream_window_height_ = (int)(stream_window_height_default_ * dpi_scale);
local_window_width_ = (int)(local_window_width_ * dpi_scale);
local_window_height_ = (int)(local_window_height_ * dpi_scale);
remote_window_width_ = (int)(remote_window_width_ * dpi_scale);
remote_window_height_ = (int)(remote_window_height_ * dpi_scale);
local_child_window_width_ = (int)(local_child_window_width_ * dpi_scale);
local_child_window_height_ = (int)(local_child_window_height_ * dpi_scale);
remote_child_window_width_ = (int)(remote_child_window_width_ * dpi_scale);
remote_child_window_height_ = (int)(remote_child_window_height_ * dpi_scale);
main_window_text_y_padding_ = (int)(main_window_text_y_padding_ * dpi_scale);
main_child_window_x_padding_ =
(int)(main_child_window_x_padding_ * dpi_scale);
main_child_window_y_padding_ =
(int)(main_child_window_y_padding_ * dpi_scale);
title_bar_width_ = (int)(title_bar_width_ * dpi_scale);
title_bar_height_ = (int)(title_bar_height_ * dpi_scale);
status_bar_height_ = (int)(status_bar_height_ * dpi_scale);
connection_status_window_width_ =
(int)(connection_status_window_width_ * dpi_scale);
connection_status_window_height_ =
(int)(connection_status_window_height_ * dpi_scale);
notification_window_width_ = (int)(notification_window_width_ * dpi_scale);
notification_window_height_ = (int)(notification_window_height_ * dpi_scale);
about_window_width_ = (int)(about_window_width_ * dpi_scale);
about_window_height_ = (int)(about_window_height_ * dpi_scale);
update_notification_window_width_ =
(int)(update_notification_window_width_ * dpi_scale);
update_notification_window_height_ =
(int)(update_notification_window_height_ * dpi_scale);
recent_connection_image_width_ =
(int)(recent_connection_image_width_ * dpi_scale);
recent_connection_image_height_ =
(int)(recent_connection_image_height_ * dpi_scale);
if (thumbnail_) {
thumbnail_->SetThumbnailDpiScale(dpi_scale);
}
return 0;
}
int Render::CreateMainWindow() { int Render::CreateMainWindow() {
main_ctx_ = ImGui::CreateContext(); main_ctx_ = ImGui::CreateContext();
if (!main_ctx_) { if (!main_ctx_) {
@@ -661,13 +611,9 @@ int Render::CreateMainWindow() {
ImGui::SetCurrentContext(main_ctx_); ImGui::SetCurrentContext(main_ctx_);
dpi_scale_ = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
LOG_INFO("System DPI scale before window creation: [{}]", dpi_scale_);
UpdateWindowSizeWithDpiScale(dpi_scale_);
if (!SDL_CreateWindowAndRenderer( if (!SDL_CreateWindowAndRenderer(
"Remote Desk", (int)main_window_width_, (int)main_window_height_, "Remote Desk", (int)main_window_width_default_,
(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_)) {
@@ -681,12 +627,6 @@ int Render::CreateMainWindow() {
// 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(
@@ -698,9 +638,6 @@ 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;
} }
@@ -734,8 +671,8 @@ int Render::CreateStreamWindow() {
ImGui::SetCurrentContext(stream_ctx_); ImGui::SetCurrentContext(stream_ctx_);
if (!SDL_CreateWindowAndRenderer( if (!SDL_CreateWindowAndRenderer(
"Stream window", (int)stream_window_width_, "Stream window", (int)stream_window_width_default_,
(int)stream_window_height_, (int)stream_window_height_default_,
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_: {}",
@@ -750,13 +687,6 @@ 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);
SDL_SetRenderScale(stream_renderer_, dpi_scale_, 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;
@@ -766,9 +696,6 @@ 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;
} }
@@ -793,9 +720,7 @@ int Render::DestroyStreamWindow() {
return 0; return 0;
} }
int Render::SetupFontAndStyle(bool main_window) { int Render::SetupFontAndStyle() {
float font_size = 32.0f;
// Setup Dear ImGui style // Setup Dear ImGui style
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
@@ -805,7 +730,7 @@ int Render::SetupFontAndStyle(bool main_window) {
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,
font_size, &config, 32.0f, &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};
@@ -815,11 +740,7 @@ int Render::SetupFontAndStyle(bool main_window) {
// Load system Chinese font as fallback // Load system Chinese font as fallback
config.MergeMode = false; config.MergeMode = false;
config.FontDataOwnedByAtlas = false; config.FontDataOwnedByAtlas = false;
if (main_window) { system_chinese_font_ = nullptr;
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 (宋体)
@@ -845,44 +766,52 @@ int Render::SetupFontAndStyle(bool main_window) {
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();
if (main_window) { system_chinese_font_ = io.Fonts->AddFontFromFileTTF(
main_windows_system_chinese_font_ = font_paths[i], 32.0f, &config, io.Fonts->GetGlyphRangesChineseFull());
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config, if (system_chinese_font_ != nullptr) {
io.Fonts->GetGlyphRangesChineseFull()); LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
if (main_windows_system_chinese_font_ != nullptr) { break;
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 (main_window) { if (system_chinese_font_ == nullptr) {
if (main_windows_system_chinese_font_ == nullptr) { system_chinese_font_ = io.Fonts->AddFontDefault(&config);
main_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config); LOG_WARN("System Chinese font not found, using default font");
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();
@@ -892,6 +821,42 @@ 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_);
@@ -915,8 +880,9 @@ int Render::DrawMainWindow() {
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(ImVec2(main_window_width_, main_window_height_), ImGui::SetNextWindowSize(
ImGuiCond_Always); ImVec2(main_window_width_, main_window_height_default_),
ImGuiCond_Always);
ImGui::Begin("MainRender", nullptr, ImGui::Begin("MainRender", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
@@ -929,20 +895,10 @@ int Render::DrawMainWindow() {
UpdateNotificationWindow(); UpdateNotificationWindow();
#ifdef __APPLE__
if (show_request_permission_window_) {
RequestPermissionWindow();
}
#endif
ImGui::End(); ImGui::End();
// Rendering // Rendering
ImGuiIO& io = ImGui::GetIO();
(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_);
@@ -964,6 +920,7 @@ int Render::DrawStreamWindow() {
StreamWindow(); StreamWindow();
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::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(stream_window_width_, ImVec2(stream_window_width_,
@@ -974,19 +931,16 @@ int Render::DrawStreamWindow() {
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoDocking); ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor();
TitleBar(false); TitleBar(false);
ImGui::End(); ImGui::End();
} }
// Rendering // Rendering
ImGuiIO& io = ImGui::GetIO();
(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_) {
@@ -1051,8 +1005,6 @@ int Render::Run() {
} }
InitializeLogger(); InitializeLogger();
LOG_INFO("CrossDesk version: {}", CROSSDESK_VERSION);
InitializeSettings(); InitializeSettings();
InitializeSDL(); InitializeSDL();
InitializeModules(); InitializeModules();
@@ -1117,6 +1069,7 @@ 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_);
} }
@@ -1227,6 +1180,7 @@ 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;
} }
@@ -1321,18 +1275,12 @@ void Render::CleanupPeers() {
DestroyPeer(&peer_); DestroyPeer(&peer_);
} }
{ for (auto& it : client_properties_) {
// std::shared_lock lock(client_properties_mutex_); auto props = it.second;
for (auto& it : client_properties_) { CleanupPeer(props);
auto props = it.second;
CleanupPeer(props);
}
} }
{ client_properties_.clear();
// std::unique_lock lock(client_properties_mutex_);
client_properties_.clear();
}
} }
void Render::CleanSubStreamWindowProperties( void Render::CleanSubStreamWindowProperties(
@@ -1349,7 +1297,6 @@ 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;
@@ -1424,41 +1371,34 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
DestroyStreamWindow(); DestroyStreamWindow();
DestroyStreamWindowContext(); DestroyStreamWindowContext();
{ for (auto& [host_name, props] : client_properties_) {
// std::shared_lock lock(client_properties_mutex_); thumbnail_->SaveToThumbnail(
for (auto& [host_name, props] : client_properties_) { (char*)props->dst_buffer_, props->video_width_,
thumbnail_->SaveToThumbnail( props->video_height_, host_name, props->remote_host_name_,
(char*)props->dst_buffer_, props->video_width_, props->remember_password_ ? props->remote_password_ : "");
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;
// std::unique_lock lock(client_properties_mutex_); props->remember_password_ = false;
client_properties_.clear(); 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();
rejoin_ = false; rejoin_ = false;
is_client_mode_ = false; is_client_mode_ = false;

View File

@@ -15,7 +15,6 @@
#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>
@@ -31,7 +30,6 @@
#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
@@ -71,10 +69,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_ = 38; float control_window_min_height_ = 40;
float control_window_max_height_ = 180; float control_window_max_height_ = 170;
float control_window_width_ = 230; float control_window_width_ = 230;
float control_window_height_ = 38; float control_window_height_ = 40;
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;
@@ -175,13 +173,14 @@ class Render {
private: private:
int ConnectTo(const std::string& remote_id, const char* password, int ConnectTo(const std::string& remote_id, const char* password,
bool remember_password); bool remember_password);
int UpdateWindowSizeWithDpiScale(float dpi_scale);
int CreateMainWindow(); int CreateMainWindow();
int DestroyMainWindow(); int DestroyMainWindow();
int CreateStreamWindow(); int CreateStreamWindow();
int DestroyStreamWindow(); int DestroyStreamWindow();
int SetupFontAndStyle(bool main_window); int SetupFontAndStyle();
int SetupMainWindow();
int DestroyMainWindowContext(); int DestroyMainWindowContext();
int SetupStreamWindow();
int DestroyStreamWindowContext(); int DestroyStreamWindowContext();
int DrawMainWindow(); int DrawMainWindow();
int DrawStreamWindow(); int DrawStreamWindow();
@@ -189,14 +188,6 @@ 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,
@@ -313,8 +304,7 @@ 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* main_windows_system_chinese_font_ = nullptr; ImFont* system_chinese_font_ = nullptr; // System Chinese font for fallback
ImFont* stream_windows_system_chinese_font_ = nullptr;
bool exit_ = false; bool exit_ = false;
const int sdl_refresh_ms_ = 16; // ~60 FPS const int sdl_refresh_ms_ = 16; // ~60 FPS
#if _WIN32 #if _WIN32
@@ -342,7 +332,6 @@ 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;
@@ -382,7 +371,6 @@ 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_ = "";
@@ -461,9 +449,6 @@ 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] = "";
@@ -507,7 +492,6 @@ 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 ------ */

View File

@@ -21,16 +21,13 @@ 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();
if (props->peer_) { SendDataFrame(props->peer_, msg.c_str(), msg.size(),
SendDataFrame(props->peer_, msg.c_str(), msg.size(), props->data_label_.c_str());
props->data_label_.c_str());
}
} }
} }
} }
@@ -45,7 +42,6 @@ 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_) {
@@ -98,10 +94,8 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
} }
std::string msg = remote_action.to_json(); std::string msg = remote_action.to_json();
if (props->peer_) { SendDataFrame(props->peer_, msg.c_str(), msg.size(),
SendDataFrame(props->peer_, msg.c_str(), msg.size(), props->data_label_.c_str());
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 +
@@ -145,10 +139,8 @@ 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();
if (props->peer_) { SendDataFrame(props->peer_, msg.c_str(), msg.size(),
SendDataFrame(props->peer_, msg.c_str(), msg.size(), props->data_label_.c_str());
props->data_label_.c_str());
}
} }
} }
@@ -162,14 +154,11 @@ void Render::SdlCaptureAudioIn(void* userdata, Uint8* stream, int len) {
} }
if (1) { if (1) {
// std::shared_lock lock(render->client_properties_mutex_); for (auto it : render->client_properties_) {
for (const auto& it : render->client_properties_) {
auto props = it.second; auto props = it.second;
if (props->connection_status_ == ConnectionStatus::Connected) { if (props->connection_status_ == ConnectionStatus::Connected) {
if (props->peer_) { SendAudioFrame(props->peer_, (const char*)stream, len,
SendAudioFrame(props->peer_, (const char*)stream, len, render->audio_label_.c_str());
render->audio_label_.c_str());
}
} }
} }
@@ -218,7 +207,6 @@ 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;
@@ -314,7 +302,6 @@ 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
@@ -386,7 +373,6 @@ 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;
@@ -416,7 +402,6 @@ 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;
@@ -443,7 +428,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_ && props->stream_texture_) { if (props->dst_buffer_) {
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_);
@@ -484,12 +469,12 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
render->need_to_send_host_info_ = true; render->need_to_send_host_info_ = true;
render->start_screen_capturer_ = true; render->start_screen_capturer_ = true;
render->start_speaker_capturer_ = true; render->start_speaker_capturer_ = true;
#ifdef CROSSDESK_DEBUG // #ifdef CROSSDESK_DEBUG
render->start_mouse_controller_ = false; // render->start_mouse_controller_ = false;
render->start_keyboard_capturer_ = false; // render->start_keyboard_capturer_ = false;
#else // #else
render->start_mouse_controller_ = true; render->start_mouse_controller_ = true;
#endif // #endif
if (std::all_of(render->connection_status_.begin(), if (std::all_of(render->connection_status_.begin(),
render->connection_status_.end(), [](const auto& kv) { render->connection_status_.end(), [](const auto& kv) {
return kv.first.find("web") != std::string::npos; return kv.first.find("web") != std::string::npos;
@@ -577,7 +562,6 @@ 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,33 +32,26 @@ 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 * dpi_scale_); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
if (props->control_bar_expand_) { if (props->control_bar_expand_) {
float button_width = 24.0f * dpi_scale_; ImGui::SetCursorPosX(props->is_control_bar_in_left_
float button_height = 24.0f * dpi_scale_; ? (props->control_window_width_ + 5.0f)
float line_padding = 4.0f * dpi_scale_; : 38.0f);
ImGui::SetCursorPosX(
props->is_control_bar_in_left_
? (props->control_window_width_ + 5.0f * dpi_scale_)
: 50.0f * dpi_scale_);
// mouse control button // mouse control button
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (props->is_control_bar_in_left_) { if (props->is_control_bar_in_left_) {
draw_list->AddLine( draw_list->AddLine(ImVec2(ImGui::GetCursorScreenPos().x - 5.0f,
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f * dpi_scale_, ImGui::GetCursorScreenPos().y - 7.0f),
ImGui::GetCursorScreenPos().y - 7.0f * dpi_scale_), ImVec2(ImGui::GetCursorScreenPos().x - 5.0f,
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f * dpi_scale_, ImGui::GetCursorScreenPos().y - 7.0f +
ImGui::GetCursorScreenPos().y - 7.0f * dpi_scale_ + props->control_window_height_),
props->control_window_height_), IM_COL32(178, 178, 178, 255), 1.0f);
IM_COL32(178, 178, 178, 255), 1.0f);
} }
std::string display = ICON_FA_DISPLAY; std::string display = ICON_FA_DISPLAY;
ImGui::SetWindowFontScale(0.5f); if (ImGui::Button(display.c_str(), ImVec2(25, 25))) {
if (ImGui::Button(display.c_str(), ImVec2(button_width, button_height))) {
ImGui::OpenPopup("display"); ImGui::OpenPopup("display");
} }
@@ -82,10 +75,11 @@ 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.5f); ImGui::SetWindowFontScale(0.6f);
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 =
@@ -94,16 +88,15 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
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 mouse_x = ImGui::GetCursorScreenPos().x; float disable_mouse_x = ImGui::GetCursorScreenPos().x + 4.0f;
float mouse_y = ImGui::GetCursorScreenPos().y; float disable_mouse_y = ImGui::GetCursorScreenPos().y + 4.0f;
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(button_width, button_height))) { if (ImGui::Button(mouse.c_str(), ImVec2(25, 25))) {
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_;
@@ -115,35 +108,30 @@ 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_) {
float line_thickness = 2.0f * dpi_scale_;
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 - line_thickness * 0.7f, ImVec2(disable_mouse_x, disable_mouse_y),
disable_mouse_y + line_thickness * 0.7f), ImVec2(disable_mouse_x + 16.0f, disable_mouse_y + 14.2f),
ImVec2( IM_COL32(0, 0, 0, 255), 2.0f);
mouse_x + button_width - line_padding - line_thickness * 0.7f, draw_list->AddLine(
mouse_y + button_height - line_padding + line_thickness * 0.7f), ImVec2(disable_mouse_x - 1.2f, disable_mouse_y + 1.2f),
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),
line_thickness); 2.0f);
} }
ImGui::SameLine(); ImGui::SameLine();
// audio capture button // audio capture button
float audio_x = ImGui::GetCursorScreenPos().x; float disable_audio_x = ImGui::GetCursorScreenPos().x + 4;
float audio_y = ImGui::GetCursorScreenPos().y; float disable_audio_y = ImGui::GetCursorScreenPos().y + 4.0f;
float disable_audio_x = audio_x + line_padding; // std::string audio = audio_capture_button_pressed_ ? ICON_FA_VOLUME_HIGH
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(button_width, button_height))) { if (ImGui::Button(audio.c_str(), ImVec2(25, 25))) {
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_;
@@ -160,22 +148,17 @@ 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_) {
float line_thickness = 2.0f * dpi_scale_;
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 - line_thickness * 0.7f, ImVec2(disable_audio_x, disable_audio_y),
disable_audio_y + line_thickness * 0.7f), ImVec2(disable_audio_x + 16.0f, disable_audio_y + 14.2f),
ImVec2( IM_COL32(0, 0, 0, 255), 2.0f);
audio_x + button_width - line_padding - line_thickness * 0.7f, draw_list->AddLine(
audio_y + button_height - line_padding + line_thickness * 0.7f), ImVec2(disable_audio_x - 1.2f, disable_audio_y + 1.2f),
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),
line_thickness); 2.0f);
} }
ImGui::SameLine(); ImGui::SameLine();
@@ -187,8 +170,7 @@ 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(), if (ImGui::Button(net_traffic_stats.c_str(), ImVec2(25, 25))) {
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;
@@ -200,7 +182,6 @@ 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;
@@ -210,8 +191,7 @@ 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(), if (ImGui::Button(fullscreen.c_str(), ImVec2(25, 25))) {
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_
@@ -229,8 +209,7 @@ 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(), if (ImGui::Button(close_button.c_str(), ImVec2(25, 25))) {
ImVec2(button_width, button_height))) {
CleanupPeer(props); CleanupPeer(props);
} }
@@ -246,10 +225,9 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
} }
} }
ImGui::SetCursorPosX( ImGui::SetCursorPosX(props->is_control_bar_in_left_
props->is_control_bar_in_left_ ? (props->control_window_width_ * 2 - 20.0f)
? (props->control_window_width_ * 2 - 20.0f * dpi_scale_) : 5.0f);
: 5.0f * dpi_scale_);
std::string control_bar = std::string control_bar =
props->control_bar_expand_ props->control_bar_expand_
@@ -257,14 +235,13 @@ 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(), if (ImGui::Button(control_bar.c_str(), ImVec2(15, 25))) {
ImVec2(15.0f * dpi_scale_, 25.0f * dpi_scale_))) {
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_ = 35 * dpi_scale_; props->control_window_height_ = 40;
props->net_traffic_stats_button_pressed_ = false; props->net_traffic_stats_button_pressed_ = false;
} }
} }
@@ -282,7 +259,8 @@ 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_ + 5.0f)
: 5.0f, : 5.0f,
35.0f * dpi_scale_)); 40.0f));
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_ - 10.0f,
props->control_window_max_height_ - 60.0f))) { props->control_window_max_height_ - 60.0f))) {

View File

@@ -7,7 +7,7 @@ int Render::StatusBar() {
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, main_window_height_ - status_bar_height_ - 1), ImVec2(0, main_window_height_default_ - status_bar_height_ - 1),
ImGuiCond_Always); ImGuiCond_Always);
ImGui::BeginChild( ImGui::BeginChild(
@@ -15,20 +15,18 @@ int Render::StatusBar() {
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImVec2 dot_pos = ImVec2(13.0f * dpi_scale_, ImVec2 dot_pos =
(main_window_height_ - status_bar_height_) * 1.025f); ImVec2(13, main_window_height_default_ - status_bar_height_ + 11.0f);
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddCircleFilled(dot_pos, 5.0f * dpi_scale_, draw_list->AddCircleFilled(dot_pos, 5.0f,
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 * dpi_scale_, ImColor(1.0f, 1.0f, 1.0f), draw_list->AddCircle(dot_pos, 6.0f, ImColor(1.0f, 1.0f, 1.0f), 100);
100);
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.6f);
draw_list->AddText( draw_list->AddText(
ImVec2(25.0f * dpi_scale_, ImVec2(25, main_window_height_default_ - status_bar_height_ + 3.0f),
(main_window_height_ - status_bar_height_) * 1.003f),
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

@@ -2,7 +2,7 @@
#include "rd_log.h" #include "rd_log.h"
#include "render.h" #include "render.h"
#define BUTTON_PADDING 36.0f * dpi_scale_ #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 {
@@ -11,6 +11,7 @@ int Render::TitleBar(bool main_window) {
ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1.0f, 1.0f, 1.0f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always); ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetWindowFontScale(0.8f);
ImGui::BeginChild( ImGui::BeginChild(
main_window ? "MainTitleBar" : "StreamTitleBar", main_window ? "MainTitleBar" : "StreamTitleBar",
ImVec2(main_window ? main_window_width_ : stream_window_width_, ImVec2(main_window ? main_window_width_ : stream_window_width_,
@@ -18,24 +19,23 @@ int Render::TitleBar(bool main_window) {
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus); ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenuBar()) {
ImGui::SetWindowFontScale(0.8f);
ImGui::SetCursorPosX( ImGui::SetCursorPosX(
(main_window ? main_window_width_ : stream_window_width_) - (main_window ? main_window_width_ : stream_window_width_) -
(BUTTON_PADDING * 3 - 3.0f * dpi_scale_)); (BUTTON_PADDING * 3 - 3));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0, 0, 0, 0.1f)); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImGui::PushStyleColor(ImGuiCol_HeaderActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (main_window) { if (main_window) {
float bar_pos_x = ImGui::GetCursorPosX() + 6 * dpi_scale_; float bar_pos_x = ImGui::GetCursorPosX() + 6;
float bar_pos_y = ImGui::GetCursorPosY() + 15 * dpi_scale_; float bar_pos_y = ImGui::GetCursorPosY() + 15;
std::string menu_button = " "; // ICON_FA_BARS; std::string menu_button = " "; // ICON_FA_BARS;
if (ImGui::BeginMenu(menu_button.c_str())) { if (ImGui::BeginMenu(menu_button.c_str())) {
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.5f);
if (ImGui::MenuItem( if (ImGui::MenuItem(
localization::settings[localization_language_index_].c_str())) { localization::settings[localization_language_index_].c_str())) {
show_settings_window_ = true; show_settings_window_ = true;
@@ -77,7 +77,7 @@ int Render::TitleBar(bool main_window) {
if (update_available_ && ImGui::IsItemHovered()) { if (update_available_ && ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::SetWindowFontScale(0.5f * dpi_scale_); ImGui::SetWindowFontScale(0.5f);
std::string new_version_available_str = std::string new_version_available_str =
localization::new_version_available localization::new_version_available
[localization_language_index_] + [localization_language_index_] +
@@ -87,12 +87,13 @@ int Render::TitleBar(bool main_window) {
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::SetWindowFontScale(1.0f);
ImGui::EndMenu(); ImGui::EndMenu();
} else { } else {
show_new_version_icon_in_menu_ = true; show_new_version_icon_in_menu_ = true;
} }
float menu_bar_line_size = 15.0f * dpi_scale_; float menu_bar_line_size = 15.0f;
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y - 6), draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y - 6),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y - 6), ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y - 6),
IM_COL32(0, 0, 0, 255)); IM_COL32(0, 0, 0, 255));
@@ -135,8 +136,6 @@ int Render::TitleBar(bool main_window) {
SelfHostedServerWindow(); SelfHostedServerWindow();
AboutWindow(); AboutWindow();
} }
} else {
ImGui::SetWindowFontScale(1.2f);
} }
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
@@ -149,15 +148,15 @@ int Render::TitleBar(bool main_window) {
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.0f * dpi_scale_; float minimize_pos_x = ImGui::GetCursorPosX() + 12;
float minimize_pos_y = ImGui::GetCursorPosY() + 15.0f * dpi_scale_; float minimize_pos_y = ImGui::GetCursorPosY() + 15;
std::string window_minimize_button = "##minimize"; // ICON_FA_MINUS; std::string window_minimize_button = "##minimize"; // ICON_FA_MINUS;
if (ImGui::Button(window_minimize_button.c_str(), if (ImGui::Button(window_minimize_button.c_str(),
ImVec2(BUTTON_PADDING, 30.0f * dpi_scale_))) { ImVec2(BUTTON_PADDING, 30))) {
SDL_MinimizeWindow(main_window ? main_window_ : stream_window_); SDL_MinimizeWindow(main_window ? main_window_ : stream_window_);
} }
draw_list->AddLine(ImVec2(minimize_pos_x, minimize_pos_y), draw_list->AddLine(ImVec2(minimize_pos_x, minimize_pos_y),
ImVec2(minimize_pos_x + 12 * dpi_scale_, minimize_pos_y), ImVec2(minimize_pos_x + 12, minimize_pos_y),
IM_COL32(0, 0, 0, 255)); IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(2); ImGui::PopStyleColor(2);
@@ -168,36 +167,33 @@ int Render::TitleBar(bool main_window) {
ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (window_maximized_) { if (window_maximized_) {
float pos_x_top = ImGui::GetCursorPosX() + 11 * dpi_scale_; float pos_x_top = ImGui::GetCursorPosX() + 11;
float pos_y_top = ImGui::GetCursorPosY() + 11 * dpi_scale_; float pos_y_top = ImGui::GetCursorPosY() + 11;
float pos_x_bottom = ImGui::GetCursorPosX() + 13 * dpi_scale_; float pos_x_bottom = ImGui::GetCursorPosX() + 13;
float pos_y_bottom = ImGui::GetCursorPosY() + 9 * dpi_scale_; float pos_y_bottom = ImGui::GetCursorPosY() + 9;
std::string window_restore_button = std::string window_restore_button =
"##restore"; // ICON_FA_WINDOW_RESTORE; "##restore"; // ICON_FA_WINDOW_RESTORE;
if (ImGui::Button(window_restore_button.c_str(), if (ImGui::Button(window_restore_button.c_str(),
ImVec2(BUTTON_PADDING, 30.0f * dpi_scale_))) { ImVec2(BUTTON_PADDING, 30))) {
SDL_RestoreWindow(stream_window_); SDL_RestoreWindow(stream_window_);
window_maximized_ = false; window_maximized_ = false;
} }
draw_list->AddRect( draw_list->AddRect(ImVec2(pos_x_top, pos_y_top),
ImVec2(pos_x_top, pos_y_top), ImVec2(pos_x_top + 12, pos_y_top + 12),
ImVec2(pos_x_top + 12 * dpi_scale_, pos_y_top + 12 * dpi_scale_),
IM_COL32(0, 0, 0, 255));
draw_list->AddRect(ImVec2(pos_x_bottom, pos_y_bottom),
ImVec2(pos_x_bottom + 12 * dpi_scale_,
pos_y_bottom + 12 * dpi_scale_),
IM_COL32(0, 0, 0, 255)); IM_COL32(0, 0, 0, 255));
draw_list->AddRectFilled( draw_list->AddRect(ImVec2(pos_x_bottom, pos_y_bottom),
ImVec2(pos_x_top + 1 * dpi_scale_, pos_y_top + 1 * dpi_scale_), ImVec2(pos_x_bottom + 12, pos_y_bottom + 12),
ImVec2(pos_x_top + 11 * dpi_scale_, pos_y_top + 11 * dpi_scale_), IM_COL32(0, 0, 0, 255));
IM_COL32(255, 255, 255, 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 { } else {
float maximize_pos_x = ImGui::GetCursorPosX() + 12 * dpi_scale_; float maximize_pos_x = ImGui::GetCursorPosX() + 12;
float maximize_pos_y = ImGui::GetCursorPosY() + 10 * dpi_scale_; float maximize_pos_y = ImGui::GetCursorPosY() + 10;
std::string window_maximize_button = std::string window_maximize_button =
"##maximize"; // ICON_FA_SQUARE_FULL; "##maximize"; // ICON_FA_SQUARE_FULL;
if (ImGui::Button(window_maximize_button.c_str(), if (ImGui::Button(window_maximize_button.c_str(),
ImVec2(BUTTON_PADDING, 30.0f * dpi_scale_))) { ImVec2(BUTTON_PADDING, 30))) {
SDL_MaximizeWindow(stream_window_); SDL_MaximizeWindow(stream_window_);
window_maximized_ = !window_maximized_; window_maximized_ = !window_maximized_;
} }
@@ -214,12 +210,11 @@ int Render::TitleBar(bool main_window) {
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f));
float xmark_pos_x = ImGui::GetCursorPosX() + 18 * dpi_scale_; float xmark_pos_x = ImGui::GetCursorPosX() + 18;
float xmark_pos_y = ImGui::GetCursorPosY() + 16 * dpi_scale_; float xmark_pos_y = ImGui::GetCursorPosY() + 16;
float xmark_size = 12.0f * dpi_scale_; float xmark_size = 12.0f;
std::string close_button = "##xmark"; // ICON_FA_XMARK; std::string close_button = "##xmark"; // ICON_FA_XMARK;
if (ImGui::Button(close_button.c_str(), if (ImGui::Button(close_button.c_str(), ImVec2(BUTTON_PADDING, 30))) {
ImVec2(BUTTON_PADDING, 30.0f * dpi_scale_))) {
#if _WIN32 #if _WIN32
if (enable_minimize_to_tray_) { if (enable_minimize_to_tray_) {
tray_->MinimizeToTray(); tray_->MinimizeToTray();

View File

@@ -202,6 +202,7 @@ 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";
@@ -209,6 +210,7 @@ int Render::ControlWindow(std::shared_ptr<SubStreamWindowProperties>& props) {
control_child_window_title.c_str(), control_child_window_title.c_str(),
ImVec2(props->control_window_width_ * 2, props->control_window_height_), ImVec2(props->control_window_width_ * 2, 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

@@ -38,9 +38,10 @@ int Render::SettingWindow() {
// Settings // Settings
{ {
static int settings_items_padding = 30 * dpi_scale_; static int settings_items_padding = 30;
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);
@@ -49,6 +50,7 @@ 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);
{ {
@@ -57,7 +59,7 @@ 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 * dpi_scale_); ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::Text( ImGui::Text(
"%s", localization::language[localization_language_index_].c_str()); "%s", localization::language[localization_language_index_].c_str());
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) { if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
@@ -68,17 +70,8 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH); ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo("##language", ImGui::Combo("##language", &language_button_value_, language_items,
language_items[language_button_value_])) { IM_ARRAYSIZE(language_items));
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();
@@ -97,7 +90,7 @@ 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 * dpi_scale_); ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::Text( ImGui::Text(
"%s", "%s",
localization::video_quality[localization_language_index_].c_str()); localization::video_quality[localization_language_index_].c_str());
@@ -110,18 +103,8 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH); ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo( ImGui::Combo("##video_quality", &video_quality_button_value_,
"##video_quality", video_quality_items, IM_ARRAYSIZE(video_quality_items));
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();
@@ -143,18 +126,9 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH); ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo( ImGui::Combo("##video_frame_rate", &video_frame_rate_button_value_,
"##video_frame_rate", video_frame_rate_items,
video_frame_rate_items[video_frame_rate_button_value_])) { IM_ARRAYSIZE(video_frame_rate_items));
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();
@@ -179,18 +153,9 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset); ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH); ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo( ImGui::Combo(
"##video_encode_format", "##video_encode_format", &video_encode_format_button_value_,
video_encode_format_items[video_encode_format_button_value_])) { video_encode_format_items, IM_ARRAYSIZE(video_encode_format_items));
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 USE_CUDA && !defined(__aarch64__) && !defined(__arm__)
@@ -503,10 +468,12 @@ 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

@@ -9,7 +9,7 @@ int Render::MainWindow() {
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("DeskWindow",
ImVec2(main_window_width_, local_window_height_), ImVec2(main_window_width_default_, local_window_height_),
ImGuiChildFlags_Border, ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -21,8 +21,8 @@ int Render::MainWindow() {
ImDrawList* draw_list = ImGui::GetWindowDrawList(); ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine( draw_list->AddLine(
ImVec2(main_window_width_ / 2, title_bar_height_ + 15.0f * dpi_scale_), ImVec2(main_window_width_default_ / 2, title_bar_height_ + 15.0f),
ImVec2(main_window_width_ / 2, title_bar_height_ + 225.0f * dpi_scale_), 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();
@@ -32,7 +32,6 @@ 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

@@ -1,205 +0,0 @@
#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,13 +54,12 @@ 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 * dpi_scale_; float fixed_width = 130.0f;
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();
@@ -155,7 +154,7 @@ int Render::SelfHostedServerWindow() {
// Settings // Settings
{ {
static int settings_items_padding = 30 * dpi_scale_; static int settings_items_padding = 30;
int settings_items_offset = 0; int settings_items_offset = 0;
ImGui::SetWindowFontScale(0.5f); ImGui::SetWindowFontScale(0.5f);

View File

@@ -32,15 +32,12 @@ void Render::DrawConnectionStatusText(
} }
void Render::CloseTab(decltype(client_properties_)::iterator& it) { void Render::CloseTab(decltype(client_properties_)::iterator& it) {
// std::unique_lock lock(client_properties_mutex_); CleanupPeer(it->second);
if (it != client_properties_.end()) { it = client_properties_.erase(it);
CleanupPeer(it->second); if (client_properties_.empty()) {
it = client_properties_.erase(it); SDL_Event event;
if (client_properties_.empty()) { event.type = SDL_EVENT_QUIT;
SDL_Event event; SDL_PushEvent(&event);
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
} }
} }
@@ -53,24 +50,20 @@ 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));
bool video_bg_opened = ImGui::Begin( ImGui::Begin("VideoBg", nullptr,
"VideoBg", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoDocking); 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.0f * dpi_scale_, 0), ImGuiCond_Always); ImGui::SetNextWindowPos(ImVec2(20, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(0, 30.0f * dpi_scale_), ImGuiCond_Always); ImGui::SetNextWindowSize(ImVec2(0, 20), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 8.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));
@@ -86,32 +79,22 @@ 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_) {
std::string remote_id_to_close = props->remote_id_; CloseTab(it);
// 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(0.6f * dpi_scale_); ImGui::SetWindowFontScale(1.0f);
ImGui::SetNextWindowSize( ImGui::SetNextWindowSize(
ImVec2(stream_window_width_, stream_window_height_), ImVec2(stream_window_width_, stream_window_height_),
@@ -139,25 +122,12 @@ int Render::StreamWindow() {
focused_remote_id_ = props->remote_id_; focused_remote_id_ = props->remote_id_;
if (!props->peer_) { if (!props->peer_) {
std::string remote_id_to_erase = props->remote_id_; it = client_properties_.erase(it);
// lock.unlock(); if (client_properties_.empty()) {
{ SDL_Event event;
// std::unique_lock unique_lock(client_properties_mutex_); event.type = SDL_EVENT_QUIT;
auto erase_it = client_properties_.find(remote_id_to_erase); SDL_PushEvent(&event);
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;
@@ -167,6 +137,7 @@ int Render::StreamWindow() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} else { } else {
props->tab_selected_ = false; props->tab_selected_ = false;
ImGui::SetWindowFontScale(1.0f);
++it; ++it;
} }
} }
@@ -176,22 +147,11 @@ 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_) {
std::string remote_id_to_close = props->remote_id_; CloseTab(it);
// 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;
} }
@@ -221,23 +181,12 @@ 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);
std::string remote_id_to_erase = props->remote_id_; it = client_properties_.erase(it);
// lock.unlock(); if (client_properties_.empty()) {
{ SDL_Event event;
// std::unique_lock unique_lock(client_properties_mutex_); event.type = SDL_EVENT_QUIT;
auto erase_it = client_properties_.find(remote_id_to_erase); SDL_PushEvent(&event);
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

@@ -58,15 +58,6 @@ int Render::UpdateNotificationWindow() {
float window_width = update_notification_window_width_; float window_width = update_notification_window_width_;
float window_height = update_notification_window_height_; float window_height = update_notification_window_height_;
// #ifdef __APPLE__
// float font_scale = 0.3f;
// #else
// float font_scale = 0.5f;
// #endif
float button_width = 35.0f * dpi_scale_;
float button_height = 25.0f * dpi_scale_;
ImGui::SetNextWindowPos( ImGui::SetNextWindowPos(
ImVec2( ImVec2(
(viewport->WorkSize.x - viewport->WorkPos.x - window_width) / 2, (viewport->WorkSize.x - viewport->WorkPos.x - window_width) / 2,
@@ -79,22 +70,29 @@ int Render::UpdateNotificationWindow() {
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_NoTitleBar); ImGuiWindowFlags_NoSavedSettings);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + window_height * 0.05f); ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f);
// 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(window_width * 0.1f);
ImGui::SetWindowFontScale(0.6f); ImGui::SetWindowFontScale(0.7f);
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.1f); ImGui::SetWindowFontScale(0.5f);
ImGui::Spacing(); ImGui::Spacing();
@@ -102,24 +100,19 @@ 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";
ImGui::SetWindowFontScale(0.5f);
Hyperlink(download_text, "https://crossdesk.cn", window_width); Hyperlink(download_text, "https://crossdesk.cn", window_width);
ImGui::SetWindowFontScale(1.0f);
ImGui::Spacing(); ImGui::Spacing();
float scrollable_height = float reserved_height = 140.0f;
window_height - UPDATE_NOTIFICATION_RESERVED_HEIGHT; float scrollable_height = window_height - 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(window_width * 0.05f);
ImGui::BeginChild("ScrollableContent", ImGui::BeginChild("ScrollableContent",
ImVec2(window_width * 0.9f, scrollable_height), ImVec2(window_width * 0.9f, scrollable_height),
ImGuiChildFlags_Border, ImGuiWindowFlags_None); ImGuiChildFlags_Border, ImGuiWindowFlags_None);
ImGui::SetWindowFontScale(0.6f);
// 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;
@@ -162,11 +155,6 @@ 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_) {
@@ -175,11 +163,9 @@ int Render::UpdateNotificationWindow() {
ImGui::SetCursorPosX(UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN); ImGui::SetCursorPosX(UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN);
} }
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())) {
ImVec2(button_width, button_height))) {
// open download page // open download page
std::string url = "https://crossdesk.cn"; std::string url = "https://crossdesk.cn";
#if defined(_WIN32) #if defined(_WIN32)
@@ -196,14 +182,20 @@ int Render::UpdateNotificationWindow() {
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button( if (ImGui::Button(
localization::cancel[localization_language_index_].c_str(), localization::cancel[localization_language_index_].c_str())) {
ImVec2(button_width, button_height))) {
show_update_notification_window_ = false; show_update_notification_window_ = false;
} }
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() / "logs"; return GetCachePath() / app_name_ / "logs";
#endif #endif
} }

View File

@@ -1,9 +1,6 @@
#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,14 +7,10 @@
#ifndef _SCREEN_CAPTURER_X11_H_ #ifndef _SCREEN_CAPTURER_X11_H_
#define _SCREEN_CAPTURER_X11_H_ #define _SCREEN_CAPTURER_X11_H_
// forward declarations for X11 types #include <X11/Xlib.h>
struct _XDisplay; #include <X11/Xutil.h>
typedef struct _XDisplay Display; #include <X11/extensions/Xrandr.h>
typedef unsigned long Window; #include <X11/extensions/Xfixes.h>
struct _XRRScreenResources;
typedef struct _XRRScreenResources XRRScreenResources;
struct _XImage;
typedef struct _XImage XImage;
#include <atomic> #include <atomic>
#include <cstring> #include <cstring>
@@ -47,9 +43,6 @@ 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;
@@ -67,8 +60,12 @@ 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,15 +196,6 @@ 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;
@@ -214,8 +205,7 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
getShareableContentWithCompletionHandler:^(SCShareableContent *result, NSError *error) { getShareableContentWithCompletionHandler:^(SCShareableContent *result, NSError *error) {
if (error) { if (error) {
capture_error = error; capture_error = error;
LOG_ERROR("Failed to get shareable content: {}", NSLog(@"Failed to get shareable content: %@", error);
std::string([error.localizedDescription UTF8String]));
} else { } else {
content = result; content = result;
} }
@@ -223,10 +213,16 @@ 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 (capture_error || !content || content.displays.count == 0) { if (capture_error) {
LOG_ERROR("Failed to get display info, error: {}", NSString *error_desc = capture_error.localizedDescription ?: @"Unknown error";
std::string([capture_error.localizedDescription UTF8String])); LOG_ERROR("Failed to get shareable content: {}",
return -1; std::string([error_desc UTF8String]));
return 0;
}
if (!content || content.displays.count == 0) {
LOG_ERROR("Failed to get display info: content is nil or no displays available");
return 0;
} }
CGDirectDisplayID displays[10]; CGDirectDisplayID displays[10];
@@ -265,16 +261,6 @@ 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;
@@ -330,17 +316,17 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
return; return;
} }
if (!content.displays || content.displays.count == 0) { if (!content.displays.count) {
LOG_ERROR("getShareableContent returned no displays"); LOG_ERROR("getShareableContent returned no displays");
permanent_error_ = true; permanent_error_ = true;
return; return;
} }
SCDisplay *captured_display = nil; SCDisplay *captured_display;
{ {
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_ != 0 && current_display_ == display.displayID) { if (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;
@@ -349,33 +335,13 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
} }
if (!captured_display) { if (!captured_display) {
captured_display = content.displays.firstObject; captured_display = content.displays.firstObject;
if (captured_display) { current_display_ = captured_display.displayID;
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;
@@ -466,28 +432,11 @@ void ScreenCapturerSckImpl::OnNewCVPixelBuffer(CVPixelBufferRef pixelBuffer,
} }
void ScreenCapturerSckImpl::StartOrReconfigureCapturer() { void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
if (permanent_error_) { // The copy is needed to avoid capturing `this` in the Objective-C block. Accessing `helper_`
LOG_ERROR("Cannot reconfigure capturer: permanent error occurred"); // inside the block is equivalent to `this->helper_` and would crash (UAF) if `this` is
return; // deleted before the block is executed.
}
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,14 +77,12 @@ 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;
} }
} }
@@ -217,14 +215,13 @@ 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;
} }
@@ -259,61 +256,18 @@ 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 (id < 0 || id >= static_cast<int>(display_info_list_.size())) { if (!nv12_frame_) {
LOG_ERROR("WGC OnFrame invalid display index: {}", id); nv12_frame_ = new unsigned char[frame.width * frame.height * 3 / 2];
return;
} }
if (!frame.data || frame.row_pitch == 0) { libyuv::ARGBToNV12((const uint8_t*)frame.data, frame.width * 4,
LOG_ERROR("WGC OnFrame received invalid frame: data={}, row_pitch={}", (uint8_t*)nv12_frame_, frame.width,
(void*)frame.data, frame.row_pitch); (uint8_t*)(nv12_frame_ + frame.width * frame.height),
return; frame.width, frame.width, frame.height);
}
// calculate the maximum width that can be contained in one row according to on_data_(nv12_frame_, frame.width * frame.height * 3 / 2, frame.width,
// row_pitch (BGRA: 4 bytes per pixel), and take the minimum with logical frame.height, display_info_list_[id].name.c_str());
// 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,7 +3,6 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector> #include <vector>
@@ -66,10 +65,6 @@ 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,50 +38,8 @@ 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();
@@ -90,7 +48,6 @@ class SpeakerCapturerMacosx;
} }
} }
} }
@end @end
namespace crossdesk { namespace crossdesk {

View File

@@ -156,12 +156,6 @@ 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,8 +33,6 @@ 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.92.1-docking", {configs = {sdl3 = true, sdl3_renderer = true}}) add_requires("imgui v1.91.5-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,8 +182,6 @@ 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")