[fix] make portable Windows Service setup optional, refs #84

This commit is contained in:
dijunkun
2026-05-28 18:59:27 +08:00
parent efcebfd82c
commit 69d77e59cc
11 changed files with 513 additions and 229 deletions
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
name="CrossDesk"
type="win32" />
<description>CrossDesk Portable Application</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</windowsSettings>
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>
+8
View File
@@ -0,0 +1,8 @@
// Portable build resource. The app itself runs as the current user; service
// installation raises a separate UAC prompt only when the user chooses it.
IDI_ICON1 ICON "..\\..\\icons\\windows\\crossdesk.ico"
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_portable.manifest"
+21
View File
@@ -79,6 +79,9 @@ int ConfigCenter::Load() {
enable_daemon_ = ini_.GetBoolValue(section_, "enable_daemon", enable_daemon_);
enable_minimize_to_tray_ = ini_.GetBoolValue(
section_, "enable_minimize_to_tray", enable_minimize_to_tray_);
portable_service_prompt_suppressed_ =
ini_.GetBoolValue(section_, "portable_service_prompt_suppressed",
portable_service_prompt_suppressed_);
const char* file_transfer_save_path_value =
ini_.GetValue(section_, "file_transfer_save_path", nullptr);
@@ -118,6 +121,8 @@ int ConfigCenter::Save() {
ini_.SetBoolValue(section_, "enable_daemon", enable_daemon_);
ini_.SetBoolValue(section_, "enable_minimize_to_tray",
enable_minimize_to_tray_);
ini_.SetBoolValue(section_, "portable_service_prompt_suppressed",
portable_service_prompt_suppressed_);
ini_.SetValue(section_, "file_transfer_save_path",
file_transfer_save_path_.c_str());
@@ -325,6 +330,18 @@ int ConfigCenter::SetDaemon(bool enable_daemon) {
return 0;
}
int ConfigCenter::SetPortableServicePromptSuppressed(bool suppressed) {
portable_service_prompt_suppressed_ = suppressed;
ini_.SetBoolValue(section_, "portable_service_prompt_suppressed",
portable_service_prompt_suppressed_);
SI_Error rc = ini_.SaveFile(config_path_.c_str());
if (rc < 0) {
return -1;
}
return 0;
}
// getters
ConfigCenter::LANGUAGE ConfigCenter::GetLanguage() const { return language_; }
@@ -377,6 +394,10 @@ bool ConfigCenter::IsEnableAutostart() const { return enable_autostart_; }
bool ConfigCenter::IsEnableDaemon() const { return enable_daemon_; }
bool ConfigCenter::IsPortableServicePromptSuppressed() const {
return portable_service_prompt_suppressed_;
}
int ConfigCenter::SetFileTransferSavePath(const std::string& path) {
file_transfer_save_path_ = path;
ini_.SetValue(section_, "file_transfer_save_path",
+3
View File
@@ -39,6 +39,7 @@ class ConfigCenter {
int SetMinimizeToTray(bool enable_minimize_to_tray);
int SetAutostart(bool enable_autostart);
int SetDaemon(bool enable_daemon);
int SetPortableServicePromptSuppressed(bool suppressed);
int SetFileTransferSavePath(const std::string& path);
// read config
@@ -60,6 +61,7 @@ class ConfigCenter {
bool IsMinimizeToTray() const;
bool IsEnableAutostart() const;
bool IsEnableDaemon() const;
bool IsPortableServicePromptSuppressed() const;
std::string GetFileTransferSavePath() const;
int Load();
@@ -87,6 +89,7 @@ class ConfigCenter {
bool enable_minimize_to_tray_ = false;
bool enable_autostart_ = false;
bool enable_daemon_ = false;
bool portable_service_prompt_suppressed_ = false;
std::string file_transfer_save_path_ = "";
};
} // namespace crossdesk
@@ -72,18 +72,45 @@ struct TranslationRow {
X(windows_service_setup_title, u8"安装 CrossDesk Service", \
"Install CrossDesk Service", u8"Установить CrossDesk Service") \
X(windows_service_setup_message, \
u8"便携版需要安装本机Windows服务,以便在锁屏/登录界面/安全桌面下完整控制此电脑。检测到服务尚未安装,可点击安装并允许相关系统权限。", \
"The portable version needs the local Windows service for full control on the lock screen, sign-in UI, and secure desktop. The service is not installed. Click Install and approve the system prompt.", \
u8"Портативной версии нужна локальная служба Windows для полного управления на экране блокировки, входа и защищенном рабочем столе. Служба не установлена. Нажмите Установить и подтвердите системный запрос.") \
X(install_windows_service, u8"安装", "Install", \
u8"Установить службу") \
u8"为支持该设备在锁屏状态下被远程控制,需要以管理员权限安装 CrossDesk " \
u8"Service。\n未安装该服务不影响 CrossDesk " \
u8"正常使用,仅无法在锁屏状态下控制本机。", \
"To support remote control of this device while it is locked, CrossDesk " \
"Service must be installed with administrator permission.\nWithout this " \
"service, CrossDesk still works normally; only lock-screen control of " \
"this computer is unavailable.", \
u8"Чтобы поддерживать удаленное управление этим устройством на экране " \
u8"блокировки, необходимо установить CrossDesk Service с правами " \
u8"администратора.\nБез этой службы CrossDesk продолжит работать " \
u8"нормально; будет недоступно только управление этим компьютером на " \
u8"экране блокировки.") \
X(install_windows_service, u8"安装", "Install", u8"Установить") \
X(windows_service_settings_label, u8"锁屏控制服务:", \
"Lock Screen Service:", u8"Служба блокировки экрана:") \
X(windows_service_installed, u8"已安装", "Installed", u8"Установлена") \
X(do_not_remind_again, u8"不再提醒", "Do not remind again", \
u8"Больше не напоминать") \
X(windows_service_prompt_suppressed_message, \
u8"已不再提醒。后续如需启用锁屏状态下被远程控制,可在设置中点击“安装”。", \
"You will not be reminded again. To enable remote control while locked " \
"later, click Install in Settings.", \
u8"Напоминание отключено. Чтобы позже включить удаленное управление на " \
u8"экране блокировки, нажмите «Установить» в настройках.") \
X(installing_windows_service, u8"正在安装服务...", "Installing service...", \
u8"Установка службы...") \
X(windows_service_install_success, u8"服务已安装并启动", \
"Service installed and started", u8"Служба установлена и запущена") \
X(windows_service_install_failed, u8"服务安装失败,请确认便携目录内服务文件完整,并允许管理员权限。", \
"Service installation failed. Check that the portable folder contains all service files and approve administrator permission.", \
u8"Не удалось установить службу. Проверьте файлы службы в папке портативной версии и подтвердите права администратора.") \
X(windows_service_install_failed, \
u8"服务安装失败。请确认 " \
u8"CrossDesk.exe、crossdesk_service.exe、crossdesk_session_helper.exe " \
u8"位于同一便携目录中,并在系统弹窗中允许管理员权限。", \
"Service installation failed. Make sure CrossDesk.exe, " \
"crossdesk_service.exe, and crossdesk_session_helper.exe are in the same " \
"portable folder, then approve the administrator prompt.", \
u8"Не удалось установить службу. Убедитесь, что CrossDesk.exe, " \
u8"crossdesk_service.exe и crossdesk_session_helper.exe находятся в " \
u8"одной папке портативной версии, затем подтвердите запрос прав " \
u8"администратора.") \
X(remote_unlock_requires_secure_desktop, \
u8"当前仍需要安全桌面专用采集/输入", \
"Secure desktop capture/input is still required", \
+5
View File
@@ -609,6 +609,11 @@ int Render::LoadSettingsFromCacheFile() {
enable_autostart_ = config_center_->IsEnableAutostart();
enable_daemon_ = config_center_->IsEnableDaemon();
enable_minimize_to_tray_ = config_center_->IsMinimizeToTray();
#if _WIN32 && CROSSDESK_PORTABLE
portable_service_prompt_suppressed_ =
config_center_->IsPortableServicePromptSuppressed();
portable_service_do_not_remind_ = portable_service_prompt_suppressed_;
#endif
// File transfer save path
{
+3
View File
@@ -567,6 +567,9 @@ class Render {
#if CROSSDESK_PORTABLE
bool portable_service_prompt_checked_ = false;
bool show_portable_service_install_window_ = false;
bool show_portable_service_prompt_suppressed_window_ = false;
bool portable_service_do_not_remind_ = false;
bool portable_service_prompt_suppressed_ = false;
std::atomic<PortableServiceInstallState> portable_service_install_state_{
PortableServiceInstallState::idle};
std::thread portable_service_install_thread_;
+108 -24
View File
@@ -4,10 +4,19 @@
#include "render.h"
#include "tinyfiledialogs.h"
#if _WIN32 && CROSSDESK_PORTABLE
#include "service_host.h"
#endif
namespace crossdesk {
int Render::SettingWindow() {
ImGuiIO& io = ImGui::GetIO();
float portable_y_padding = 0.0f;
#if _WIN32 && CROSSDESK_PORTABLE
portable_y_padding = 0.05f;
#endif
if (show_settings_window_) {
if (settings_window_pos_reset_) {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
@@ -18,12 +27,14 @@ int Render::SettingWindow() {
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.05f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.9f));
ImVec2(io.DisplaySize.x * 0.315f,
io.DisplaySize.y * (0.9f + portable_y_padding)));
#else
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.343f, io.DisplaySize.y * 0.08f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.315f, io.DisplaySize.y * 0.85f));
ImVec2(io.DisplaySize.x * 0.315f,
io.DisplaySize.y * (0.85f + portable_y_padding)));
#endif
} else {
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
@@ -32,12 +43,14 @@ int Render::SettingWindow() {
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.05f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.9f));
ImVec2(io.DisplaySize.x * 0.42f,
io.DisplaySize.y * (0.9f + portable_y_padding)));
#else
ImGui::SetNextWindowPos(
ImVec2(io.DisplaySize.x * 0.297f, io.DisplaySize.y * 0.08f));
ImGui::SetNextWindowSize(
ImVec2(io.DisplaySize.x * 0.407f, io.DisplaySize.y * 0.85f));
ImVec2(io.DisplaySize.x * 0.42f,
io.DisplaySize.y * (0.85f + portable_y_padding)));
#endif
}
@@ -73,23 +86,21 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
ImGui::SetCursorPosX(title_bar_button_width_ * 4.7f);
}
ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
if (ImGui::BeginCombo(
"##language",
if (ImGui::BeginCombo("##language",
localization::GetSupportedLanguages()
[localization::detail::ClampLanguageIndex(
language_button_value_)]
.display_name
.c_str())) {
.display_name.c_str())) {
ImGui::SetWindowFontScale(0.5f);
for (int i = 0; i < static_cast<int>(supported_languages.size());
++i) {
bool selected = (i == language_button_value_);
if (ImGui::Selectable(
supported_languages[i].display_name.c_str(), selected))
if (ImGui::Selectable(supported_languages[i].display_name.c_str(),
selected))
language_button_value_ = i;
if (selected) {
ImGui::SetItemDefaultFocus();
@@ -125,7 +136,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
ImGui::SetCursorPosX(title_bar_button_width_ * 4.7f);
}
ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
@@ -158,7 +169,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
ImGui::SetCursorPosX(title_bar_button_width_ * 4.7f);
}
ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
@@ -194,7 +205,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 3.0f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
ImGui::SetCursorPosX(title_bar_button_width_ * 4.7f);
}
ImGui::SetNextItemWidth(title_bar_button_width_ * 1.8f);
@@ -228,7 +239,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_hardware_video_codec",
@@ -249,7 +260,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_turn", &enable_turn_);
@@ -268,7 +279,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_srtp", &enable_srtp_);
@@ -289,7 +300,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_self_hosted", &enable_self_hosted_);
@@ -308,7 +319,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_autostart_", &enable_autostart_);
@@ -327,7 +338,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_daemon_", &enable_daemon_);
@@ -359,7 +370,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.275f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.755f);
ImGui::SetCursorPosX(title_bar_button_width_ * 5.955f);
}
ImGui::Checkbox("##enable_minimize_to_tray_",
@@ -384,7 +395,7 @@ int Render::SettingWindow() {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 2.82f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.3f);
ImGui::SetCursorPosX(title_bar_button_width_ * 4.5f);
}
std::string display_path =
@@ -429,6 +440,80 @@ int Render::SettingWindow() {
ImGui::EndDisabled();
}
#if _WIN32 && CROSSDESK_PORTABLE
ImGui::Separator();
{
settings_items_offset += settings_items_padding;
ImGui::SetCursorPosY(settings_items_offset);
ImGui::AlignTextToFramePadding();
ImGui::Text("%s", localization::windows_service_settings_label
[localization_language_index_]
.c_str());
ImGui::SameLine();
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.0f);
} else if (ConfigCenter::LANGUAGE::ENGLISH == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.42f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.6f);
}
const PortableServiceInstallState state =
portable_service_install_state_.load(std::memory_order_acquire);
const bool service_installed =
IsCrossDeskServiceInstalled() ||
state == PortableServiceInstallState::succeeded;
if (service_installed) {
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 3.9f);
} else if (ConfigCenter::LANGUAGE::ENGLISH ==
localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 5.32f);
} else {
ImGui::SetCursorPosX(title_bar_button_width_ * 4.6f);
}
ImGui::Text("%s", localization::windows_service_installed
[localization_language_index_]
.c_str());
} else {
if (state == PortableServiceInstallState::installing) {
ImGui::BeginDisabled();
}
if (ImGui::Button(localization::install_windows_service
[localization_language_index_]
.c_str())) {
StartPortableWindowsServiceInstall();
}
if (state == PortableServiceInstallState::installing) {
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::Text("%s", localization::installing_windows_service
[localization_language_index_]
.c_str());
} else if (state == PortableServiceInstallState::failed) {
ImGui::SameLine();
ImGui::Text(
"%s",
localization::failed[localization_language_index_].c_str());
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::SetWindowFontScale(0.5f);
ImGui::PushTextWrapPos(title_bar_button_width_ * 10.0f);
ImGui::TextWrapped("%s",
localization::windows_service_install_failed
[localization_language_index_]
.c_str());
ImGui::PopTextWrapPos();
ImGui::SetWindowFontScale(1.0f);
ImGui::EndTooltip();
}
}
}
}
#endif
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(title_bar_button_width_ * 1.59f);
} else {
@@ -464,8 +549,7 @@ int Render::SettingWindow() {
localization::GetSupportedLanguages()
[localization::detail::ClampLanguageIndex(
localization_language_index_)]
.code
.c_str());
.code.c_str());
// Video quality
if (video_quality_button_value_ == 0) {
@@ -4,6 +4,7 @@
#include <shellapi.h>
#include <algorithm>
#include <vector>
#include "localization.h"
@@ -16,8 +17,7 @@ namespace {
std::filesystem::path GetCurrentExecutablePath() {
std::vector<wchar_t> buffer(MAX_PATH);
while (true) {
DWORD length =
GetModuleFileNameW(nullptr, buffer.data(),
DWORD length = GetModuleFileNameW(nullptr, buffer.data(),
static_cast<DWORD>(buffer.size()));
if (length == 0) {
return {};
@@ -46,7 +46,8 @@ bool InstallServiceWithElevation() {
if (!std::filesystem::exists(service_path) ||
!std::filesystem::exists(helper_path)) {
LOG_ERROR(
"Portable service install failed: service binaries missing, service={}, "
"Portable service install failed: service binaries missing, "
"service={}, "
"helper={}",
service_path.string(), helper_path.string());
return false;
@@ -106,12 +107,17 @@ void Render::CheckPortableWindowsService() {
return;
}
if (portable_service_prompt_suppressed_) {
return;
}
portable_service_install_state_.store(PortableServiceInstallState::idle,
std::memory_order_relaxed);
show_portable_service_install_window_ = true;
}
void Render::StartPortableWindowsServiceInstall() {
portable_service_do_not_remind_ = false;
PortableServiceInstallState expected = PortableServiceInstallState::idle;
if (!portable_service_install_state_.compare_exchange_strong(
expected, PortableServiceInstallState::installing,
@@ -140,18 +146,82 @@ void Render::JoinPortableWindowsServiceInstallThread() {
}
int Render::PortableServiceInstallWindow() {
if (!show_portable_service_install_window_) {
if (!show_portable_service_install_window_ &&
!show_portable_service_prompt_suppressed_window_) {
return 0;
}
const ImGuiViewport* viewport = ImGui::GetMainViewport();
const float window_width = title_bar_button_width_ * 12.0f;
const float window_height = title_bar_button_width_ * 4.0f;
const float window_width =
(std::min)(viewport->WorkSize.x * 0.6f, title_bar_button_width_ * 18.0f);
const float window_height =
(std::min)(viewport->WorkSize.y * 0.5f, title_bar_button_width_ * 8.0f);
if (show_portable_service_prompt_suppressed_window_) {
const float notice_width = window_width;
const float notice_height = (std::min)(viewport->WorkSize.y * 0.35f,
title_bar_button_width_ * 4.6f);
ImGui::SetNextWindowPos(
ImVec2((viewport->WorkSize.x - viewport->WorkPos.x - window_width) /
2.0f,
(viewport->WorkSize.y - viewport->WorkPos.y - window_height) /
2.0f),
ImVec2(
viewport->WorkPos.x + (viewport->WorkSize.x - notice_width) / 2.0f,
viewport->WorkPos.y +
(viewport->WorkSize.y - notice_height) / 2.0f),
ImGuiCond_Appearing);
ImGui::SetNextWindowSize(ImVec2(notice_width, notice_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, window_rounding_);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, window_rounding_ * 0.5f);
ImGui::Begin(
localization::notification[localization_language_index_].c_str(),
nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoTitleBar);
ImGui::Spacing();
ImGui::SetWindowFontScale(0.55f);
ImGui::SetCursorPosX(notice_width * 0.08f);
ImGui::Text(
"%s", localization::notification[localization_language_index_].c_str());
ImGui::SetWindowFontScale(0.5f);
ImGui::SetCursorPosX(notice_width * 0.06f);
ImGui::SetCursorPosY(notice_height * 0.28f);
ImGui::PushTextWrapPos(notice_width * 0.88f);
ImGui::TextWrapped("%s",
localization::windows_service_prompt_suppressed_message
[localization_language_index_]
.c_str());
ImGui::PopTextWrapPos();
const std::string ok_label = localization::ok[localization_language_index_];
const ImGuiStyle& style = ImGui::GetStyle();
const float ok_width =
ImGui::CalcTextSize(ok_label.c_str()).x + style.FramePadding.x * 2.0f;
ImGui::SetCursorPosX((notice_width - ok_width) * 0.5f);
ImGui::SetCursorPosY(notice_height * 0.75f);
if (ImGui::Button(ok_label.c_str())) {
show_portable_service_prompt_suppressed_window_ = false;
}
ImGui::SetWindowFontScale(1.0f);
ImGui::End();
ImGui::PopStyleVar(3);
ImGui::PopStyleColor();
}
if (!show_portable_service_install_window_) {
return 0;
}
ImGui::SetNextWindowPos(
ImVec2(
viewport->WorkPos.x + (viewport->WorkSize.x - window_width) / 2.0f,
viewport->WorkPos.y + (viewport->WorkSize.y - window_height) / 2.0f),
ImGuiCond_Appearing);
ImGui::SetNextWindowSize(ImVec2(window_width, window_height),
ImGuiCond_Always);
@@ -187,13 +257,11 @@ int Render::PortableServiceInstallWindow() {
localization::installing_windows_service[localization_language_index_]
.c_str();
if (state == PortableServiceInstallState::succeeded) {
status_text =
localization::windows_service_install_success
status_text = localization::windows_service_install_success
[localization_language_index_]
.c_str();
} else if (state == PortableServiceInstallState::failed) {
status_text =
localization::windows_service_install_failed
status_text = localization::windows_service_install_failed
[localization_language_index_]
.c_str();
}
@@ -203,7 +271,7 @@ int Render::PortableServiceInstallWindow() {
ImGui::SetCursorPosX(window_width * 0.04f);
ImGui::SetCursorPosY(window_height * 0.22f);
ImGui::BeginChild("PortableServiceInstallContent",
ImVec2(window_width * 0.92f, window_height * 0.5f),
ImVec2(window_width * 0.92f, window_height * 0.45f),
ImGuiChildFlags_Borders, ImGuiWindowFlags_None);
ImGui::SetWindowFontScale(0.5f);
const float wrap_pos = ImGui::GetContentRegionAvail().x;
@@ -220,7 +288,15 @@ int Render::PortableServiceInstallWindow() {
ImGui::EndChild();
ImGui::SetWindowFontScale(0.5f);
const float button_y = window_height * 0.76f;
ImGui::SetCursorPosX(window_width * 0.08f);
ImGui::SetCursorPosY(window_height * 0.71f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
ImGui::Checkbox(
localization::do_not_remind_again[localization_language_index_].c_str(),
&portable_service_do_not_remind_);
ImGui::PopStyleVar();
const float button_y = window_height * 0.84f;
const ImGuiStyle& style = ImGui::GetStyle();
const auto default_button_width = [&style](const std::string& label) {
return ImGui::CalcTextSize(label.c_str()).x + style.FramePadding.x * 2.0f;
@@ -259,6 +335,11 @@ int Render::PortableServiceInstallWindow() {
ImGui::BeginDisabled();
}
if (ImGui::Button(cancel_label.c_str())) {
if (portable_service_do_not_remind_) {
portable_service_prompt_suppressed_ = true;
config_center_->SetPortableServicePromptSuppressed(true);
show_portable_service_prompt_suppressed_window_ = true;
}
show_portable_service_install_window_ = false;
}
if (state == PortableServiceInstallState::installing) {
+23
View File
@@ -82,16 +82,27 @@ int main() {
}
const std::string rc = ReadFile(repo_root / "scripts/windows/crossdesk.rc");
const std::string portable_rc =
ReadFile(repo_root / "scripts/windows/crossdesk_portable.rc");
const std::string manifest =
ReadFile(repo_root / "scripts/windows/crossdesk.manifest");
const std::string debug_manifest =
ReadFile(repo_root / "scripts/windows/crossdesk_debug.manifest");
const std::string portable_manifest =
ReadFile(repo_root / "scripts/windows/crossdesk_portable.manifest");
const std::string targets = ReadFile(repo_root / "xmake/targets.lua");
bool ok = true;
ok &= ExpectContains("crossdesk.rc", rc, "crossdesk.manifest");
ok &= ExpectContains("crossdesk.rc", rc, "crossdesk_debug.manifest");
ok &= ExpectContains("crossdesk.rc", rc, "CROSSDESK_DEBUG");
ok &= ExpectContains("crossdesk.rc", rc, "RT_MANIFEST");
ok &= ExpectContains("crossdesk_portable.rc", portable_rc,
"crossdesk_portable.manifest");
ok &= ExpectContains("crossdesk_portable.rc", portable_rc, "RT_MANIFEST");
ok &= ExpectContains("xmake/targets.lua", targets,
"scripts/windows/crossdesk_portable.rc");
ok &= ExpectContains("xmake/targets.lua", targets, "CROSSDESK_PORTABLE");
ok &= ExpectContains("crossdesk.manifest", manifest,
"level=\"requireAdministrator\"");
ok &= ExpectContains("crossdesk.manifest", manifest,
@@ -108,10 +119,22 @@ int main() {
"http://schemas.microsoft.com/SMI/2016/WindowsSettings");
ok &= ExpectNotContains("crossdesk_debug.manifest", debug_manifest,
"processorArchitecture=\"*\"");
ok &= ExpectContains("crossdesk_portable.manifest", portable_manifest,
"level=\"asInvoker\"");
ok &= ExpectNotContains("crossdesk_portable.manifest", portable_manifest,
"level=\"requireAdministrator\"");
ok &= ExpectContains("crossdesk_portable.manifest", portable_manifest,
"http://schemas.microsoft.com/SMI/2005/WindowsSettings");
ok &= ExpectContains("crossdesk_portable.manifest", portable_manifest,
"http://schemas.microsoft.com/SMI/2016/WindowsSettings");
ok &= ExpectNotContains("crossdesk_portable.manifest", portable_manifest,
"processorArchitecture=\"*\"");
#ifdef _WIN32
ok &= ExpectActivationContext(repo_root / "scripts/windows/crossdesk.manifest");
ok &= ExpectActivationContext(
repo_root / "scripts/windows/crossdesk_debug.manifest");
ok &= ExpectActivationContext(
repo_root / "scripts/windows/crossdesk_portable.manifest");
#endif
return ok ? 0 : 1;
}
+7 -10
View File
@@ -3,6 +3,11 @@ function setup_targets()
includes("submodules", "thirdparty")
local crossdesk_windows_resource = "scripts/windows/crossdesk.rc"
if is_config("CROSSDESK_PORTABLE", true) then
crossdesk_windows_resource = "scripts/windows/crossdesk_portable.rc"
end
target("rd_log")
set_kind("object")
add_packages("spdlog")
@@ -65,14 +70,6 @@ function setup_targets()
set_default(false)
add_files("tests/display_popup_hover_state_test.cpp")
target("version_checker_test")
set_kind("binary")
set_default(false)
add_packages("cpp-httplib", "nlohmann_json")
add_includedirs("src/version_checker")
add_files("tests/version_checker_test.cpp",
"src/version_checker/version_checker.cpp")
target("screen_capturer")
set_kind("object")
add_deps("rd_log", "common")
@@ -231,7 +228,7 @@ function setup_targets()
add_deps("rd_log", "path_manager")
add_links("Advapi32", "User32", "Wtsapi32", "Gdi32")
add_files("src/service/windows/session_helper_main.cpp")
add_files("scripts/windows/crossdesk.rc")
add_files(crossdesk_windows_resource)
add_includedirs("src/service/windows", {public = true})
end
@@ -245,6 +242,6 @@ function setup_targets()
add_includedirs("src/service/windows", {public = true})
add_links("Advapi32", "Wtsapi32", "Ole32", "Userenv")
add_deps("wgc_plugin", "crossdesk_service", "crossdesk_session_helper")
add_files("scripts/windows/crossdesk.rc")
add_files(crossdesk_windows_resource)
end
end