[fix] make Xfce optional with separate Linux deb packages, refs #106

This commit is contained in:
dijunkun
2026-10-08 14:43:58 +08:00
parent ec6fe8ea98
commit 9550731681
17 changed files with 256 additions and 64 deletions
@@ -1498,7 +1498,11 @@ void GuiApplication::BindMainCallbacks() {
? UiText(std::to_string(signal_port))
: slint::SharedString{});
});
main->on_open_download([this] { OpenUrl("https://crossdesk.cn"); });
main->on_open_download([this] {
const auto& latest = update_checker_->latest();
OpenUrl(latest && !latest->download_url.empty() ? latest->download_url
: "https://crossdesk.cn");
});
main->on_check_for_updates([this] {
update_checker_->RequestCheck();
SyncMainWindow();
@@ -524,7 +524,10 @@ int RunHeadless(const Options& options, const std::function<int()>& run) {
const std::string xvfb = FindExecutable("Xvfb");
if (xvfb.empty()) {
Diagnostic() << "No usable display. Headless mode requires Xvfb; on Debian/Ubuntu "
"install it with: sudo apt install xvfb\n";
"install it with: sudo apt install xvfb\n"
"For a complete independent desktop, install the "
"crossdesk-virtual-desktop-xfce .deb and use "
"--headless-session startxfce4.\n";
return 1;
}
std::string session;
@@ -532,9 +535,15 @@ int RunHeadless(const Options& options, const std::function<int()>& run) {
if (!options.session.empty() && options.session != "none") {
session = FindExecutable(options.session);
dbus = FindExecutable("dbus-run-session");
if (session.empty() || dbus.empty()) {
Diagnostic() << "Headless desktop requires an executable --headless-session "
"and dbus-run-session (Debian/Ubuntu: dbus-daemon)\n";
if (session.empty()) {
Diagnostic() << "Desktop session executable not found: " << options.session
<< ". Install that desktop environment first; for Xfce use the "
"crossdesk-virtual-desktop-xfce .deb.\n";
return 1;
}
if (dbus.empty()) {
Diagnostic() << "Headless desktop requires dbus-run-session. Install "
"dbus-daemon (or dbus on older Debian/Ubuntu releases).\n";
return 1;
}
}
@@ -0,0 +1,55 @@
#include "linux_update_download.h"
#include <fstream>
#include <nlohmann/json.hpp>
namespace crossdesk {
std::string LinuxUpdateDownloadUrl(const nlohmann::json& manifest,
const VersionInfo& latest,
const std::string& architecture,
const std::filesystem::path& executable_dir) {
const std::string fallback = "https://github.com/kunkundi/crossdesk/releases";
if ((architecture != "amd64" && architecture != "arm64") ||
executable_dir.empty()) {
return fallback;
}
std::string package_name = "crossdesk";
const auto marker = executable_dir / "package-name";
std::error_code error;
const bool has_marker = std::filesystem::exists(marker, error);
if (error) return fallback;
if (has_marker) {
std::ifstream file(marker);
if (!std::getline(file, package_name)) return fallback;
}
std::string key = "linux-" + architecture;
if (package_name == "crossdesk-virtual-desktop-xfce") {
key += "-virtual-desktop-xfce";
} else if (package_name != "crossdesk") {
return fallback;
}
try {
const auto& download = manifest.at("downloads").at(key);
const auto version = ParseVersionInfoJSON(download.dump());
// A partial release can leave older downloads in the merged manifest.
if (!version || version->version != latest.version ||
IsNewerVersionWithMetadata(version->version, latest.version,
latest.release_date, latest.patch)) {
return fallback;
}
const std::string filename = package_name + "-linux-" + architecture +
"-v" + latest.version + ".deb";
const std::string url = "https://downloads.crossdesk.cn/" + filename;
// Verify the variant in the asset name too, not just the manifest key.
if (download.at("filename") == filename && download.at("url") == url) {
return url;
}
} catch (const nlohmann::json::exception&) {
}
return fallback;
}
} // namespace crossdesk
@@ -0,0 +1,29 @@
/*
* @Author: DI JUNKUN
* @Date: 2026-10-08
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _LINUX_UPDATE_DOWNLOAD_H_
#define _LINUX_UPDATE_DOWNLOAD_H_
#include <filesystem>
#include <string>
#include <nlohmann/json_fwd.hpp>
#include "app_version.h"
namespace crossdesk {
// Uses package-name beside the executable, so source builds cannot inherit an
// unrelated system installation's variant. Missing/invalid downloads open the
// release list rather than silently offering a different package or old release.
std::string LinuxUpdateDownloadUrl(const nlohmann::json& manifest,
const VersionInfo& latest,
const std::string& architecture,
const std::filesystem::path& executable_dir);
} // namespace crossdesk
#endif
@@ -10,6 +10,7 @@
#include <nlohmann/json.hpp>
#include "rd_log.h"
#include "linux_update_download.h"
#include <cstdlib>
#include <filesystem>
@@ -118,8 +119,22 @@ std::optional<VersionInfo> CheckUpdate() {
if (res) {
if (res->status == 200) {
try {
auto info = ParseVersionInfo(nlohmann::json::parse(res->body));
const auto manifest = nlohmann::json::parse(res->body);
auto info = ParseVersionInfo(manifest);
if (info) {
#if defined(__linux__)
std::string architecture;
#if defined(__x86_64__)
architecture = "amd64";
#elif defined(__aarch64__)
architecture = "arm64";
#endif
std::error_code error;
const auto executable = std::filesystem::read_symlink("/proc/self/exe", error);
info->download_url = LinuxUpdateDownloadUrl(
manifest, *info, architecture,
error ? std::filesystem::path{} : executable.parent_path());
#endif
LOG_INFO("Fetched version.json: latest_version={}, releaseDate={}, patch={}",
info->version, info->release_date, info->patch);
} else {