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/
build/
certs/
# MacOS Cache
.DS_Store
# VSCode cache
.vscode
.vscode
continuous-desk.code-workspace

View File

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

View File

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

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

@@ -78,6 +78,14 @@ EOF
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..."
pkgbuild \
--identifier "${IDENTIFIER}" \
@@ -86,66 +94,54 @@ pkgbuild \
--component "${APP_BUNDLE}" \
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
set -e
IDENTIFIER="cn.crossdesk.app"
APP_NAME="CrossDesk"
APP_PATH="/Applications/${APP_NAME}.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 复制证书文件
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
mkdir -p "$DEST"
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
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
if [ -d "/Library/Application Support/CrossDesk/certs" ]; then
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
if [ -d "$APP_PATH" ]; then
touch "$APP_PATH"
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$APP_PATH" 2>/dev/null || true
USER_ID=$(dscl . -read /Users/$USER_HOME UniqueID 2>/dev/null | awk '{print $2}')
if [ -n "$USER_ID" ]; then
sleep 1
launchctl asuser $USER_ID open "$APP_PATH" 2>/dev/null &
APP_PID=$!
sleep 3
kill "$APP_PID" 2>/dev/null || pkill -f "${APP_NAME}" 2>/dev/null || true
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
EOF
chmod +x build_pkg_scripts/postinstall
chmod +x scripts/postinstall
pkgbuild \
--root "${CERTS_SOURCE}" \
--identifier "${IDENTIFIER}.certs" \
--version "${APP_VERSION}" \
--install-location "/Library/Application Support/CrossDesk/certs" \
--scripts build_pkg_scripts \
--scripts scripts \
build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \
@@ -155,7 +151,7 @@ productbuild \
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 "package ${APP_BUNDLE}"

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

