|
17 | 17 | #define IS_APP_INDICATOR APP_IS_INDICATOR ///< Define IS_APP_INDICATOR for app-indicator compatibility. |
18 | 18 | #endif |
19 | 19 | #include <libnotify/notify.h> |
20 | | -#define TRAY_APPINDICATOR_ID "tray-id" ///< Tray appindicator ID. |
| 20 | + |
| 21 | +#include <stdio.h> |
| 22 | +#include <unistd.h> |
| 23 | + |
| 24 | +// Use a per-process AppIndicator id to avoid DBus collisions when tests create multiple |
| 25 | +// tray instances in the same desktop/session. |
| 26 | +static unsigned long tray_appindicator_seq = 0; |
21 | 27 |
|
22 | 28 | // local includes |
23 | 29 | #include "tray.h" |
@@ -68,9 +74,23 @@ int tray_init(struct tray *tray) { |
68 | 74 | if (gtk_init_check(0, NULL) == FALSE) { |
69 | 75 | return -1; |
70 | 76 | } |
| 77 | + |
| 78 | + // If a previous tray instance wasn't fully torn down (common in unit tests), |
| 79 | + // drop our references before creating a new indicator. |
| 80 | + if (indicator != NULL) { |
| 81 | + g_object_unref(G_OBJECT(indicator)); |
| 82 | + indicator = NULL; |
| 83 | + } |
71 | 84 | loop_result = 0; |
72 | 85 | notify_init("tray-icon"); |
73 | | - indicator = app_indicator_new(TRAY_APPINDICATOR_ID, tray->icon, APP_INDICATOR_CATEGORY_APPLICATION_STATUS); |
| 86 | + // The id is used as part of the exported DBus object path. |
| 87 | + // Make it unique per *tray instance* to prevent collisions inside a single test process. |
| 88 | + // Avoid underscores and other characters that may be normalized/stripped. |
| 89 | + char appindicator_id[64]; |
| 90 | + tray_appindicator_seq++; |
| 91 | + snprintf(appindicator_id, sizeof(appindicator_id), "trayid%ld%lu", (long) getpid(), tray_appindicator_seq); |
| 92 | + |
| 93 | + indicator = app_indicator_new(appindicator_id, tray->icon, APP_INDICATOR_CATEGORY_APPLICATION_STATUS); |
74 | 94 | if (indicator == NULL || !IS_APP_INDICATOR(indicator)) { |
75 | 95 | return -1; |
76 | 96 | } |
@@ -159,11 +179,26 @@ void tray_show_menu(void) { |
159 | 179 | } |
160 | 180 |
|
161 | 181 | static gboolean tray_exit_internal(gpointer user_data) { |
| 182 | + (void) user_data; |
| 183 | + |
162 | 184 | if (currentNotification != NULL && NOTIFY_IS_NOTIFICATION(currentNotification)) { |
163 | 185 | int v = notify_notification_close(currentNotification, NULL); |
164 | 186 | if (v == TRUE) { |
165 | 187 | g_object_unref(G_OBJECT(currentNotification)); |
166 | 188 | } |
| 189 | + currentNotification = NULL; |
| 190 | + } |
| 191 | + |
| 192 | + if (current_menu != NULL) { |
| 193 | + g_object_unref(current_menu); |
| 194 | + current_menu = NULL; |
| 195 | + } |
| 196 | + |
| 197 | + if (indicator != NULL) { |
| 198 | + // Make the indicator passive before unref to encourage a clean DBus unexport. |
| 199 | + app_indicator_set_status(indicator, APP_INDICATOR_STATUS_PASSIVE); |
| 200 | + g_object_unref(G_OBJECT(indicator)); |
| 201 | + indicator = NULL; |
167 | 202 | } |
168 | 203 | notify_uninit(); |
169 | 204 | return G_SOURCE_REMOVE; |
|
0 commit comments