Skip to content

Commit 367b7db

Browse files
committed
Add icon support to GTK menu items on Linux
Implements setting and displaying icons in GTK menu items by creating a custom box layout with an icon and label. Also updates label handling to support both simple and custom layouts, ensuring label updates work correctly when an icon is present.
1 parent 85bede2 commit 367b7db

File tree

1 file changed

+75
-2
lines changed

1 file changed

+75
-2
lines changed

src/platform/linux/menu_linux.cpp

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,24 @@ void MenuItem::SetLabel(const std::optional<std::string>& label) {
148148
pimpl_->title_ = label;
149149
if (pimpl_->gtk_menu_item_ && pimpl_->type_ != MenuItemType::Separator) {
150150
const char* labelStr = label.has_value() ? label->c_str() : "";
151-
gtk_menu_item_set_label(GTK_MENU_ITEM(pimpl_->gtk_menu_item_), labelStr);
151+
152+
// Check if we have a custom box layout (with icon)
153+
GtkWidget* child = gtk_bin_get_child(GTK_BIN(pimpl_->gtk_menu_item_));
154+
if (child && GTK_IS_BOX(child)) {
155+
// Custom layout with icon - find the label widget and update it
156+
GList* children = gtk_container_get_children(GTK_CONTAINER(child));
157+
for (GList* iter = children; iter != nullptr; iter = iter->next) {
158+
GtkWidget* widget = GTK_WIDGET(iter->data);
159+
if (GTK_IS_LABEL(widget)) {
160+
gtk_label_set_text(GTK_LABEL(widget), labelStr);
161+
break;
162+
}
163+
}
164+
g_list_free(children);
165+
} else {
166+
// Simple label-only layout
167+
gtk_menu_item_set_label(GTK_MENU_ITEM(pimpl_->gtk_menu_item_), labelStr);
168+
}
152169
}
153170
}
154171

@@ -158,7 +175,63 @@ std::optional<std::string> MenuItem::GetLabel() const {
158175

159176
void MenuItem::SetIcon(std::shared_ptr<Image> image) {
160177
pimpl_->image_ = image;
161-
// TODO: Implement icon setting for GTK menu item
178+
179+
if (!pimpl_->gtk_menu_item_ || pimpl_->type_ == MenuItemType::Separator) {
180+
return;
181+
}
182+
183+
// Get current label text to preserve it
184+
const char* label_text = gtk_menu_item_get_label(GTK_MENU_ITEM(pimpl_->gtk_menu_item_));
185+
std::string current_label = label_text ? label_text : "";
186+
187+
// Remove existing child widget
188+
GtkWidget* existing_child = gtk_bin_get_child(GTK_BIN(pimpl_->gtk_menu_item_));
189+
if (existing_child) {
190+
gtk_container_remove(GTK_CONTAINER(pimpl_->gtk_menu_item_), existing_child);
191+
}
192+
193+
if (image && image->GetNativeObject()) {
194+
// Create a horizontal box to hold icon and label
195+
GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); // 6px spacing
196+
197+
// Get the GdkPixbuf from the image
198+
GdkPixbuf* pixbuf = static_cast<GdkPixbuf*>(image->GetNativeObject());
199+
200+
// Scale the icon to a reasonable menu size (16x16 is standard for menu items)
201+
const int icon_size = 16;
202+
GdkPixbuf* scaled_pixbuf = nullptr;
203+
204+
int original_width = gdk_pixbuf_get_width(pixbuf);
205+
int original_height = gdk_pixbuf_get_height(pixbuf);
206+
207+
if (original_width != icon_size || original_height != icon_size) {
208+
scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, icon_size, icon_size, GDK_INTERP_BILINEAR);
209+
} else {
210+
scaled_pixbuf = gdk_pixbuf_copy(pixbuf);
211+
}
212+
213+
// Create GtkImage from the pixbuf
214+
GtkWidget* gtk_image = gtk_image_new_from_pixbuf(scaled_pixbuf);
215+
g_object_unref(scaled_pixbuf); // GtkImage takes its own reference
216+
217+
// Create label widget
218+
GtkWidget* label = gtk_label_new(current_label.c_str());
219+
gtk_label_set_xalign(GTK_LABEL(label), 0.0); // Left-align the label
220+
221+
// Pack icon and label into box
222+
gtk_box_pack_start(GTK_BOX(box), gtk_image, FALSE, FALSE, 0);
223+
gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
224+
225+
// Add box to menu item
226+
gtk_container_add(GTK_CONTAINER(pimpl_->gtk_menu_item_), box);
227+
gtk_widget_show_all(box);
228+
} else {
229+
// No icon - restore simple label display
230+
GtkWidget* label = gtk_label_new(current_label.c_str());
231+
gtk_label_set_xalign(GTK_LABEL(label), 0.0);
232+
gtk_container_add(GTK_CONTAINER(pimpl_->gtk_menu_item_), label);
233+
gtk_widget_show(label);
234+
}
162235
}
163236

164237
std::shared_ptr<Image> MenuItem::GetIcon() const {

0 commit comments

Comments
 (0)