@@ -78,6 +78,14 @@ EOF
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..."
pkgbuild \
--identifier "${IDENTIFIER}" \
@@ -86,66 +94,54 @@ pkgbuild \
--component "${APP_BUNDLE}" \
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
set -e
IDENTIFIER="cn.crossdesk.app"
APP_NAME="CrossDesk"
APP_PATH="/Applications/${APP_NAME}.app"
# 获取当前登录用户
USER_HOME=$( /usr/bin/stat -f "%Su" /dev/console )
HOME_DIR=$( /usr/bin/dscl . -read /Users/$USER_HOME NFSHomeDirectory | awk '{print $2}' )
# 复制证书文件
DEST="$HOME_DIR/Library/Application Support/CrossDesk/certs"
mkdir -p "$DEST"
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/"
# 清除应用的权限授权,以便重新授权
# 使用 tccutil 重置录屏权限和辅助功能权限
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
if [ -d "/Library/Application Support/CrossDesk/certs" ]; then
cp -R "/Library/Application Support/CrossDesk/certs/"* "$DEST/" 2>/dev/null || true
fi
# 为所有用户清除权限(可选,如果需要)
# 遍历所有用户目录并清除权限
for USER_DIR in /Users/*; do
if [ -d "$USER_DIR" ] && [ "$USER_DIR" != "/Users/Shared" ]; then
USER_NAME=$(basename "$USER_DIR")
# 跳过系统用户
if [ "$USER_NAME" != "Shared" ] && [ -d "$USER_DIR/Library" ]; then
# 删除 TCC 数据库中的相关条目(需要管理员权限)
TCC_DB="$USER_DIR/Library/Application Support/com.apple.TCC/TCC.db"
if [ -f "$TCC_DB" ]; then
# 使用 sqlite3 删除相关权限记录(如果可用)
if command -v sqlite3 >/dev/null 2>&1; then
sqlite3 "$TCC_DB" "DELETE FROM access WHERE client='$IDENTIFIER' AND service IN ('kTCCServiceScreenCapture', 'kTCCServiceAccessibility');" 2>/dev/null || true
fi
fi
fi
if [ -d "$APP_PATH" ]; then
touch "$APP_PATH"
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$APP_PATH" 2>/dev/null || true
USER_ID=$(dscl . -read /Users/$USER_HOME UniqueID 2>/dev/null | awk '{print $2}')
if [ -n "$USER_ID" ]; then
sleep 1
launchctl asuser $USER_ID open "$APP_PATH" 2>/dev/null &
APP_PID=$!
sleep 3
kill "$APP_PID" 2>/dev/null || pkill -f "${APP_NAME}" 2>/dev/null || true
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
EOF
chmod +x build_pkg_scripts/postinstall
chmod +x scripts/postinstall
pkgbuild \
--root "${CERTS_SOURCE}" \
--identifier "${IDENTIFIER}.certs" \
--version "${APP_VERSION}" \
--install-location "/Library/Application Support/CrossDesk/certs" \
--scripts build_pkg_scripts \
--scripts scripts \
build_pkg_temp/${APP_NAME}-certs.pkg
productbuild \
@@ -155,7 +151,7 @@ productbuild \
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 "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_
#define _LAYOUT_STYLE_H_
#include "render.h"
#define MENU_WINDOW_WIDTH_CN 300 * dpi_scale_
#define MENU_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define LOCAL_WINDOW_WIDTH_CN 300 * dpi_scale_
#define LOCAL_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define REMOTE_WINDOW_WIDTH_CN 300 * dpi_scale_
#define REMOTE_WINDOW_HEIGHT_CN 280 * dpi_scale_
#define MENU_WINDOW_WIDTH_EN 190 * dpi_scale_
#define MENU_WINDOW_HEIGHT_EN 245 * dpi_scale_
#define IPUT_WINDOW_WIDTH 160 * dpi_scale_
#define INPUT_WINDOW_PADDING_CN 66 * dpi_scale_
#define INPUT_WINDOW_PADDING_EN 96 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_CN 202 * dpi_scale_
#define SETTINGS_WINDOW_WIDTH_EN 248 * dpi_scale_
#define MENU_WINDOW_WIDTH_CN 300
#define MENU_WINDOW_HEIGHT_CN 280
#define LOCAL_WINDOW_WIDTH_CN 300
#define LOCAL_WINDOW_HEIGHT_CN 280
#define REMOTE_WINDOW_WIDTH_CN 300
#define REMOTE_WINDOW_HEIGHT_CN 280
#define MENU_WINDOW_WIDTH_EN 190
#define MENU_WINDOW_HEIGHT_EN 245
#define IPUT_WINDOW_WIDTH 160
#define INPUT_WINDOW_PADDING_CN 66
#define INPUT_WINDOW_PADDING_EN 96
#define SETTINGS_WINDOW_WIDTH_CN 202
#define SETTINGS_WINDOW_WIDTH_EN 248
#if USE_CUDA
#if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 405 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 405 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_CN 405
#define SETTINGS_WINDOW_HEIGHT_EN 405
#else
#define SETTINGS_WINDOW_HEIGHT_CN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_CN 375
#define SETTINGS_WINDOW_HEIGHT_EN 375
#endif
#else
#if _WIN32
#define SETTINGS_WINDOW_HEIGHT_CN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 375 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_CN 375
#define SETTINGS_WINDOW_HEIGHT_EN 375
#else
#define SETTINGS_WINDOW_HEIGHT_CN 345 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_EN 345 * dpi_scale_
#define SETTINGS_WINDOW_HEIGHT_CN 345
#define SETTINGS_WINDOW_HEIGHT_EN 345
#endif
#endif
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 195 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 195 * dpi_scale_
#define LANGUAGE_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define LANGUAGE_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN 120 * dpi_scale_
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN 167 * dpi_scale_
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_TURN_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_TURN_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_SRTP_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_SRTP_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171 * dpi_scale_
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218 * dpi_scale_
#define ENABLE_AUTOSTART_PADDING_CN 171 * dpi_scale_
#define ENABLE_AUTOSTART_PADDING_EN 218 * dpi_scale_
#define ENABLE_DAEMON_PADDING_CN 171 * dpi_scale_
#define ENABLE_DAEMON_PADDING_EN 218 * dpi_scale_
#define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171 * dpi_scale_
#define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218 * dpi_scale_
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90 * dpi_scale_
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137 * dpi_scale_
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90 * dpi_scale_
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN 137 * dpi_scale_
#define SETTINGS_SELECT_WINDOW_WIDTH 73 * dpi_scale_
#define SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH 130 * dpi_scale_
#define SETTINGS_OK_BUTTON_PADDING_CN 65 * dpi_scale_
#define SETTINGS_OK_BUTTON_PADDING_EN 83 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN 78 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN 91 * dpi_scale_
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN 162 * dpi_scale_
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN 146 * dpi_scale_
#define UPDATE_NOTIFICATION_RESERVED_HEIGHT 120 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_WIDTH_CN 130 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_HEIGHT_CN 125 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_WIDTH_EN 260 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_HEIGHT_EN 125 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_CN 90 * dpi_scale_
#define REQUEST_PERMISSION_WINDOW_CHECKBOX_PADDING_EN 210 * dpi_scale_
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_CN 228
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_WIDTH_EN 275
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_CN 195
#define SELF_HOSTED_SERVER_CONFIG_WINDOW_HEIGHT_EN 195
#define LANGUAGE_SELECT_WINDOW_PADDING_CN 120
#define LANGUAGE_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_QUALITY_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_FRAME_RATE_SELECT_WINDOW_PADDING_EN 167
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_CN 120
#define VIDEO_ENCODE_FORMAT_SELECT_WINDOW_PADDING_EN 167
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_CN 171
#define ENABLE_HARDWARE_VIDEO_CODEC_CHECKBOX_PADDING_EN 218
#define ENABLE_TURN_CHECKBOX_PADDING_CN 171
#define ENABLE_TURN_CHECKBOX_PADDING_EN 218
#define ENABLE_SRTP_CHECKBOX_PADDING_CN 171
#define ENABLE_SRTP_CHECKBOX_PADDING_EN 218
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_CN 171
#define ENABLE_SELF_HOSTED_SERVER_CHECKBOX_PADDING_EN 218
#define ENABLE_AUTOSTART_PADDING_CN 171
#define ENABLE_AUTOSTART_PADDING_EN 218
#define ENABLE_DAEMON_PADDING_CN 171
#define ENABLE_DAEMON_PADDING_EN 218
#define ENABLE_MINIZE_TO_TRAY_PADDING_CN 171
#define ENABLE_MINIZE_TO_TRAY_PADDING_EN 218
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_CN 90
#define SELF_HOSTED_SERVER_HOST_INPUT_BOX_PADDING_EN 137
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_CN 90
#define SELF_HOSTED_SERVER_PORT_INPUT_BOX_PADDING_EN 137
#define SETTINGS_SELECT_WINDOW_WIDTH 73
#define SELF_HOSTED_SERVER_INPUT_WINDOW_WIDTH 130
#define SETTINGS_OK_BUTTON_PADDING_CN 65
#define SETTINGS_OK_BUTTON_PADDING_EN 83
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_CN 78
#define SELF_HOSTED_SERVER_CONFIG_OK_BUTTON_PADDING_EN 91
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_CN 162
#define UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN 146
#endif

View File

@@ -188,19 +188,6 @@ static std::vector<std::string> minimize_to_tray = {
"Minimize to system tray when exit:"};
static std::vector<LPCWSTR> exit_program = {L"退出", L"Exit"};
#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 crossdesk
#endif

View File

@@ -76,8 +76,7 @@ int Render::LocalWindow() {
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(ICON_FA_COPY,
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
if (ImGui::Button(ICON_FA_COPY, ImVec2(22, 38))) {
local_id_copied_ = true;
ImGui::SetClipboardText(client_id_);
copy_start_time_ = ImGui::GetTime();
@@ -157,27 +156,23 @@ int Render::LocalWindow() {
ImGui::SetWindowFontScale(0.5f);
auto l_x = ImGui::GetCursorScreenPos().x;
auto l_y = ImGui::GetCursorScreenPos().y;
if (ImGui::Button(ICON_FA_EYE,
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
if (ImGui::Button(ICON_FA_EYE, ImVec2(22, 38))) {
show_password_ = !show_password_;
}
if (!show_password_) {
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine(
ImVec2(l_x + 3.0f * dpi_scale_, l_y + 12.5f * dpi_scale_),
ImVec2(l_x + 20.3f * dpi_scale_, l_y + 26.5f * dpi_scale_),
IM_COL32(239, 240, 242, 255), 2.0f);
draw_list->AddLine(
ImVec2(l_x + 3.0f * dpi_scale_, l_y + 11.0f * dpi_scale_),
ImVec2(l_x + 20.3f * dpi_scale_, l_y + 25.0f * dpi_scale_),
IM_COL32(0, 0, 0, 255), 1.5f);
draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 12.5f),
ImVec2(l_x + 20.3f, l_y + 26.5f),
IM_COL32(239, 240, 242, 255), 2.0f);
draw_list->AddLine(ImVec2(l_x + 3.0f, l_y + 11.0f),
ImVec2(l_x + 20.3f, l_y + 25.0f),
IM_COL32(0, 0, 0, 255), 1.5f);
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_PEN,
ImVec2(22 * dpi_scale_, 38 * dpi_scale_))) {
if (ImGui::Button(ICON_FA_PEN, ImVec2(22, 38))) {
show_reset_password_window_ = true;
}
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::BeginChild(
"RecentConnectionsWindow",
ImVec2(main_window_width_, main_window_height_ - title_bar_height_ -
local_window_height_ - status_bar_height_ +
1.0f),
ImVec2(main_window_width_default_,
main_window_height_default_ - title_bar_height_ -
local_window_height_ - status_bar_height_ + 1.0f),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -37,22 +37,18 @@ int Render::RecentConnectionsWindow() {
}
int Render::ShowRecentConnections() {
float recent_connection_window_padding = 25.0f * dpi_scale_;
float recent_connection_window_width =
main_window_width_ - 2 * recent_connection_window_padding;
ImGui::SetCursorPosX(recent_connection_window_padding);
ImGui::SetCursorPosX(25.0f);
ImVec2 sub_window_pos = ImGui::GetCursorPos();
std::map<std::string, ImVec2> sub_containers_pos;
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 =
recent_connection_image_height_ + 36.0f * dpi_scale_;
recent_connection_image_height_ + 36.0f;
ImGui::PushStyleColor(ImGuiCol_ChildBg,
ImVec4(239.0f / 255, 240.0f / 255, 242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("RecentConnectionsContainer",
ImVec2(recent_connection_window_width,
recent_connection_sub_container_height * 1.1f),
ImVec2(main_window_width_default_ - 50.0f, 145.0f),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -64,8 +60,8 @@ int Render::ShowRecentConnections() {
ImGui::PopStyleColor();
size_t recent_connections_count = recent_connections_.size();
int count = 0;
float button_width = 22 * dpi_scale_;
float button_height = 22 * dpi_scale_;
float button_width = 22;
float button_height = 22;
for (auto& it : recent_connections_) {
sub_containers_pos[it.first] = ImGui::GetCursorPos();
std::string recent_connection_sub_window_name =
@@ -118,11 +114,10 @@ int Render::ShowRecentConnections() {
it.second.remote_host_name = "unknown";
}
ImVec2 image_screen_pos =
ImVec2(ImGui::GetCursorScreenPos().x + 5.0f * dpi_scale_,
ImGui::GetCursorScreenPos().y + 5.0f * dpi_scale_);
ImVec2 image_pos = ImVec2(ImGui::GetCursorPosX() + 5.0f * dpi_scale_,
ImGui::GetCursorPosY() + 5.0f * dpi_scale_);
ImVec2 image_screen_pos = ImVec2(ImGui::GetCursorScreenPos().x + 5.0f,
ImGui::GetCursorScreenPos().y + 5.0f);
ImVec2 image_pos =
ImVec2(ImGui::GetCursorPosX() + 5.0f, ImGui::GetCursorPosY() + 5.0f);
ImGui::SetCursorPos(image_pos);
ImGui::Image((ImTextureID)(intptr_t)it.second.texture,
ImVec2((float)recent_connection_image_width_,
@@ -211,20 +206,17 @@ int Render::ShowRecentConnections() {
if (count != recent_connections_count - 1) {
ImVec2 line_start =
ImVec2(image_screen_pos.x + recent_connection_image_width_ +
20.0f * dpi_scale_,
ImVec2(image_screen_pos.x + recent_connection_image_width_ + 20.0f,
image_screen_pos.y);
ImVec2 line_end = ImVec2(
image_screen_pos.x + recent_connection_image_width_ +
20.0f * dpi_scale_,
image_screen_pos.x + recent_connection_image_width_ + 20.0f,
image_screen_pos.y + recent_connection_image_height_ + button_height);
ImGui::GetWindowDrawList()->AddLine(line_start, line_end,
IM_COL32(0, 0, 0, 122), 1.0f);
}
count++;
ImGui::SameLine(
0, count != recent_connections_count ? (25.0f * dpi_scale_) : 0.0f);
ImGui::SameLine(0, count != recent_connections_count ? 26.0f : 0.0f);
}
ImGui::EndChild();

View File

@@ -75,64 +75,38 @@ int Render::RemoteWindow() {
remote_id.erase(remove_if(remote_id.begin(), remote_id.end(),
static_cast<int (*)(int)>(&isspace)),
remote_id.end());
if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG,
ImVec2(55 * dpi_scale_, 38 * dpi_scale_)) ||
if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG, ImVec2(55, 38)) ||
enter_pressed) {
connect_button_pressed_ = true;
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_) {
if (id.find(remote_id) != std::string::npos) {
found = true;
target_remote_id = props.remote_id;
target_password = props.password;
{
// std::shared_lock lock(client_properties_mutex_);
if (client_properties_.find(remote_id) !=
client_properties_.end()) {
if (!client_properties_[remote_id]->connection_established_) {
should_connect = true;
} else {
already_connected = true;
}
if (client_properties_.find(remote_id) !=
client_properties_.end()) {
if (!client_properties_[remote_id]->connection_established_) {
ConnectTo(props.remote_id, props.password.c_str(), false);
} 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) {
ConnectTo(remote_id, "", false);
}
}
// check every 1 second for rejoin
if (need_to_rejoin_) {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_rejoin_check_time_)
.count();
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_);
}
need_to_rejoin_ = false;
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);
focused_remote_id_ = remote_id;
// std::shared_lock shared_lock(client_properties_mutex_);
bool exists =
(client_properties_.find(remote_id) != client_properties_.end());
// shared_lock.unlock();
if (client_properties_.find(remote_id) == client_properties_.end()) {
client_properties_[remote_id] =
std::make_shared<SubStreamWindowProperties>();
auto props = client_properties_[remote_id];
props->local_id_ = "C-" + std::string(client_id_);
props->remote_id_ = remote_id;
memcpy(&props->params_, &params_, sizeof(Params));
props->params_.user_id = props->local_id_.c_str();
props->peer_ = CreatePeer(&props->params_);
if (!exists) {
PeerPtr* peer_to_init = nullptr;
std::string local_id;
for (auto& display_info : display_info_list_) {
AddVideoStream(peer_, display_info.name.c_str());
}
AddAudioStream(props->peer_, props->audio_label_.c_str());
AddDataStream(props->peer_, props->data_label_.c_str());
{
// std::unique_lock unique_lock(client_properties_mutex_);
if (client_properties_.find(remote_id) == client_properties_.end()) {
client_properties_[remote_id] =
std::make_shared<SubStreamWindowProperties>();
auto props = client_properties_[remote_id];
props->local_id_ = "C-" + std::string(client_id_);
props->remote_id_ = remote_id;
memcpy(&props->params_, &params_, sizeof(Params));
props->params_.user_id = props->local_id_.c_str();
props->peer_ = CreatePeer(&props->params_);
props->control_window_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 (props->peer_) {
LOG_INFO("[{}] Create peer instance successful", props->local_id_);
Init(props->peer_);
LOG_INFO("[{}] Peer init finish", props->local_id_);
} else {
LOG_INFO("Create peer [{}] instance failed", props->local_id_);
}
if (peer_to_init) {
LOG_INFO("[{}] Create peer instance successful", local_id);
Init(peer_to_init);
LOG_INFO("[{}] Peer init finish", local_id);
}
props->connection_status_ = ConnectionStatus::Connecting;
}
int ret = -1;
// std::shared_lock read_lock(client_properties_mutex_);
auto props = client_properties_[remote_id];
if (!props->connection_established_) {
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;
if (props->peer_) {
ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str());
if (0 == ret) {
props->rejoin_ = false;
} else {
props->rejoin_ = true;
need_to_rejoin_ = true;
}
ret = JoinConnection(props->peer_, remote_id_with_pwd.c_str());
if (0 == ret) {
props->rejoin_ = false;
} else {
props->rejoin_ = true;
need_to_rejoin_ = true;
}
}
// read_lock.unlock();
return 0;
}

View File

@@ -133,9 +133,9 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
int window_width, window_height;
SDL_GetWindowSize(window, &window_width, &window_height);
if (area->y < 30 * render->dpi_scale_ && area->y > MOUSE_GRAB_PADDING &&
area->x < window_width - 120 * render->dpi_scale_ &&
area->x > MOUSE_GRAB_PADDING && !render->is_tab_bar_hovered_) {
if (area->y < 30 && area->y > MOUSE_GRAB_PADDING &&
area->x < window_width - 120 && area->x > MOUSE_GRAB_PADDING &&
!render->is_tab_bar_hovered_) {
return SDL_HITTEST_DRAGGABLE;
}
@@ -168,7 +168,7 @@ SDL_HitTestResult Render::HitTestCallback(SDL_Window* window,
return SDL_HITTEST_NORMAL;
}
Render::Render() : last_rejoin_check_time_(std::chrono::steady_clock::now()) {}
Render::Render() {}
Render::~Render() {}
@@ -365,16 +365,13 @@ int Render::StartSpeakerCapturer() {
if (speaker_capturer_) {
speaker_capturer_->Start();
start_speaker_capturer_ = true;
}
return 0;
}
int Render::StopSpeakerCapturer() {
if (speaker_capturer_) {
speaker_capturer_->Stop();
start_speaker_capturer_ = false;
}
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() {
main_ctx_ = ImGui::CreateContext();
if (!main_ctx_) {
@@ -661,13 +611,9 @@ int Render::CreateMainWindow() {
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(
"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_HIDDEN,
&main_window_, &main_renderer_)) {
@@ -681,12 +627,6 @@ int Render::CreateMainWindow() {
// for window region action
SDL_SetWindowHitTest(main_window_, HitTestCallback, this);
SetupFontAndStyle(true);
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(dpi_scale_);
style.FontScaleDpi = dpi_scale_;
#if _WIN32
SDL_PropertiesID props = SDL_GetWindowProperties(main_window_);
HWND main_hwnd = (HWND)SDL_GetPointerProperty(
@@ -698,9 +638,6 @@ int Render::CreateMainWindow() {
localization_language_index_);
#endif
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
ImGui_ImplSDLRenderer3_Init(main_renderer_);
return 0;
}
@@ -734,8 +671,8 @@ int Render::CreateStreamWindow() {
ImGui::SetCurrentContext(stream_ctx_);
if (!SDL_CreateWindowAndRenderer(
"Stream window", (int)stream_window_width_,
(int)stream_window_height_,
"Stream window", (int)stream_window_width_default_,
(int)stream_window_height_default_,
SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_BORDERLESS,
&stream_window_, &stream_renderer_)) {
LOG_ERROR("Error creating stream_window_ and stream_renderer_: {}",
@@ -750,13 +687,6 @@ int Render::CreateStreamWindow() {
// for window region action
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_
SDL_Event event;
event.type = SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED;
@@ -766,9 +696,6 @@ int Render::CreateStreamWindow() {
stream_window_created_ = true;
just_created_ = true;
stream_window_inited_ = true;
LOG_INFO("Stream window inited");
return 0;
}
@@ -793,9 +720,7 @@ int Render::DestroyStreamWindow() {
return 0;
}
int Render::SetupFontAndStyle(bool main_window) {
float font_size = 32.0f;
int Render::SetupFontAndStyle() {
// Setup Dear ImGui style
ImGuiIO& io = ImGui::GetIO();
@@ -805,7 +730,7 @@ int Render::SetupFontAndStyle(bool main_window) {
ImFontConfig config;
config.FontDataOwnedByAtlas = false;
io.Fonts->AddFontFromMemoryTTF(OPPOSans_Regular_ttf, OPPOSans_Regular_ttf_len,
font_size, &config,
32.0f, &config,
io.Fonts->GetGlyphRangesChineseFull());
config.MergeMode = true;
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
config.MergeMode = false;
config.FontDataOwnedByAtlas = false;
if (main_window) {
main_windows_system_chinese_font_ = nullptr;
} else {
stream_windows_system_chinese_font_ = nullptr;
}
system_chinese_font_ = nullptr;
#if defined(_WIN32)
// 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);
if (font_file.good()) {
font_file.close();
if (main_window) {
main_windows_system_chinese_font_ =
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
io.Fonts->GetGlyphRangesChineseFull());
if (main_windows_system_chinese_font_ != nullptr) {
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
break;
}
} else {
stream_windows_system_chinese_font_ =
io.Fonts->AddFontFromFileTTF(font_paths[i], font_size, &config,
io.Fonts->GetGlyphRangesChineseFull());
if (stream_windows_system_chinese_font_ != nullptr) {
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
break;
}
system_chinese_font_ = io.Fonts->AddFontFromFileTTF(
font_paths[i], 32.0f, &config, io.Fonts->GetGlyphRangesChineseFull());
if (system_chinese_font_ != nullptr) {
LOG_INFO("Loaded system Chinese font: {}", font_paths[i]);
break;
}
}
}
// If no system font found, use default font
if (main_window) {
if (main_windows_system_chinese_font_ == nullptr) {
main_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
LOG_WARN("System Chinese font not found, using default font");
}
} else {
if (stream_windows_system_chinese_font_ == nullptr) {
stream_windows_system_chinese_font_ = io.Fonts->AddFontDefault(&config);
LOG_WARN("System Chinese font not found, using default font");
}
if (system_chinese_font_ == nullptr) {
system_chinese_font_ = io.Fonts->AddFontDefault(&config);
LOG_WARN("System Chinese font not found, using default font");
}
io.Fonts->Build();
ImGui::StyleColorsLight();
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() {
ImGui::SetCurrentContext(main_ctx_);
ImGui_ImplSDLRenderer3_Shutdown();
@@ -892,6 +821,42 @@ int Render::DestroyMainWindowContext() {
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() {
stream_window_inited_ = false;
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::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(main_window_width_, main_window_height_),
ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(main_window_width_, main_window_height_default_),
ImGuiCond_Always);
ImGui::Begin("MainRender", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
@@ -929,20 +895,10 @@ int Render::DrawMainWindow() {
UpdateNotificationWindow();
#ifdef __APPLE__
if (show_request_permission_window_) {
RequestPermissionWindow();
}
#endif
ImGui::End();
// Rendering
ImGuiIO& io = ImGui::GetIO();
(void)io;
ImGui::Render();
SDL_SetRenderScale(main_renderer_, io.DisplayFramebufferScale.x,
io.DisplayFramebufferScale.y);
SDL_RenderClear(main_renderer_);
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), main_renderer_);
SDL_RenderPresent(main_renderer_);
@@ -964,6 +920,7 @@ int Render::DrawStreamWindow() {
StreamWindow();
if (!fullscreen_button_pressed_) {
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(stream_window_width_,
@@ -974,19 +931,16 @@ int Render::DrawStreamWindow() {
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor();
TitleBar(false);
ImGui::End();
}
// Rendering
ImGuiIO& io = ImGui::GetIO();
(void)io;
ImGui::Render();
SDL_SetRenderScale(stream_renderer_, io.DisplayFramebufferScale.x,
io.DisplayFramebufferScale.y);
SDL_RenderClear(stream_renderer_);
// std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) {
auto props = it.second;
if (props->tab_selected_) {
@@ -1051,8 +1005,6 @@ int Render::Run() {
}
InitializeLogger();
LOG_INFO("CrossDesk version: {}", CROSSDESK_VERSION);
InitializeSettings();
InitializeSDL();
InitializeModules();
@@ -1117,6 +1069,7 @@ void Render::InitializeModules() {
void Render::InitializeMainWindow() {
CreateMainWindow();
SetupMainWindow();
if (SDL_WINDOW_HIDDEN & SDL_GetWindowFlags(main_window_)) {
SDL_ShowWindow(main_window_);
}
@@ -1227,6 +1180,7 @@ void Render::HandleRecentConnections() {
void Render::HandleStreamWindow() {
if (need_to_create_stream_window_) {
CreateStreamWindow();
SetupStreamWindow();
need_to_create_stream_window_ = false;
}
@@ -1321,18 +1275,12 @@ void Render::CleanupPeers() {
DestroyPeer(&peer_);
}
{
// std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) {
auto props = it.second;
CleanupPeer(props);
}
for (auto& it : client_properties_) {
auto props = it.second;
CleanupPeer(props);
}
{
// std::unique_lock lock(client_properties_mutex_);
client_properties_.clear();
}
client_properties_.clear();
}
void Render::CleanSubStreamWindowProperties(
@@ -1349,7 +1297,6 @@ void Render::CleanSubStreamWindowProperties(
}
void Render::UpdateRenderRect() {
// std::shared_lock lock(client_properties_mutex_);
for (auto& [_, props] : client_properties_) {
if (!props->reset_control_bar_pos_) {
props->mouse_diff_control_bar_pos_x_ = 0;
@@ -1424,41 +1371,34 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
DestroyStreamWindow();
DestroyStreamWindowContext();
{
// std::shared_lock lock(client_properties_mutex_);
for (auto& [host_name, props] : client_properties_) {
thumbnail_->SaveToThumbnail(
(char*)props->dst_buffer_, props->video_width_,
props->video_height_, host_name, props->remote_host_name_,
props->remember_password_ ? props->remote_password_ : "");
for (auto& [host_name, props] : client_properties_) {
thumbnail_->SaveToThumbnail(
(char*)props->dst_buffer_, props->video_width_,
props->video_height_, host_name, props->remote_host_name_,
props->remember_password_ ? props->remote_password_ : "");
if (props->peer_) {
std::string client_id = (host_name == client_id_)
? "C-" + std::string(client_id_)
: client_id_;
LOG_INFO("[{}] Leave connection [{}]", client_id, host_name);
LeaveConnection(props->peer_, host_name.c_str());
LOG_INFO("Destroy peer [{}]", client_id);
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);
if (props->peer_) {
std::string client_id = (host_name == client_id_)
? "C-" + std::string(client_id_)
: client_id_;
LOG_INFO("[{}] Leave connection [{}]", client_id, host_name);
LeaveConnection(props->peer_, host_name.c_str());
LOG_INFO("Destroy peer [{}]", client_id);
DestroyPeer(&props->peer_);
}
}
{
// std::unique_lock lock(client_properties_mutex_);
client_properties_.clear();
props->streaming_ = false;
props->remember_password_ = false;
props->connection_established_ = false;
props->audio_capture_button_pressed_ = false;
memset(&props->net_traffic_stats_, 0,
sizeof(props->net_traffic_stats_));
SDL_SetWindowFullscreen(main_window_, false);
SDL_FlushEvents(STREAM_REFRESH_EVENT, STREAM_REFRESH_EVENT);
memset(audio_buffer_, 0, 720);
}
client_properties_.clear();
rejoin_ = false;
is_client_mode_ = false;

View File

@@ -15,7 +15,6 @@
#include <mutex>
#include <nlohmann/json.hpp>
#include <optional>
#include <shared_mutex>
#include <string>
#include <unordered_map>
@@ -31,7 +30,6 @@
#include "screen_capturer_factory.h"
#include "speaker_capturer_factory.h"
#include "thumbnail.h"
#if _WIN32
#include "win_tray.h"
#endif
@@ -71,10 +69,10 @@ class Render {
float sub_stream_window_height_ = 720;
float control_window_min_width_ = 20;
float control_window_max_width_ = 230;
float control_window_min_height_ = 38;
float control_window_max_height_ = 180;
float control_window_min_height_ = 40;
float control_window_max_height_ = 170;
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_y_ = 30;
float mouse_diff_control_bar_pos_x_ = 0;
@@ -175,13 +173,14 @@ class Render {
private:
int ConnectTo(const std::string& remote_id, const char* password,
bool remember_password);
int UpdateWindowSizeWithDpiScale(float dpi_scale);
int CreateMainWindow();
int DestroyMainWindow();
int CreateStreamWindow();
int DestroyStreamWindow();
int SetupFontAndStyle(bool main_window);
int SetupFontAndStyle();
int SetupMainWindow();
int DestroyMainWindowContext();
int SetupStreamWindow();
int DestroyStreamWindowContext();
int DrawMainWindow();
int DrawStreamWindow();
@@ -189,14 +188,6 @@ class Render {
int NetTrafficStats(std::shared_ptr<SubStreamWindowProperties>& props);
void DrawConnectionStatusText(
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:
static void OnReceiveVideoBufferCb(const XVideoFrame* video_frame,
@@ -313,8 +304,7 @@ class Render {
SDL_Window* main_window_ = nullptr;
SDL_Renderer* main_renderer_ = nullptr;
ImGuiContext* main_ctx_ = nullptr;
ImFont* main_windows_system_chinese_font_ = nullptr;
ImFont* stream_windows_system_chinese_font_ = nullptr;
ImFont* system_chinese_font_ = nullptr; // System Chinese font for fallback
bool exit_ = false;
const int sdl_refresh_ms_ = 16; // ~60 FPS
#if _WIN32
@@ -342,7 +332,6 @@ class Render {
int main_window_height_real_ = 540;
float main_window_dpi_scaling_w_ = 1.0f;
float main_window_dpi_scaling_h_ = 1.0f;
float dpi_scale_ = 1.0f;
float main_window_width_default_ = 640;
float main_window_height_default_ = 480;
float main_window_width_ = 640;
@@ -382,7 +371,6 @@ class Render {
int audio_len_ = 0;
bool audio_buffer_fresh_ = false;
bool need_to_rejoin_ = false;
std::chrono::steady_clock::time_point last_rejoin_check_time_;
bool just_created_ = false;
std::string controlled_remote_id_ = "";
std::string focused_remote_id_ = "";
@@ -461,9 +449,6 @@ class Render {
bool show_new_version_icon_in_menu_ = true;
uint64_t new_version_icon_last_trigger_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_display_[12] = "";
char client_id_with_password_[17] = "";
@@ -507,7 +492,6 @@ class Render {
/* ------ sub stream window property start ------ */
std::unordered_map<std::string, std::shared_ptr<SubStreamWindowProperties>>
client_properties_;
std::shared_mutex client_properties_mutex_;
void CloseTab(decltype(client_properties_)::iterator& it);
/* ------ 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;
if (!controlled_remote_id_.empty()) {
// std::shared_lock lock(client_properties_mutex_);
if (client_properties_.find(controlled_remote_id_) !=
client_properties_.end()) {
auto props = client_properties_[controlled_remote_id_];
if (props->connection_status_ == ConnectionStatus::Connected) {
std::string msg = remote_action.to_json();
if (props->peer_) {
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
}
}
@@ -45,7 +42,6 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
float ratio_x, ratio_y = 0;
RemoteAction remote_action;
// std::shared_lock lock(client_properties_mutex_);
for (auto& it : client_properties_) {
auto props = it.second;
if (!props->control_mouse_) {
@@ -98,10 +94,8 @@ int Render::ProcessMouseEvent(const SDL_Event& event) {
}
std::string msg = remote_action.to_json();
if (props->peer_) {
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
} else if (SDL_EVENT_MOUSE_WHEEL == event.type &&
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;
std::string msg = remote_action.to_json();
if (props->peer_) {
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
SendDataFrame(props->peer_, msg.c_str(), msg.size(),
props->data_label_.c_str());
}
}
@@ -162,14 +154,11 @@ void Render::SdlCaptureAudioIn(void* userdata, Uint8* stream, int len) {
}
if (1) {
// std::shared_lock lock(render->client_properties_mutex_);
for (const auto& it : render->client_properties_) {
for (auto it : render->client_properties_) {
auto props = it.second;
if (props->connection_status_ == ConnectionStatus::Connected) {
if (props->peer_) {
SendAudioFrame(props->peer_, (const char*)stream, len,
render->audio_label_.c_str());
}
SendAudioFrame(props->peer_, (const char*)stream, len,
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::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) {
return;
@@ -314,7 +302,6 @@ void Render::OnReceiveDataBufferCb(const char* data, size_t 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) !=
render->client_properties_.end()) {
// 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::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) {
return;
@@ -416,7 +402,6 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
if (!render) return;
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 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: {
props->connection_established_ = 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_);
SDL_UpdateTexture(props->stream_texture_, NULL, props->dst_buffer_,
props->texture_width_);
@@ -484,12 +469,12 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char* user_id,
render->need_to_send_host_info_ = true;
render->start_screen_capturer_ = true;
render->start_speaker_capturer_ = true;
#ifdef CROSSDESK_DEBUG
render->start_mouse_controller_ = false;
render->start_keyboard_capturer_ = false;
#else
// #ifdef CROSSDESK_DEBUG
// render->start_mouse_controller_ = false;
// render->start_keyboard_capturer_ = false;
// #else
render->start_mouse_controller_ = true;
#endif
// #endif
if (std::all_of(render->connection_status_.begin(),
render->connection_status_.end(), [](const auto& kv) {
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::shared_lock lock(render->client_properties_mutex_);
if (render->client_properties_.find(remote_id) ==
render->client_properties_.end()) {
return;

View File

@@ -32,33 +32,26 @@ int LossRateDisplay(float loss_rate) {
}
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_) {
float button_width = 24.0f * dpi_scale_;
float button_height = 24.0f * dpi_scale_;
float line_padding = 4.0f * dpi_scale_;
ImGui::SetCursorPosX(
props->is_control_bar_in_left_
? (props->control_window_width_ + 5.0f * dpi_scale_)
: 50.0f * dpi_scale_);
ImGui::SetCursorPosX(props->is_control_bar_in_left_
? (props->control_window_width_ + 5.0f)
: 38.0f);
// mouse control button
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (props->is_control_bar_in_left_) {
draw_list->AddLine(
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f * dpi_scale_,
ImGui::GetCursorScreenPos().y - 7.0f * dpi_scale_),
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f * dpi_scale_,
ImGui::GetCursorScreenPos().y - 7.0f * dpi_scale_ +
props->control_window_height_),
IM_COL32(178, 178, 178, 255), 1.0f);
draw_list->AddLine(ImVec2(ImGui::GetCursorScreenPos().x - 5.0f,
ImGui::GetCursorScreenPos().y - 7.0f),
ImVec2(ImGui::GetCursorScreenPos().x - 5.0f,
ImGui::GetCursorScreenPos().y - 7.0f +
props->control_window_height_),
IM_COL32(178, 178, 178, 255), 1.0f);
}
std::string display = ICON_FA_DISPLAY;
ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(display.c_str(), ImVec2(button_width, button_height))) {
if (ImGui::Button(display.c_str(), ImVec2(25, 25))) {
ImGui::OpenPopup("display");
}
@@ -82,10 +75,11 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
}
props->display_selectable_hovered_ = ImGui::IsWindowHovered();
}
ImGui::SetWindowFontScale(1.0f);
ImGui::EndPopup();
}
ImGui::SetWindowFontScale(0.5f);
ImGui::SetWindowFontScale(0.6f);
ImVec2 text_size = ImGui::CalcTextSize(
std::to_string(props->selected_display_ + 1).c_str());
ImVec2 text_pos =
@@ -94,16 +88,15 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::GetWindowDrawList()->AddText(
text_pos, IM_COL32(0, 0, 0, 255),
std::to_string(props->selected_display_ + 1).c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::SameLine();
float mouse_x = ImGui::GetCursorScreenPos().x;
float mouse_y = ImGui::GetCursorScreenPos().y;
float disable_mouse_x = mouse_x + line_padding;
float disable_mouse_y = mouse_y + line_padding;
float disable_mouse_x = ImGui::GetCursorScreenPos().x + 4.0f;
float disable_mouse_y = ImGui::GetCursorScreenPos().y + 4.0f;
std::string mouse = props->mouse_control_button_pressed_
? 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_) {
start_keyboard_capturer_ = !start_keyboard_capturer_;
props->control_mouse_ = !props->control_mouse_;
@@ -115,35 +108,30 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
: localization::control_mouse[localization_language_index_];
}
}
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(
ImVec2(disable_mouse_x - line_thickness * 0.7f,
disable_mouse_y + line_thickness * 0.7f),
ImVec2(
mouse_x + button_width - line_padding - line_thickness * 0.7f,
mouse_y + button_height - line_padding + line_thickness * 0.7f),
ImVec2(disable_mouse_x, disable_mouse_y),
ImVec2(disable_mouse_x + 16.0f, disable_mouse_y + 14.2f),
IM_COL32(0, 0, 0, 255), 2.0f);
draw_list->AddLine(
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)
: IM_COL32(179, 213, 253, 255),
line_thickness);
2.0f);
}
ImGui::SameLine();
// audio capture button
float audio_x = ImGui::GetCursorScreenPos().x;
float audio_y = ImGui::GetCursorScreenPos().y;
float disable_audio_x = audio_x + line_padding;
float disable_audio_y = audio_y + line_padding;
float disable_audio_x = ImGui::GetCursorScreenPos().x + 4;
float disable_audio_y = ImGui::GetCursorScreenPos().y + 4.0f;
// std::string audio = audio_capture_button_pressed_ ? ICON_FA_VOLUME_HIGH
// :
// ICON_FA_VOLUME_XMARK;
std::string audio = props->audio_capture_button_pressed_
? 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_) {
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());
}
}
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(
ImVec2(disable_audio_x - line_thickness * 0.7f,
disable_audio_y + line_thickness * 0.7f),
ImVec2(
audio_x + button_width - line_padding - line_thickness * 0.7f,
audio_y + button_height - line_padding + line_thickness * 0.7f),
ImVec2(disable_audio_x, disable_audio_y),
ImVec2(disable_audio_x + 16.0f, disable_audio_y + 14.2f),
IM_COL32(0, 0, 0, 255), 2.0f);
draw_list->AddLine(
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)
: IM_COL32(179, 213, 253, 255),
line_thickness);
2.0f);
}
ImGui::SameLine();
@@ -187,8 +170,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
button_color_style_pushed = true;
}
std::string net_traffic_stats = ICON_FA_SIGNAL;
if (ImGui::Button(net_traffic_stats.c_str(),
ImVec2(button_width, button_height))) {
if (ImGui::Button(net_traffic_stats.c_str(), ImVec2(25, 25))) {
props->net_traffic_stats_button_pressed_ =
!props->net_traffic_stats_button_pressed_;
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_language_index_];
}
if (button_color_style_pushed) {
ImGui::PopStyleColor();
button_color_style_pushed = false;
@@ -210,8 +191,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
// fullscreen button
std::string fullscreen =
fullscreen_button_pressed_ ? ICON_FA_COMPRESS : ICON_FA_EXPAND;
if (ImGui::Button(fullscreen.c_str(),
ImVec2(button_width, button_height))) {
if (ImGui::Button(fullscreen.c_str(), ImVec2(25, 25))) {
fullscreen_button_pressed_ = !fullscreen_button_pressed_;
props->fullscreen_button_label_ =
fullscreen_button_pressed_
@@ -229,8 +209,7 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
ImGui::SameLine();
// close button
std::string close_button = ICON_FA_XMARK;
if (ImGui::Button(close_button.c_str(),
ImVec2(button_width, button_height))) {
if (ImGui::Button(close_button.c_str(), ImVec2(25, 25))) {
CleanupPeer(props);
}
@@ -246,10 +225,9 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
}
}
ImGui::SetCursorPosX(
props->is_control_bar_in_left_
? (props->control_window_width_ * 2 - 20.0f * dpi_scale_)
: 5.0f * dpi_scale_);
ImGui::SetCursorPosX(props->is_control_bar_in_left_
? (props->control_window_width_ * 2 - 20.0f)
: 5.0f);
std::string control_bar =
props->control_bar_expand_
@@ -257,14 +235,13 @@ int Render::ControlBar(std::shared_ptr<SubStreamWindowProperties>& props) {
: ICON_FA_ANGLE_RIGHT)
: (props->is_control_bar_in_left_ ? ICON_FA_ANGLE_RIGHT
: ICON_FA_ANGLE_LEFT);
if (ImGui::Button(control_bar.c_str(),
ImVec2(15.0f * dpi_scale_, 25.0f * dpi_scale_))) {
if (ImGui::Button(control_bar.c_str(), ImVec2(15, 25))) {
props->control_bar_expand_ = !props->control_bar_expand_;
props->control_bar_button_pressed_time_ = ImGui::GetTime();
props->control_window_width_is_changing_ = true;
if (!props->control_bar_expand_) {
props->control_window_height_ = 35 * dpi_scale_;
props->control_window_height_ = 40;
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_
? (props->control_window_width_ + 5.0f)
: 5.0f,
35.0f * dpi_scale_));
40.0f));
if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH,
ImVec2(props->control_window_max_width_ - 10.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));
static bool a, b, c, d, e;
ImGui::SetNextWindowPos(
ImVec2(0, main_window_height_ - status_bar_height_ - 1),
ImVec2(0, main_window_height_default_ - status_bar_height_ - 1),
ImGuiCond_Always);
ImGui::BeginChild(
@@ -15,20 +15,18 @@ int Render::StatusBar() {
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImVec2 dot_pos = ImVec2(13.0f * dpi_scale_,
(main_window_height_ - status_bar_height_) * 1.025f);
ImVec2 dot_pos =
ImVec2(13, main_window_height_default_ - status_bar_height_ + 11.0f);
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,
signal_connected_ ? 1.0f : 0.0f, 0.0f),
100);
draw_list->AddCircle(dot_pos, 6.0f * dpi_scale_, ImColor(1.0f, 1.0f, 1.0f),
100);
draw_list->AddCircle(dot_pos, 6.0f, ImColor(1.0f, 1.0f, 1.0f), 100);
ImGui::SetWindowFontScale(0.6f);
draw_list->AddText(
ImVec2(25.0f * dpi_scale_,
(main_window_height_ - status_bar_height_) * 1.003f),
ImVec2(25, main_window_height_default_ - status_bar_height_ + 3.0f),
ImColor(0.0f, 0.0f, 0.0f),
signal_connected_
? localization::signal_connected[localization_language_index_].c_str()

View File

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

View File

@@ -38,9 +38,10 @@ int Render::SettingWindow() {
// Settings
{
static int settings_items_padding = 30 * dpi_scale_;
static int settings_items_padding = 30;
int settings_items_offset = 0;
ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
@@ -49,6 +50,7 @@ int Render::SettingWindow() {
nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoSavedSettings);
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
{
@@ -57,7 +59,7 @@ int Render::SettingWindow() {
localization::language_en[localization_language_index_].c_str()};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4 * dpi_scale_);
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::Text(
"%s", localization::language[localization_language_index_].c_str());
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
@@ -68,17 +70,8 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo("##language",
language_items[language_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(language_items); i++) {
bool selected = (i == language_button_value_);
if (ImGui::Selectable(language_items[i], selected))
language_button_value_ = i;
}
ImGui::EndCombo();
}
ImGui::Combo("##language", &language_button_value_, language_items,
IM_ARRAYSIZE(language_items));
}
ImGui::Separator();
@@ -97,7 +90,7 @@ int Render::SettingWindow() {
.c_str()};
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset + 4 * dpi_scale_);
ImGui::SetCursorPosY(settings_items_offset + 4);
ImGui::Text(
"%s",
localization::video_quality[localization_language_index_].c_str());
@@ -110,18 +103,8 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo(
"##video_quality",
video_quality_items[video_quality_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_quality_items); i++) {
bool selected = (i == video_quality_button_value_);
if (ImGui::Selectable(video_quality_items[i], selected))
video_quality_button_value_ = i;
}
ImGui::EndCombo();
}
ImGui::Combo("##video_quality", &video_quality_button_value_,
video_quality_items, IM_ARRAYSIZE(video_quality_items));
}
ImGui::Separator();
@@ -143,18 +126,9 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo(
"##video_frame_rate",
video_frame_rate_items[video_frame_rate_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_frame_rate_items); i++) {
bool selected = (i == video_frame_rate_button_value_);
if (ImGui::Selectable(video_frame_rate_items[i], selected))
video_frame_rate_button_value_ = i;
}
ImGui::EndCombo();
}
ImGui::Combo("##video_frame_rate", &video_frame_rate_button_value_,
video_frame_rate_items,
IM_ARRAYSIZE(video_frame_rate_items));
}
ImGui::Separator();
@@ -179,18 +153,9 @@ int Render::SettingWindow() {
ImGui::SetCursorPosY(settings_items_offset);
ImGui::SetNextItemWidth(SETTINGS_SELECT_WINDOW_WIDTH);
if (ImGui::BeginCombo(
"##video_encode_format",
video_encode_format_items[video_encode_format_button_value_])) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < IM_ARRAYSIZE(video_encode_format_items); i++) {
bool selected = (i == video_encode_format_button_value_);
if (ImGui::Selectable(video_encode_format_items[i], selected))
video_encode_format_button_value_ = i;
}
ImGui::EndCombo();
}
ImGui::Combo(
"##video_encode_format", &video_encode_format_button_value_,
video_encode_format_items, IM_ARRAYSIZE(video_encode_format_items));
}
#if USE_CUDA && !defined(__aarch64__) && !defined(__arm__)
@@ -503,10 +468,12 @@ int Render::SettingWindow() {
settings_window_pos_reset_ = true;
}
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f);
ImGui::End();
ImGui::PopStyleVar(2);
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::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild("DeskWindow",
ImVec2(main_window_width_, local_window_height_),
ImVec2(main_window_width_default_, local_window_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
@@ -21,8 +21,8 @@ int Render::MainWindow() {
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine(
ImVec2(main_window_width_ / 2, title_bar_height_ + 15.0f * dpi_scale_),
ImVec2(main_window_width_ / 2, title_bar_height_ + 225.0f * dpi_scale_),
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 15.0f),
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 225.0f),
IM_COL32(0, 0, 0, 122), 1.0f);
RemoteWindow();
@@ -32,7 +32,6 @@ int Render::MainWindow() {
StatusBar();
if (show_connection_status_window_) {
// std::unique_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin();
it != client_properties_.end();) {
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_) {
ImGui::PushItemFlag(ImGuiItemFlags_AutoClosePopups, false);
float fixed_width = 130.0f * dpi_scale_;
float fixed_width = 130.0f;
ImGui::SetNextItemWidth(fixed_width);
ImGui::SetNextWindowSizeConstraints(ImVec2(fixed_width, 0),
ImVec2(fixed_width, 100.0f));
if (ImGui::BeginCombo("##select_a_file", display_text.c_str(), 0)) {
ImGui::SetWindowFontScale(0.5f);
bool file_selected = false;
auto roots = GetRootEntries();
@@ -155,7 +154,7 @@ int Render::SelfHostedServerWindow() {
// Settings
{
static int settings_items_padding = 30 * dpi_scale_;
static int settings_items_padding = 30;
int settings_items_offset = 0;
ImGui::SetWindowFontScale(0.5f);

View File

@@ -32,15 +32,12 @@ void Render::DrawConnectionStatusText(
}
void Render::CloseTab(decltype(client_properties_)::iterator& it) {
// std::unique_lock lock(client_properties_mutex_);
if (it != client_properties_.end()) {
CleanupPeer(it->second);
it = client_properties_.erase(it);
if (client_properties_.empty()) {
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
CleanupPeer(it->second);
it = client_properties_.erase(it);
if (client_properties_.empty()) {
SDL_Event 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::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
bool video_bg_opened = ImGui::Begin(
"VideoBg", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoDocking);
ImGui::Begin("VideoBg", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoDocking);
ImGui::PopStyleColor(2);
ImGui::PopStyleVar();
if (!video_bg_opened) {
return 0;
}
ImGuiWindowFlags stream_window_flag =
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoMove;
if (!fullscreen_button_pressed_) {
ImGui::SetNextWindowPos(ImVec2(20.0f * dpi_scale_, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(0, 30.0f * dpi_scale_), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(20, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(ImVec2(0, 20), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 8.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0.0f));
@@ -86,32 +79,22 @@ int Render::StreamWindow() {
ImGuiTabBarFlags_AutoSelectNewTabs)) {
is_tab_bar_hovered_ = ImGui::IsWindowHovered();
// std::shared_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin();
it != client_properties_.end();) {
auto& props = it->second;
if (!props->tab_opened_) {
std::string remote_id_to_close = props->remote_id_;
// lock.unlock();
{
// std::unique_lock unique_lock(client_properties_mutex_);
auto close_it = client_properties_.find(remote_id_to_close);
if (close_it != client_properties_.end()) {
CloseTab(close_it);
}
}
// lock.lock();
it = client_properties_.begin();
CloseTab(it);
continue;
}
ImGui::SetWindowFontScale(0.6f);
std::string tab_label =
enable_srtp_
? std::string(ICON_FA_SHIELD_HALVED) + " " + props->remote_id_
: props->remote_id_;
if (ImGui::BeginTabItem(tab_label.c_str(), &props->tab_opened_)) {
props->tab_selected_ = true;
ImGui::SetWindowFontScale(0.6f * dpi_scale_);
ImGui::SetWindowFontScale(1.0f);
ImGui::SetNextWindowSize(
ImVec2(stream_window_width_, stream_window_height_),
@@ -139,25 +122,12 @@ int Render::StreamWindow() {
focused_remote_id_ = props->remote_id_;
if (!props->peer_) {
std::string remote_id_to_erase = props->remote_id_;
// lock.unlock();
{
// std::unique_lock unique_lock(client_properties_mutex_);
auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) {
erase_it = client_properties_.erase(erase_it);
if (client_properties_.empty()) {
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
}
it = client_properties_.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 {
DrawConnectionStatusText(props);
++it;
@@ -167,6 +137,7 @@ int Render::StreamWindow() {
ImGui::EndTabItem();
} else {
props->tab_selected_ = false;
ImGui::SetWindowFontScale(1.0f);
++it;
}
}
@@ -176,22 +147,11 @@ int Render::StreamWindow() {
ImGui::End(); // End TabBar
} else {
// std::shared_lock lock(client_properties_mutex_);
for (auto it = client_properties_.begin();
it != client_properties_.end();) {
auto& props = it->second;
if (!props->tab_opened_) {
std::string remote_id_to_close = props->remote_id_;
// lock.unlock();
{
// std::unique_lock unique_lock(client_properties_mutex_);
auto close_it = client_properties_.find(remote_id_to_close);
if (close_it != client_properties_.end()) {
CloseTab(close_it);
}
}
// lock.lock();
it = client_properties_.begin();
CloseTab(it);
continue;
}
@@ -221,23 +181,12 @@ int Render::StreamWindow() {
if (!props->peer_) {
fullscreen_button_pressed_ = false;
SDL_SetWindowFullscreen(stream_window_, false);
std::string remote_id_to_erase = props->remote_id_;
// lock.unlock();
{
// std::unique_lock unique_lock(client_properties_mutex_);
auto erase_it = client_properties_.find(remote_id_to_erase);
if (erase_it != client_properties_.end()) {
client_properties_.erase(erase_it);
if (client_properties_.empty()) {
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
}
}
it = client_properties_.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 {
DrawConnectionStatusText(props);
++it;

View File

@@ -58,15 +58,6 @@ int Render::UpdateNotificationWindow() {
float window_width = update_notification_window_width_;
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(
ImVec2(
(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_WindowRounding, 5.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::SetWindowFontScale(0.5f);
ImGui::Begin(
localization::notification[localization_language_index_].c_str(),
nullptr,
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
ImGui::SetCursorPosX(window_width * 0.1f);
ImGui::SetWindowFontScale(0.6f);
ImGui::SetWindowFontScale(0.7f);
std::string title =
localization::new_version_available[localization_language_index_] +
": v" + latest_version_;
ImGui::Text("%s", title.c_str());
ImGui::SetWindowFontScale(0.1f);
ImGui::SetWindowFontScale(0.5f);
ImGui::Spacing();
@@ -102,24 +100,19 @@ int Render::UpdateNotificationWindow() {
std::string download_text =
localization::access_website[localization_language_index_] +
"https://crossdesk.cn";
ImGui::SetWindowFontScale(0.5f);
Hyperlink(download_text, "https://crossdesk.cn", window_width);
ImGui::SetWindowFontScale(1.0f);
ImGui::Spacing();
float scrollable_height =
window_height - UPDATE_NOTIFICATION_RESERVED_HEIGHT;
float reserved_height = 140.0f;
float scrollable_height = window_height - reserved_height;
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PushFont(main_windows_system_chinese_font_);
}
// scrollable content area
ImGui::SetCursorPosX(window_width * 0.05f);
ImGui::BeginChild("ScrollableContent",
ImVec2(window_width * 0.9f, scrollable_height),
ImGuiChildFlags_Border, ImGuiWindowFlags_None);
ImGui::SetWindowFontScale(0.6f);
// set text wrap position to current available width (accounts for
// scrollbar)
float wrap_pos = ImGui::GetContentRegionAvail().x;
@@ -162,11 +155,6 @@ int Render::UpdateNotificationWindow() {
ImGui::EndChild();
// pop system font
if (main_windows_system_chinese_font_ != nullptr) {
ImGui::PopFont();
}
ImGui::Spacing();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
@@ -175,11 +163,9 @@ int Render::UpdateNotificationWindow() {
ImGui::SetCursorPosX(UPDATE_NOTIFICATION_OK_BUTTON_PADDING_EN);
}
ImGui::SetWindowFontScale(0.5f);
// update button
if (ImGui::Button(
localization::update[localization_language_index_].c_str(),
ImVec2(button_width, button_height))) {
localization::update[localization_language_index_].c_str())) {
// open download page
std::string url = "https://crossdesk.cn";
#if defined(_WIN32)
@@ -196,14 +182,20 @@ int Render::UpdateNotificationWindow() {
ImGui::SameLine();
if (ImGui::Button(
localization::cancel[localization_language_index_].c_str(),
ImVec2(button_width, button_height))) {
localization::cancel[localization_language_index_].c_str())) {
show_update_notification_window_ = false;
}
ImGui::SetWindowFontScale(1.0f);
ImGui::SetWindowFontScale(0.5f);
// pop system font
if (system_chinese_font_ != nullptr) {
ImGui::PopFont();
}
ImGui::End();
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleVar(3);
ImGui::PopStyleColor();
}

View File

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

View File

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

View File

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

View File

@@ -196,15 +196,6 @@ ScreenCapturerSckImpl::~ScreenCapturerSckImpl() {
int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_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);
__block SCShareableContent *content = nil;
@@ -214,8 +205,7 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
getShareableContentWithCompletionHandler:^(SCShareableContent *result, NSError *error) {
if (error) {
capture_error = error;
LOG_ERROR("Failed to get shareable content: {}",
std::string([error.localizedDescription UTF8String]));
NSLog(@"Failed to get shareable content: %@", error);
} else {
content = result;
}
@@ -223,10 +213,16 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if (capture_error || !content || content.displays.count == 0) {
LOG_ERROR("Failed to get display info, error: {}",
std::string([capture_error.localizedDescription UTF8String]));
return -1;
if (capture_error) {
NSString *error_desc = capture_error.localizedDescription ?: @"Unknown error";
LOG_ERROR("Failed to get shareable content: {}",
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];
@@ -265,16 +261,6 @@ int ScreenCapturerSckImpl::Init(const int fps, cb_desktop_data cb) {
}
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;
StartOrReconfigureCapturer();
return 0;
@@ -330,17 +316,17 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
return;
}
if (!content.displays || content.displays.count == 0) {
if (!content.displays.count) {
LOG_ERROR("getShareableContent returned no displays");
permanent_error_ = true;
return;
}
SCDisplay *captured_display = nil;
SCDisplay *captured_display;
{
std::lock_guard<std::mutex> lock(lock_);
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_,
display_id_name_map_[current_display_]);
captured_display = display;
@@ -349,33 +335,13 @@ void ScreenCapturerSckImpl::OnShareableContentCreated(SCShareableContent *conten
}
if (!captured_display) {
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
excludingWindows:@[]];
if (!filter) {
LOG_ERROR("Failed to create SCContentFilter");
permanent_error_ = true;
return;
}
SCStreamConfiguration *config = [[SCStreamConfiguration alloc] init];
if (!config) {
LOG_ERROR("Failed to create SCStreamConfiguration");
permanent_error_ = true;
return;
}
config.pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
config.showsCursor = show_cursor_;
config.width = filter.contentRect.size.width * filter.pointPixelScale;
@@ -466,28 +432,11 @@ void ScreenCapturerSckImpl::OnNewCVPixelBuffer(CVPixelBufferRef pixelBuffer,
}
void ScreenCapturerSckImpl::StartOrReconfigureCapturer() {
if (permanent_error_) {
LOG_ERROR("Cannot reconfigure capturer: permanent error occurred");
return;
}
if (@available(macOS 10.15, *)) {
bool has_permission = CGPreflightScreenCaptureAccess();
if (!has_permission) {
LOG_ERROR("Screen recording permission not granted");
permanent_error_ = true;
return;
}
}
// The copy is needed to avoid capturing `this` in the Objective-C block. Accessing `helper_`
// inside the block is equivalent to `this->helper_` and would crash (UAF) if `this` is
// deleted before the block is executed.
SckHelper *local_helper = helper_;
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];
};
[SCShareableContent getShareableContentWithCompletionHandler:handler];

View File

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

View File

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

View File

@@ -38,50 +38,8 @@ class SpeakerCapturerMacosx;
if (_owner->cb_ && dataPtr && length > 0 && asbd) {
std::vector<short> out_pcm16;
if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) {
int channels = asbd->mChannelsPerFrame;
int samples = (int)(length / sizeof(float));
float* floatData = (float*)dataPtr;
std::vector<short> pcm16(samples);
for (int i = 0; i < samples; ++i) {
float v = floatData[i];
if (v > 1.0f) v = 1.0f;
if (v < -1.0f) v = -1.0f;
pcm16[i] = (short)(v * 32767.0f);
}
if (channels > 1) {
int mono_samples = samples / channels;
out_pcm16.resize(mono_samples);
for (int i = 0; i < mono_samples; ++i) {
int sum = 0;
for (int c = 0; c < channels; ++c) {
sum += pcm16[i * channels + c];
}
out_pcm16[i] = sum / channels;
}
} else {
out_pcm16 = std::move(pcm16);
}
} else if (asbd->mBitsPerChannel == 16) {
int channels = asbd->mChannelsPerFrame;
int samples = (int)(length / 2);
short* src = (short*)dataPtr;
if (channels > 1) {
int mono_samples = samples / channels;
out_pcm16.resize(mono_samples);
for (int i = 0; i < mono_samples; ++i) {
int sum = 0;
for (int c = 0; c < channels; ++c) {
sum += src[i * channels + c];
}
out_pcm16[i] = sum / channels;
}
} else {
out_pcm16.assign(src, src + samples);
}
}
// ... 数据转换逻辑保持不变 ...
// 调用回调
size_t frame_bytes = 960; // 480 * 2
size_t total_bytes = out_pcm16.size() * sizeof(short);
unsigned char* p = (unsigned char*)out_pcm16.data();
@@ -90,7 +48,6 @@ class SpeakerCapturerMacosx;
}
}
}
@end
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,
const std::string& remote_id,
const std::string& host_name,

View File

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

View File

@@ -29,7 +29,7 @@ if is_mode("debug") then
end
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("nlohmann_json 3.11.3")
add_requires("cpp-httplib v0.26.0", {configs = {ssl = true}})
@@ -182,8 +182,6 @@ target("gui")
if is_os("windows") then
add_files("src/gui/tray/*.cpp")
add_includedirs("src/gui/tray", {public = true})
elseif is_os("macosx") then
add_files("src/gui/windows/*.mm")
end
target("crossdesk")