From 3be67ced646f9d884c32ce6858f39fe9dd8d634b Mon Sep 17 00:00:00 2001
From: Semphris <[EMAIL REDACTED]>
Date: Wed, 12 Feb 2025 17:55:23 -0500
Subject: [PATCH] Fix GTK tray icon without menu + lifetime
---
src/tray/unix/SDL_tray.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/src/tray/unix/SDL_tray.c b/src/tray/unix/SDL_tray.c
index 02b59436bcf3f..dc2d0ca6396eb 100644
--- a/src/tray/unix/SDL_tray.c
+++ b/src/tray/unix/SDL_tray.c
@@ -58,6 +58,13 @@ typedef enum
static gulong (*g_signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags);
static void (*g_object_unref)(gpointer object);
static gchar *(*g_mkdtemp)(gchar *template);
+gpointer (*g_object_ref_sink)(gpointer object);
+gpointer (*g_object_ref)(gpointer object);
+
+// glib_typeof requires compiler-specific code and includes that are too complex
+// to be worth copy-pasting here
+//#define g_object_ref(Obj) ((glib_typeof (Obj)) (g_object_ref) (Obj))
+//#define g_object_ref_sink(Obj) ((glib_typeof (Obj)) (g_object_ref_sink) (Obj))
#define g_signal_connect(instance, detailed_signal, c_handler, data) \
g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0)
@@ -248,6 +255,8 @@ static bool init_gtk(void)
g_mkdtemp = dlsym(libgdk, "g_mkdtemp");
g_signal_connect_data = dlsym(libgdk, "g_signal_connect_data");
g_object_unref = dlsym(libgdk, "g_object_unref");
+ g_object_ref_sink = dlsym(libgdk, "g_object_ref_sink");
+ g_object_ref = dlsym(libgdk, "g_object_ref");
app_indicator_new = dlsym(libappindicator, "app_indicator_new");
app_indicator_set_status = dlsym(libappindicator, "app_indicator_set_status");
@@ -268,6 +277,8 @@ static bool init_gtk(void)
!gtk_menu_shell_insert ||
!gtk_widget_destroy ||
!g_mkdtemp ||
+ !g_object_ref_sink ||
+ !g_object_ref ||
!g_signal_connect_data ||
!g_object_unref ||
!app_indicator_new ||
@@ -326,6 +337,8 @@ struct SDL_Tray {
SDL_TrayMenu *menu;
char icon_dir[sizeof(ICON_DIR_TEMPLATE)];
char icon_path[256];
+
+ GtkMenuShell *menu_cached;
};
static void call_callback(GtkMenuItem *item, gpointer ptr)
@@ -384,6 +397,11 @@ static void DestroySDLMenu(SDL_TrayMenu *menu)
}
SDL_free(menu->entries[i]);
}
+
+ if (menu->menu) {
+ g_object_unref(menu->menu);
+ }
+
SDL_free(menu->entries);
SDL_free(menu);
}
@@ -435,6 +453,10 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
app_indicator_set_status(tray->indicator, APP_INDICATOR_STATUS_ACTIVE);
+ // The tray icon isn't shown before a menu is created; create one early.
+ tray->menu_cached = (GtkMenuShell *) g_object_ref_sink(gtk_menu_new());
+ app_indicator_set_menu(tray->indicator, GTK_MENU(tray->menu_cached));
+
SDL_RegisterTray(tray);
return tray;
@@ -478,14 +500,12 @@ SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
return NULL;
}
- tray->menu->menu = (GtkMenuShell *)gtk_menu_new();
+ tray->menu->menu = g_object_ref(tray->menu_cached);
tray->menu->parent_tray = tray;
tray->menu->parent_entry = NULL;
tray->menu->nEntries = 0;
tray->menu->entries = NULL;
- app_indicator_set_menu(tray->indicator, GTK_MENU(tray->menu->menu));
-
return tray->menu;
}
@@ -785,6 +805,10 @@ void SDL_DestroyTray(SDL_Tray *tray)
SDL_RemovePath(tray->icon_dir);
}
+ if (tray->menu_cached) {
+ g_object_unref(tray->menu_cached);
+ }
+
if (tray->indicator) {
g_object_unref(tray->indicator);
}