mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-07-01 03:19:31 +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);
|
if (pid > 0) _exit(0);
|
||||||
|
|
||||||
umask(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 file descriptors: keep stdout/stderr if from terminal, else
|
||||||
// redirect to /dev/null
|
// redirect to /dev/null
|
||||||
|
|||||||
+88
-4
@@ -1374,6 +1374,10 @@ int Render::CreateMainWindow() {
|
|||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
tray_ = std::make_unique<MacTray>(main_window_, "CrossDesk",
|
tray_ = std::make_unique<MacTray>(main_window_, "CrossDesk",
|
||||||
localization_language_index_);
|
localization_language_index_);
|
||||||
|
#elif defined(__linux__) && !defined(__APPLE__)
|
||||||
|
tray_ = std::make_unique<LinuxTray>(main_window_, "CrossDesk",
|
||||||
|
localization_language_index_,
|
||||||
|
APP_EXIT_EVENT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
|
ImGui_ImplSDL3_InitForSDLRenderer(main_window_, main_renderer_);
|
||||||
@@ -1673,20 +1677,47 @@ int Render::SetupFontAndStyle(ImFont** system_chinese_font_out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Render::DestroyMainWindowContext() {
|
int Render::DestroyMainWindowContext() {
|
||||||
|
if (!main_ctx_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SetCurrentContext(main_ctx_);
|
ImGui::SetCurrentContext(main_ctx_);
|
||||||
ImGui_ImplSDLRenderer3_Shutdown();
|
ImGui_ImplSDLRenderer3_Shutdown();
|
||||||
ImGui_ImplSDL3_Shutdown();
|
ImGui_ImplSDL3_Shutdown();
|
||||||
ImGui::DestroyContext(main_ctx_);
|
ImGui::DestroyContext(main_ctx_);
|
||||||
|
main_ctx_ = nullptr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Render::DestroyStreamWindowContext() {
|
int Render::DestroyStreamWindowContext() {
|
||||||
|
if (!stream_ctx_) {
|
||||||
|
stream_window_inited_ = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
stream_window_inited_ = false;
|
stream_window_inited_ = false;
|
||||||
ImGui::SetCurrentContext(stream_ctx_);
|
ImGui::SetCurrentContext(stream_ctx_);
|
||||||
ImGui_ImplSDLRenderer3_Shutdown();
|
ImGui_ImplSDLRenderer3_Shutdown();
|
||||||
ImGui_ImplSDL3_Shutdown();
|
ImGui_ImplSDL3_Shutdown();
|
||||||
ImGui::DestroyContext(stream_ctx_);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1955,9 +1986,12 @@ void Render::InitializeSDL() {
|
|||||||
screen_height_ = dm->h;
|
screen_height_ = dm->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
STREAM_REFRESH_EVENT = SDL_RegisterEvents(1);
|
const uint32_t custom_event_base = SDL_RegisterEvents(2);
|
||||||
if (STREAM_REFRESH_EVENT == (uint32_t)-1) {
|
if (custom_event_base == static_cast<uint32_t>(-1)) {
|
||||||
LOG_ERROR("Failed to register custom SDL event");
|
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_);
|
LOG_INFO("Screen resolution: [{}x{}]", screen_width_, screen_height_);
|
||||||
@@ -2031,6 +2065,10 @@ void Render::MainLoop() {
|
|||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
#elif defined(__linux__) && !defined(__APPLE__)
|
||||||
|
if (tray_) {
|
||||||
|
tray_->ProcessEvents();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UpdateLabels();
|
UpdateLabels();
|
||||||
@@ -2041,7 +2079,11 @@ void Render::MainLoop() {
|
|||||||
HandleServerWindow();
|
HandleServerWindow();
|
||||||
HandleWindowsServiceIntegration();
|
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_) {
|
if (stream_window_inited_) {
|
||||||
DrawStreamWindow();
|
DrawStreamWindow();
|
||||||
}
|
}
|
||||||
@@ -2066,6 +2108,12 @@ bool Render::MinimizeMainWindowToTray() {
|
|||||||
|
|
||||||
tray_->MinimizeToTray();
|
tray_->MinimizeToTray();
|
||||||
return true;
|
return true;
|
||||||
|
#elif defined(__linux__) && !defined(__APPLE__)
|
||||||
|
if (!tray_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tray_->MinimizeToTray();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
@@ -2407,6 +2455,7 @@ void Render::HandleServerWindow() {
|
|||||||
|
|
||||||
if (need_to_destroy_server_window_) {
|
if (need_to_destroy_server_window_) {
|
||||||
DestroyServerWindow();
|
DestroyServerWindow();
|
||||||
|
DestroyServerWindowContext();
|
||||||
need_to_destroy_server_window_ = false;
|
need_to_destroy_server_window_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2447,6 +2496,27 @@ void Render::Cleanup() {
|
|||||||
WaitForThumbnailSaveTasks();
|
WaitForThumbnailSaveTasks();
|
||||||
|
|
||||||
AudioDeviceDestroy();
|
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();
|
DestroyMainWindowContext();
|
||||||
DestroyMainWindow();
|
DestroyMainWindow();
|
||||||
SDL_Quit();
|
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) {
|
switch (event.type) {
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
if (stream_window_inited_) {
|
if (stream_window_inited_) {
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
#include "win_tray.h"
|
#include "win_tray.h"
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
#include "mac_tray.h"
|
#include "mac_tray.h"
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "linux_tray.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
@@ -515,6 +517,8 @@ class Render {
|
|||||||
std::unique_ptr<WinTray> tray_;
|
std::unique_ptr<WinTray> tray_;
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
std::unique_ptr<MacTray> tray_;
|
std::unique_ptr<MacTray> tray_;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
std::unique_ptr<LinuxTray> tray_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// main window properties
|
// main window properties
|
||||||
@@ -596,6 +600,7 @@ class Render {
|
|||||||
SDL_Event last_mouse_event{};
|
SDL_Event last_mouse_event{};
|
||||||
SDL_AudioStream* output_stream_ = nullptr;
|
SDL_AudioStream* output_stream_ = nullptr;
|
||||||
uint32_t STREAM_REFRESH_EVENT = 0;
|
uint32_t STREAM_REFRESH_EVENT = 0;
|
||||||
|
uint32_t APP_EXIT_EVENT = 0;
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
std::atomic<bool> pending_windows_service_sas_{false};
|
std::atomic<bool> pending_windows_service_sas_{false};
|
||||||
bool local_service_status_received_ = false;
|
bool local_service_status_received_ = false;
|
||||||
|
|||||||
@@ -300,13 +300,12 @@ int Render::TitleBar(bool main_window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (close_button_clicked) {
|
if (close_button_clicked) {
|
||||||
if (main_window && MinimizeMainWindowToTray()) {
|
const bool minimized_to_tray = main_window && MinimizeMainWindowToTray();
|
||||||
return 0;
|
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,
|
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();
|
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;
|
settings_items_offset += settings_items_padding;
|
||||||
ImGui::SetCursorPosY(settings_items_offset);
|
ImGui::SetCursorPosY(settings_items_offset);
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
@@ -375,10 +371,6 @@ int Render::SettingWindow() {
|
|||||||
|
|
||||||
ImGui::Checkbox("##enable_minimize_to_tray_",
|
ImGui::Checkbox("##enable_minimize_to_tray_",
|
||||||
&enable_minimize_to_tray_);
|
&enable_minimize_to_tray_);
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@@ -626,14 +618,12 @@ int Render::SettingWindow() {
|
|||||||
}
|
}
|
||||||
enable_daemon_last_ = enable_daemon_;
|
enable_daemon_last_ = enable_daemon_;
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__APPLE__)
|
|
||||||
if (enable_minimize_to_tray_) {
|
if (enable_minimize_to_tray_) {
|
||||||
config_center_->SetMinimizeToTray(true);
|
config_center_->SetMinimizeToTray(true);
|
||||||
} else {
|
} else {
|
||||||
config_center_->SetMinimizeToTray(false);
|
config_center_->SetMinimizeToTray(false);
|
||||||
}
|
}
|
||||||
enable_minimize_to_tray_last_ = enable_minimize_to_tray_;
|
enable_minimize_to_tray_last_ = enable_minimize_to_tray_;
|
||||||
#endif
|
|
||||||
|
|
||||||
// File transfer save path
|
// File transfer save path
|
||||||
config_center_->SetFileTransferSavePath(file_transfer_save_path_buf_);
|
config_center_->SetFileTransferSavePath(file_transfer_save_path_buf_);
|
||||||
|
|||||||
+6
-1
@@ -35,7 +35,12 @@ function setup_platform_settings()
|
|||||||
add_links("pulse-simple", "pulse")
|
add_links("pulse-simple", "pulse")
|
||||||
add_requires("libyuv")
|
add_requires("libyuv")
|
||||||
add_syslinks("pthread", "dl")
|
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
|
if is_config("USE_DRM", true) then
|
||||||
add_links("drm")
|
add_links("drm")
|
||||||
|
|||||||
+4
-1
@@ -214,12 +214,15 @@ function setup_targets()
|
|||||||
add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",
|
add_includedirs("src/gui", "src/gui/panels", "src/gui/toolbars",
|
||||||
"src/gui/windows", {public = true})
|
"src/gui/windows", {public = true})
|
||||||
if is_os("windows") then
|
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",
|
add_includedirs("src/gui/tray", "src/service/windows",
|
||||||
{public = true})
|
{public = true})
|
||||||
elseif is_os("macosx") then
|
elseif is_os("macosx") then
|
||||||
add_files("src/gui/windows/*.mm", "src/gui/tray/*.mm")
|
add_files("src/gui/windows/*.mm", "src/gui/tray/*.mm")
|
||||||
add_includedirs("src/gui/tray", {public = true})
|
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
|
end
|
||||||
|
|
||||||
if is_os("windows") then
|
if is_os("windows") then
|
||||||
|
|||||||
Reference in New Issue
Block a user