mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-06-30 19:05:53 +08:00
[feat] support minimizing to the system tray on Linux when closing
This commit is contained in:
+5
-1
@@ -128,7 +128,11 @@ bool Daemon::start(MainLoopFunc loop) {
|
||||
if (pid > 0) _exit(0);
|
||||
|
||||
umask(0);
|
||||
chdir("/");
|
||||
if (chdir("/") != 0) {
|
||||
std::cerr << "Failed to change daemon working directory to /: "
|
||||
<< std::strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// redirect file descriptors: keep stdout/stderr if from terminal, else
|
||||
// redirect to /dev/null
|
||||
|
||||
+88
-4
@@ -1374,6 +1374,10 @@ int Render::CreateMainWindow() {
|
||||
#elif defined(__APPLE__)
|
||||
tray_ = std::make_unique<MacTray>(main_window_, "CrossDesk",
|
||||
localization_language_index_);
|
||||
#elif defined(__linux__) && !defined(__APPLE__)
|
||||
tray_ = std::make_unique<LinuxTray>(main_window_, "CrossDesk",
|
||||
localization_language_index_,
|
||||
APP_EXIT_EVENT);
|
||||
#endif
|
||||
|
||||
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
|
||||
@@ -1673,20 +1677,47 @@ int Render::SetupFontAndStyle(ImFont** system_chinese_font_out) {
|
||||
}
|
||||
|
||||
int Render::DestroyMainWindowContext() {
|
||||
if (!main_ctx_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ImGui::SetCurrentContext(main_ctx_);
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext(main_ctx_);
|
||||
main_ctx_ = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Render::DestroyStreamWindowContext() {
|
||||
if (!stream_ctx_) {
|
||||
stream_window_inited_ = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream_window_inited_ = false;
|
||||
ImGui::SetCurrentContext(stream_ctx_);
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext(stream_ctx_);
|
||||
stream_ctx_ = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Render::DestroyServerWindowContext() {
|
||||
if (!server_ctx_) {
|
||||
server_window_inited_ = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
server_window_inited_ = false;
|
||||
ImGui::SetCurrentContext(server_ctx_);
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
ImGui_ImplSDL3_Shutdown();
|
||||
ImGui::DestroyContext(server_ctx_);
|
||||
server_ctx_ = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1955,9 +1986,12 @@ void Render::InitializeSDL() {
|
||||
screen_height_ = dm->h;
|
||||
}
|
||||
|
||||
STREAM_REFRESH_EVENT = SDL_RegisterEvents(1);
|
||||
if (STREAM_REFRESH_EVENT == (uint32_t)-1) {
|
||||
LOG_ERROR("Failed to register custom SDL event");
|
||||
const uint32_t custom_event_base = SDL_RegisterEvents(2);
|
||||
if (custom_event_base == static_cast<uint32_t>(-1)) {
|
||||
LOG_ERROR("Failed to register custom SDL events");
|
||||
} else {
|
||||
STREAM_REFRESH_EVENT = custom_event_base;
|
||||
APP_EXIT_EVENT = custom_event_base + 1;
|
||||
}
|
||||
|
||||
LOG_INFO("Screen resolution: [{}x{}]", screen_width_, screen_height_);
|
||||
@@ -2031,6 +2065,10 @@ void Render::MainLoop() {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
#elif defined(__linux__) && !defined(__APPLE__)
|
||||
if (tray_) {
|
||||
tray_->ProcessEvents();
|
||||
}
|
||||
#endif
|
||||
|
||||
UpdateLabels();
|
||||
@@ -2041,7 +2079,11 @@ void Render::MainLoop() {
|
||||
HandleServerWindow();
|
||||
HandleWindowsServiceIntegration();
|
||||
|
||||
DrawMainWindow();
|
||||
const bool main_window_visible =
|
||||
main_window_ && !(SDL_GetWindowFlags(main_window_) & SDL_WINDOW_HIDDEN);
|
||||
if (main_window_visible) {
|
||||
DrawMainWindow();
|
||||
}
|
||||
if (stream_window_inited_) {
|
||||
DrawStreamWindow();
|
||||
}
|
||||
@@ -2066,6 +2108,12 @@ bool Render::MinimizeMainWindowToTray() {
|
||||
|
||||
tray_->MinimizeToTray();
|
||||
return true;
|
||||
#elif defined(__linux__) && !defined(__APPLE__)
|
||||
if (!tray_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tray_->MinimizeToTray();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -2407,6 +2455,7 @@ void Render::HandleServerWindow() {
|
||||
|
||||
if (need_to_destroy_server_window_) {
|
||||
DestroyServerWindow();
|
||||
DestroyServerWindowContext();
|
||||
need_to_destroy_server_window_ = false;
|
||||
}
|
||||
}
|
||||
@@ -2447,6 +2496,27 @@ void Render::Cleanup() {
|
||||
WaitForThumbnailSaveTasks();
|
||||
|
||||
AudioDeviceDestroy();
|
||||
#if defined(_WIN32) || defined(__APPLE__) || defined(__linux__)
|
||||
tray_.reset();
|
||||
#endif
|
||||
|
||||
if (stream_window_created_) {
|
||||
if (stream_window_) {
|
||||
SDL_SetWindowMouseGrab(stream_window_, false);
|
||||
}
|
||||
DestroyStreamWindow();
|
||||
}
|
||||
if (stream_ctx_) {
|
||||
DestroyStreamWindowContext();
|
||||
}
|
||||
|
||||
if (server_window_created_) {
|
||||
DestroyServerWindow();
|
||||
}
|
||||
if (server_ctx_) {
|
||||
DestroyServerWindowContext();
|
||||
}
|
||||
|
||||
DestroyMainWindowContext();
|
||||
DestroyMainWindow();
|
||||
SDL_Quit();
|
||||
@@ -2860,6 +2930,20 @@ void Render::ProcessSdlEvent(const SDL_Event& event) {
|
||||
}
|
||||
}
|
||||
|
||||
if (APP_EXIT_EVENT != 0 && event.type == APP_EXIT_EVENT) {
|
||||
LOG_INFO("Quit program from system tray");
|
||||
if (stream_window_) {
|
||||
SDL_SetWindowMouseGrab(stream_window_, false);
|
||||
}
|
||||
#if defined(__linux__) && !defined(__APPLE__)
|
||||
if (tray_) {
|
||||
tray_->RemoveTrayIcon();
|
||||
}
|
||||
#endif
|
||||
exit_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_QUIT:
|
||||
if (stream_window_inited_) {
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "win_tray.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include "mac_tray.h"
|
||||
#elif defined(__linux__)
|
||||
#include "linux_tray.h"
|
||||
#endif
|
||||
|
||||
namespace crossdesk {
|
||||
@@ -515,6 +517,8 @@ class Render {
|
||||
std::unique_ptr<WinTray> tray_;
|
||||
#elif defined(__APPLE__)
|
||||
std::unique_ptr<MacTray> tray_;
|
||||
#elif defined(__linux__)
|
||||
std::unique_ptr<LinuxTray> tray_;
|
||||
#endif
|
||||
|
||||
// main window properties
|
||||
@@ -596,6 +600,7 @@ class Render {
|
||||
SDL_Event last_mouse_event{};
|
||||
SDL_AudioStream* output_stream_ = nullptr;
|
||||
uint32_t STREAM_REFRESH_EVENT = 0;
|
||||
uint32_t APP_EXIT_EVENT = 0;
|
||||
#if _WIN32
|
||||
std::atomic<bool> pending_windows_service_sas_{false};
|
||||
bool local_service_status_received_ = false;
|
||||
|
||||
@@ -300,13 +300,12 @@ int Render::TitleBar(bool main_window) {
|
||||
}
|
||||
|
||||
if (close_button_clicked) {
|
||||
if (main_window && MinimizeMainWindowToTray()) {
|
||||
return 0;
|
||||
const bool minimized_to_tray = main_window && MinimizeMainWindowToTray();
|
||||
if (!minimized_to_tray) {
|
||||
SDL_Event event;
|
||||
event.type = SDL_EVENT_QUIT;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
event.type = SDL_EVENT_QUIT;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
draw_list->AddLine(ImVec2(xmark_pos_x - xmark_size / 2 - 0.25f,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2026-06-23
|
||||
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_TRAY_H_
|
||||
#define _LINUX_TRAY_H_
|
||||
|
||||
#if defined(__linux__) && !defined(__APPLE__)
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
struct SDL_Window;
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
struct LinuxTrayImpl;
|
||||
|
||||
class LinuxTray {
|
||||
public:
|
||||
LinuxTray(::SDL_Window* app_window, const std::string& tooltip,
|
||||
int language_index, uint32_t exit_event_type);
|
||||
~LinuxTray();
|
||||
|
||||
bool MinimizeToTray();
|
||||
void RemoveTrayIcon();
|
||||
void ProcessEvents();
|
||||
|
||||
private:
|
||||
std::unique_ptr<LinuxTrayImpl> impl_;
|
||||
};
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif // defined(__linux__) && !defined(__APPLE__)
|
||||
|
||||
#endif // _LINUX_TRAY_H_
|
||||
@@ -356,10 +356,6 @@ int Render::SettingWindow() {
|
||||
ImGui::Separator();
|
||||
|
||||
{
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
ImGui::BeginDisabled();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
#endif
|
||||
settings_items_offset += settings_items_padding;
|
||||
ImGui::SetCursorPosY(settings_items_offset);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
@@ -375,10 +371,6 @@ int Render::SettingWindow() {
|
||||
|
||||
ImGui::Checkbox("##enable_minimize_to_tray_",
|
||||
&enable_minimize_to_tray_);
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndDisabled();
|
||||
#endif
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -626,14 +618,12 @@ int Render::SettingWindow() {
|
||||
}
|
||||
enable_daemon_last_ = enable_daemon_;
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
if (enable_minimize_to_tray_) {
|
||||
config_center_->SetMinimizeToTray(true);
|
||||
} else {
|
||||
config_center_->SetMinimizeToTray(false);
|
||||
}
|
||||
enable_minimize_to_tray_last_ = enable_minimize_to_tray_;
|
||||
#endif
|
||||
|
||||
// File transfer save path
|
||||
config_center_->SetFileTransferSavePath(file_transfer_save_path_buf_);
|
||||
|
||||
+6
-1
@@ -35,7 +35,12 @@ function setup_platform_settings()
|
||||
add_links("pulse-simple", "pulse")
|
||||
add_requires("libyuv")
|
||||
add_syslinks("pthread", "dl")
|
||||
add_links("SDL3", "asound", "X11", "Xtst", "Xrandr", "Xfixes")
|
||||
add_links("SDL3", "asound", "X11", "Xext", "Xrender", "Xft", "Xtst",
|
||||
"Xrandr", "Xfixes")
|
||||
add_existing_include_dirs({
|
||||
"/usr/include/freetype2",
|
||||
"/usr/local/include/freetype2"
|
||||
}, {system = true})
|
||||
|
||||
if is_config("USE_DRM", true) then
|
||||
add_links("drm")
|
||||
|
||||
+4
-1
@@ -214,12 +214,15 @@ function setup_targets()
|
||||
add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",
|
||||
"src/gui/windows", {public = true})
|
||||
if is_os("windows") then
|
||||
add_files("src/gui/tray/*.cpp")
|
||||
add_files("src/gui/tray/win_tray.cpp")
|
||||
add_includedirs("src/gui/tray", "src/service/windows",
|
||||
{public = true})
|
||||
elseif is_os("macosx") then
|
||||
add_files("src/gui/windows/*.mm", "src/gui/tray/*.mm")
|
||||
add_includedirs("src/gui/tray", {public = true})
|
||||
elseif is_os("linux") then
|
||||
add_files("src/gui/tray/linux_tray.cpp")
|
||||
add_includedirs("src/gui/tray", {public = true})
|
||||
end
|
||||
|
||||
if is_os("windows") then
|
||||
|
||||
Reference in New Issue
Block a user