Skip to content

Commit 1a87670

Browse files
Copilotlijy91
andcommitted
Implement Linux TrayManager and Tray classes with basic functionality
Co-authored-by: lijy91 <3889523+lijy91@users.noreply.github.com>
1 parent cee9ccc commit 1a87670

File tree

3 files changed

+197
-0
lines changed

3 files changed

+197
-0
lines changed

CMakeLists.txt.bak

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
3+
project(libnativeapi_library VERSION 0.0.1 LANGUAGES CXX)
4+
5+
# Add library subdirectory
6+
add_subdirectory(src)
7+
8+
# Add example programs subdirectory
9+
add_subdirectory(examples/display_example)
10+
add_subdirectory(examples/nswindow_example)
11+
add_subdirectory(examples/window_example)

src/platform/linux/tray_linux.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#include <iostream>
2+
#include <string>
3+
#include <glib.h>
4+
#include <gtk/gtk.h>
5+
#include <gdk-pixbuf/gdk-pixbuf.h>
6+
#include "../../menu.h"
7+
#include "../../tray.h"
8+
9+
namespace nativeapi {
10+
11+
// Private implementation class
12+
class Tray::Impl {
13+
public:
14+
Impl(GtkStatusIcon* tray) : gtk_status_icon_(tray), title_(""), tooltip_("") {}
15+
16+
GtkStatusIcon* gtk_status_icon_;
17+
std::string title_; // GTK StatusIcon doesn't have title, so we store it
18+
std::string tooltip_;
19+
};
20+
21+
Tray::Tray() : pimpl_(new Impl(nullptr)) {
22+
id = -1;
23+
}
24+
25+
Tray::Tray(void* tray) : pimpl_(new Impl((GtkStatusIcon*)tray)) {
26+
id = -1; // Will be set by TrayManager when created
27+
// Make the status icon visible
28+
if (pimpl_->gtk_status_icon_) {
29+
gtk_status_icon_set_visible(pimpl_->gtk_status_icon_, TRUE);
30+
}
31+
}
32+
33+
Tray::~Tray() {
34+
if (pimpl_->gtk_status_icon_) {
35+
g_object_unref(pimpl_->gtk_status_icon_);
36+
}
37+
delete pimpl_;
38+
}
39+
40+
void Tray::SetIcon(std::string icon) {
41+
if (!pimpl_->gtk_status_icon_) {
42+
return;
43+
}
44+
45+
// Check if the icon is a base64 string
46+
if (icon.find("data:image") != std::string::npos) {
47+
// Extract the base64 part
48+
size_t pos = icon.find("base64,");
49+
if (pos != std::string::npos) {
50+
std::string base64Icon = icon.substr(pos + 7);
51+
52+
// Decode base64 data
53+
gsize decoded_len;
54+
guchar* decoded_data = g_base64_decode(base64Icon.c_str(), &decoded_len);
55+
56+
if (decoded_data) {
57+
// Create pixbuf from decoded data
58+
GInputStream* stream = g_memory_input_stream_new_from_data(
59+
decoded_data, decoded_len, g_free);
60+
GError* error = nullptr;
61+
GdkPixbuf* pixbuf = gdk_pixbuf_new_from_stream(stream, nullptr, &error);
62+
63+
if (pixbuf && !error) {
64+
// Scale pixbuf to appropriate size (24x24 is common for tray icons)
65+
GdkPixbuf* scaled_pixbuf = gdk_pixbuf_scale_simple(
66+
pixbuf, 24, 24, GDK_INTERP_BILINEAR);
67+
68+
gtk_status_icon_set_from_pixbuf(pimpl_->gtk_status_icon_, scaled_pixbuf);
69+
70+
g_object_unref(scaled_pixbuf);
71+
g_object_unref(pixbuf);
72+
} else if (error) {
73+
std::cerr << "Error loading icon from base64: " << error->message << std::endl;
74+
g_error_free(error);
75+
}
76+
77+
g_object_unref(stream);
78+
}
79+
}
80+
} else {
81+
// Use the icon as a file path or stock icon name
82+
if (g_file_test(icon.c_str(), G_FILE_TEST_EXISTS)) {
83+
// It's a file path
84+
gtk_status_icon_set_from_file(pimpl_->gtk_status_icon_, icon.c_str());
85+
} else {
86+
// Try as a stock icon name
87+
gtk_status_icon_set_from_icon_name(pimpl_->gtk_status_icon_, icon.c_str());
88+
}
89+
}
90+
}
91+
92+
void Tray::SetTitle(std::string title) {
93+
pimpl_->title_ = title;
94+
// GTK StatusIcon doesn't support title directly, so we just store it
95+
// Some desktop environments might show this in tooltips or context
96+
}
97+
98+
std::string Tray::GetTitle() {
99+
return pimpl_->title_;
100+
}
101+
102+
void Tray::SetTooltip(std::string tooltip) {
103+
pimpl_->tooltip_ = tooltip;
104+
if (pimpl_->gtk_status_icon_) {
105+
gtk_status_icon_set_tooltip_text(pimpl_->gtk_status_icon_, tooltip.c_str());
106+
}
107+
}
108+
109+
std::string Tray::GetTooltip() {
110+
return pimpl_->tooltip_;
111+
}
112+
113+
void Tray::SetContextMenu(Menu menu) {
114+
// For now, just store the menu - full implementation would need
115+
// to connect popup-menu signal and show GTK menu
116+
// TODO: Implement proper menu integration
117+
}
118+
119+
Menu Tray::GetContextMenu() {
120+
// Return a default/empty menu for now
121+
// TODO: Return the stored menu once properly implemented
122+
return Menu();
123+
}
124+
125+
Rectangle Tray::GetBounds() {
126+
Rectangle bounds = {0, 0, 0, 0};
127+
128+
if (pimpl_->gtk_status_icon_) {
129+
GdkScreen* screen;
130+
GdkRectangle area;
131+
GtkOrientation orientation;
132+
133+
if (gtk_status_icon_get_geometry(pimpl_->gtk_status_icon_, &screen, &area, &orientation)) {
134+
bounds.x = area.x;
135+
bounds.y = area.y;
136+
bounds.width = area.width;
137+
bounds.height = area.height;
138+
}
139+
}
140+
141+
return bounds;
142+
}
143+
144+
} // namespace nativeapi
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <cstring>
2+
#include <iostream>
3+
#include <string>
4+
5+
#include "../../tray.h"
6+
#include "../../tray_manager.h"
7+
8+
// Import GTK headers
9+
#include <gtk/gtk.h>
10+
11+
namespace nativeapi {
12+
13+
TrayManager::TrayManager() : next_tray_id_(1) {}
14+
15+
TrayManager::~TrayManager() {}
16+
17+
std::shared_ptr<Tray> TrayManager::Create() {
18+
// Create a new tray using GTK StatusIcon
19+
GtkStatusIcon* status_icon = gtk_status_icon_new();
20+
auto tray = std::make_shared<Tray>((void*)status_icon);
21+
tray->id = next_tray_id_++;
22+
trays_[tray->id] = tray;
23+
return tray;
24+
}
25+
26+
std::shared_ptr<Tray> TrayManager::Get(TrayID id) {
27+
auto it = trays_.find(id);
28+
if (it != trays_.end()) {
29+
return it->second;
30+
}
31+
return nullptr;
32+
}
33+
34+
std::vector<std::shared_ptr<Tray>> TrayManager::GetAll() {
35+
std::vector<std::shared_ptr<Tray>> trays;
36+
for (auto& tray : trays_) {
37+
trays.push_back(tray.second);
38+
}
39+
return trays;
40+
}
41+
42+
} // namespace nativeapi

0 commit comments

Comments
 (0)