diff --git a/src/core/unix/SDL_gtk.c b/src/core/unix/SDL_gtk.c index 323b417bd4..53af04b21c 100644 --- a/src/core/unix/SDL_gtk.c +++ b/src/core/unix/SDL_gtk.c @@ -114,8 +114,8 @@ static bool InitGtk(void) SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_submenu); SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_get_label); SDL_GTK_SYM(gtk, libgtk, gtk, menu_item_set_label); - SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append); - SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert); + SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_append); + SDL_GTK_SYM(gtk, libgtk, gtk, menu_shell_insert); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_new_with_label); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_get_active); SDL_GTK_SYM(gtk, libgtk, gtk, check_menu_item_set_active); @@ -127,6 +127,7 @@ static bool InitGtk(void) SDL_GTK_SYM(gtk, libgdk, g, signal_connect_data); SDL_GTK_SYM(gtk, libgdk, g, mkdtemp); + SDL_GTK_SYM(gtk, libgdk, g, get_user_cache_dir); SDL_GTK_SYM(gtk, libgdk, g, object_ref); SDL_GTK_SYM(gtk, libgdk, g, object_ref_sink); SDL_GTK_SYM(gtk, libgdk, g, object_unref); diff --git a/src/core/unix/SDL_gtk.h b/src/core/unix/SDL_gtk.h index e966dac45e..2ec3ea0b09 100644 --- a/src/core/unix/SDL_gtk.h +++ b/src/core/unix/SDL_gtk.h @@ -80,6 +80,7 @@ typedef struct SDL_GtkContext gulong (*signal_connect_data)(gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, SDL_GConnectFlags connect_flags); void (*object_unref)(gpointer object); gchar *(*mkdtemp)(gchar *template); + gchar *(*get_user_cache_dir)(void); gpointer (*object_ref_sink)(gpointer object); gpointer (*object_ref)(gpointer object); void (*object_get)(gpointer object, const gchar *first_property_name, ...); diff --git a/src/tray/unix/SDL_tray.c b/src/tray/unix/SDL_tray.c index 23863269ee..a9863932b1 100644 --- a/src/tray/unix/SDL_tray.c +++ b/src/tray/unix/SDL_tray.c @@ -153,15 +153,11 @@ struct SDL_TrayEntry { SDL_TrayMenu *submenu; }; -/* Template for g_mkdtemp(). The Xs will get replaced with a random - * directory name, which is created safely and atomically. */ -#define ICON_DIR_TEMPLATE "/tmp/SDL-tray-XXXXXX" - struct SDL_Tray { AppIndicator *indicator; SDL_TrayMenu *menu; - char icon_dir[sizeof(ICON_DIR_TEMPLATE)]; - char icon_path[256]; + char *icon_dir; + char *icon_path; GtkMenuShell *menu_cached; }; @@ -188,13 +184,13 @@ static bool new_tmp_filename(SDL_Tray *tray) { static int count = 0; - int would_have_written = SDL_snprintf(tray->icon_path, sizeof(tray->icon_path), "%s/%d.bmp", tray->icon_dir, count++); + int would_have_written = SDL_asprintf(&tray->icon_path, "%s/%d.bmp", tray->icon_dir, count++); - if (would_have_written > 0 && ((unsigned) would_have_written) < sizeof(tray->icon_path) - 1) { + if (would_have_written >= 0) { return true; } - tray->icon_path[0] = '\0'; + tray->icon_path = NULL; SDL_SetError("Failed to format new temporary filename"); return false; } @@ -254,29 +250,47 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) SDL_Tray *tray = NULL; SDL_GtkContext *gtk = SDL_Gtk_EnterContext(); if (!gtk) { - goto error; + goto tray_error; } tray = (SDL_Tray *)SDL_calloc(1, sizeof(*tray)); if (!tray) { - goto error; + goto tray_error; + } + + const gchar *cache_dir = gtk->g.get_user_cache_dir(); + if (!cache_dir) { + SDL_SetError("Cannot get user cache directory: %s", strerror(errno)); + goto tray_error; + } + + char *sdl_dir; + SDL_asprintf(&sdl_dir, "%s/SDL", cache_dir); + if (!SDL_GetPathInfo(sdl_dir, NULL)) { + if (!SDL_CreateDirectory(sdl_dir)) { + SDL_SetError("Cannot create directory for tray icon: %s", strerror(errno)); + goto sdl_dir_error; + } } /* On success, g_mkdtemp edits its argument in-place to replace the Xs * with a random directory name, which it creates safely and atomically. * On failure, it sets errno. */ - SDL_strlcpy(tray->icon_dir, ICON_DIR_TEMPLATE, sizeof(tray->icon_dir)); + SDL_asprintf(&tray->icon_dir, "%s/tray-XXXXXX", sdl_dir); if (!gtk->g.mkdtemp(tray->icon_dir)) { SDL_SetError("Cannot create directory for tray icon: %s", strerror(errno)); - goto error; + goto icon_dir_error; } if (icon) { if (!new_tmp_filename(tray)) { - goto error; + goto icon_dir_error; } SDL_SaveBMP(icon, tray->icon_path); + } else { + // allocate a dummy icon path + SDL_asprintf(&tray->icon_path, " "); } tray->indicator = app_indicator_new(get_appindicator_id(), tray->icon_path, @@ -293,7 +307,13 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip) return tray; -error: +icon_dir_error: + SDL_free(tray->icon_dir); + +sdl_dir_error: + SDL_free(sdl_dir); + +tray_error: if (tray) { SDL_free(tray); } @@ -311,8 +331,10 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon) return; } - if (*tray->icon_path) { + if (tray->icon_path) { SDL_RemovePath(tray->icon_path); + SDL_free(tray->icon_path); + tray->icon_path = NULL; } /* AppIndicator caches the icon files; always change filename to avoid caching */ @@ -321,7 +343,8 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon) SDL_SaveBMP(icon, tray->icon_path); app_indicator_set_icon(tray->indicator, tray->icon_path); } else { - *tray->icon_path = '\0'; + SDL_free(tray->icon_path); + tray->icon_path = NULL; app_indicator_set_icon(tray->indicator, NULL); } } @@ -714,12 +737,14 @@ void SDL_DestroyTray(SDL_Tray *tray) DestroySDLMenu(tray->menu); } - if (*tray->icon_path) { + if (tray->icon_path) { SDL_RemovePath(tray->icon_path); + SDL_free(tray->icon_path); } - if (*tray->icon_dir) { + if (tray->icon_dir) { SDL_RemovePath(tray->icon_dir); + SDL_free(tray->icon_dir); } SDL_GtkContext *gtk = SDL_Gtk_EnterContext();