-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtray_icon_linux.cpp
More file actions
211 lines (178 loc) · 6.04 KB
/
tray_icon_linux.cpp
File metadata and controls
211 lines (178 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <iostream>
#include <string>
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libayatana-appindicator/app-indicator.h>
#include "../../menu.h"
#include "../../tray_icon.h"
#include "../../tray_icon_event.h"
namespace nativeapi {
// Private implementation class
class TrayIcon::Impl {
public:
Impl(AppIndicator* indicator) : app_indicator_(indicator), title_(""), tooltip_(""), context_menu_(nullptr), visible_(false) {}
AppIndicator* app_indicator_;
std::shared_ptr<Menu> context_menu_; // Store menu shared_ptr to keep it alive
std::string title_;
std::string tooltip_;
bool visible_;
};
TrayIcon::TrayIcon() : pimpl_(std::make_unique<Impl>(nullptr)) {
id = -1;
}
TrayIcon::TrayIcon(void* tray) : pimpl_(std::make_unique<Impl>((AppIndicator*)tray)) {
id = -1; // Will be set by TrayManager when created
// Make the indicator visible by default
if (pimpl_->app_indicator_) {
pimpl_->visible_ = true;
}
}
TrayIcon::~TrayIcon() {
if (pimpl_->app_indicator_) {
g_object_unref(pimpl_->app_indicator_);
}
}
void TrayIcon::SetIcon(std::string icon) {
if (!pimpl_->app_indicator_) {
return;
}
// Check if the icon is a base64 string
if (icon.find("data:image") != std::string::npos) {
// For base64 images, we need to save them to a temporary file
// since AppIndicator expects file paths or stock icon names
size_t pos = icon.find("base64,");
if (pos != std::string::npos) {
std::string base64Icon = icon.substr(pos + 7);
// Decode base64 data
gsize decoded_len;
guchar* decoded_data = g_base64_decode(base64Icon.c_str(), &decoded_len);
if (decoded_data) {
// Create a temporary file path
const char* temp_dir = g_get_tmp_dir();
std::string temp_path = std::string(temp_dir) + "/nativeapi_tray_icon_" + std::to_string(id) + ".png";
// Write to file
GError* error = nullptr;
if (g_file_set_contents(temp_path.c_str(), (const gchar*)decoded_data, decoded_len, &error)) {
app_indicator_set_icon_full(pimpl_->app_indicator_, temp_path.c_str(), "Tray Icon");
} else if (error) {
std::cerr << "Error saving icon to temp file: " << error->message << std::endl;
g_error_free(error);
}
g_free(decoded_data);
}
}
} else {
// Use the icon as a file path or stock icon name
if (g_file_test(icon.c_str(), G_FILE_TEST_EXISTS)) {
// It's a file path
app_indicator_set_icon_full(pimpl_->app_indicator_, icon.c_str(), "Tray Icon");
} else {
// Try as a stock icon name
app_indicator_set_icon_full(pimpl_->app_indicator_, icon.c_str(), "Tray Icon");
}
}
}
void TrayIcon::SetTitle(std::string title) {
pimpl_->title_ = title;
// AppIndicator uses the title as the accessible name and in some desktop environments
if (pimpl_->app_indicator_) {
app_indicator_set_title(pimpl_->app_indicator_, title.c_str());
}
}
std::string TrayIcon::GetTitle() {
return pimpl_->title_;
}
void TrayIcon::SetTooltip(std::string tooltip) {
pimpl_->tooltip_ = tooltip;
// AppIndicator doesn't have direct tooltip support like GtkStatusIcon
// The tooltip functionality is typically handled through the title
// or through custom menu items. We'll store it for potential future use.
}
std::string TrayIcon::GetTooltip() {
return pimpl_->tooltip_;
}
void TrayIcon::SetContextMenu(std::shared_ptr<Menu> menu) {
// Store the menu shared_ptr to keep it alive
pimpl_->context_menu_ = menu;
// AppIndicator requires a menu to be set
if (pimpl_->app_indicator_ && menu && menu->GetNativeObject()) {
GtkMenu* gtk_menu = static_cast<GtkMenu*>(menu->GetNativeObject());
app_indicator_set_menu(pimpl_->app_indicator_, gtk_menu);
}
}
std::shared_ptr<Menu> TrayIcon::GetContextMenu() {
return pimpl_->context_menu_;
}
Rectangle TrayIcon::GetBounds() {
Rectangle bounds = {0, 0, 0, 0};
// AppIndicator doesn't provide geometry information like GtkStatusIcon did
// This is a limitation of the AppIndicator API as it's handled by the
// system tray implementation. We return empty bounds.
// In most modern desktop environments, this information isn't available
// to applications for security reasons.
return bounds;
}
bool TrayIcon::Show() {
if (pimpl_->app_indicator_) {
app_indicator_set_status(pimpl_->app_indicator_, APP_INDICATOR_STATUS_ACTIVE);
pimpl_->visible_ = true;
return true;
}
return false;
}
bool TrayIcon::Hide() {
if (pimpl_->app_indicator_) {
app_indicator_set_status(pimpl_->app_indicator_, APP_INDICATOR_STATUS_PASSIVE);
pimpl_->visible_ = false;
return true;
}
return false;
}
bool TrayIcon::IsVisible() {
if (pimpl_->app_indicator_) {
AppIndicatorStatus status = app_indicator_get_status(pimpl_->app_indicator_);
return status == APP_INDICATOR_STATUS_ACTIVE;
}
return false;
}
bool TrayIcon::ShowContextMenu(double x, double y) {
if (!pimpl_->context_menu_ || !pimpl_->context_menu_->GetNativeObject()) {
return false;
}
// AppIndicator shows context menu automatically on right-click
// We don't need to manually show it at specific coordinates
// The menu is managed by the indicator framework
return true;
}
bool TrayIcon::ShowContextMenu() {
if (!pimpl_->context_menu_ || !pimpl_->context_menu_->GetNativeObject()) {
return false;
}
// AppIndicator shows context menu automatically on right-click
// We don't need to manually show it as it's managed by the indicator framework
return true;
}
// Internal method to handle click events
void TrayIcon::HandleLeftClick() {
try {
EmitSync<TrayIconClickedEvent>(id, "left");
} catch (...) {
// Protect against event emission exceptions
}
}
void TrayIcon::HandleRightClick() {
try {
EmitSync<TrayIconRightClickedEvent>(id);
} catch (...) {
// Protect against event emission exceptions
}
}
void TrayIcon::HandleDoubleClick() {
try {
EmitSync<TrayIconDoubleClickedEvent>(id);
} catch (...) {
// Protect against event emission exceptions
}
}
} // namespace nativeapi