mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-05 19:08:12 +00:00
tray: improved error checking
Also clean up any existing trays when the program quits Fixes https://github.com/libsdl-org/SDL/issues/11893
This commit is contained in:
@@ -51,6 +51,7 @@
|
||||
#include "sensor/SDL_sensor_c.h"
|
||||
#include "stdlib/SDL_getenv_c.h"
|
||||
#include "thread/SDL_thread_c.h"
|
||||
#include "tray/SDL_tray_utils.h"
|
||||
#include "video/SDL_pixels_c.h"
|
||||
#include "video/SDL_surface_c.h"
|
||||
#include "video/SDL_video_c.h"
|
||||
@@ -642,6 +643,7 @@ void SDL_Quit(void)
|
||||
SDL_HelperWindowDestroy();
|
||||
#endif
|
||||
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
|
||||
SDL_CleanupTrays();
|
||||
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
SDL_DBus_Quit();
|
||||
|
@@ -178,6 +178,22 @@ bool SDL_ObjectValid(void *object, SDL_ObjectType type)
|
||||
return (((SDL_ObjectType)(uintptr_t)object_type) == type);
|
||||
}
|
||||
|
||||
int SDL_GetObjects(SDL_ObjectType type, void **objects, int count)
|
||||
{
|
||||
const void *object, *object_type;
|
||||
void *iter = NULL;
|
||||
int num_objects = 0;
|
||||
while (SDL_IterateHashTable(SDL_objects, &object, &object_type, &iter)) {
|
||||
if ((SDL_ObjectType)(uintptr_t)object_type == type) {
|
||||
if (num_objects < count) {
|
||||
objects[num_objects] = (void *)object;
|
||||
}
|
||||
++num_objects;
|
||||
}
|
||||
}
|
||||
return num_objects;
|
||||
}
|
||||
|
||||
void SDL_SetObjectsInvalid(void)
|
||||
{
|
||||
if (SDL_ShouldQuit(&SDL_objects_init)) {
|
||||
@@ -217,6 +233,9 @@ void SDL_SetObjectsInvalid(void)
|
||||
case SDL_OBJECT_TYPE_THREAD:
|
||||
type = "thread";
|
||||
break;
|
||||
case SDL_OBJECT_TYPE_TRAY:
|
||||
type = "SDL_Tray";
|
||||
break;
|
||||
default:
|
||||
type = "unknown object";
|
||||
break;
|
||||
|
@@ -61,12 +61,14 @@ typedef enum
|
||||
SDL_OBJECT_TYPE_HIDAPI_DEVICE,
|
||||
SDL_OBJECT_TYPE_HIDAPI_JOYSTICK,
|
||||
SDL_OBJECT_TYPE_THREAD,
|
||||
SDL_OBJECT_TYPE_TRAY,
|
||||
|
||||
} SDL_ObjectType;
|
||||
|
||||
extern Uint32 SDL_GetNextObjectID(void);
|
||||
extern void SDL_SetObjectValid(void *object, SDL_ObjectType type, bool valid);
|
||||
extern bool SDL_ObjectValid(void *object, SDL_ObjectType type);
|
||||
extern int SDL_GetObjects(SDL_ObjectType type, void **objects, int count);
|
||||
extern void SDL_SetObjectsInvalid(void);
|
||||
|
||||
extern const char *SDL_GetPersistentString(const char *string);
|
||||
|
@@ -27,38 +27,65 @@
|
||||
|
||||
static int active_trays = 0;
|
||||
|
||||
extern void SDL_IncrementTrayCount(void)
|
||||
void SDL_RegisterTray(SDL_Tray *tray)
|
||||
{
|
||||
if (++active_trays < 1) {
|
||||
SDL_Log("Active tray count corrupted (%d < 1), this is a bug. The app may close or fail to close unexpectedly.", active_trays);
|
||||
}
|
||||
SDL_SetObjectValid(tray, SDL_OBJECT_TYPE_TRAY, true);
|
||||
|
||||
++active_trays;
|
||||
}
|
||||
|
||||
extern void SDL_DecrementTrayCount(void)
|
||||
void SDL_UnregisterTray(SDL_Tray *tray)
|
||||
{
|
||||
int toplevel_count = 0;
|
||||
SDL_Window *n;
|
||||
SDL_assert(SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY));
|
||||
|
||||
if (--active_trays < 0) {
|
||||
SDL_Log("Active tray count corrupted (%d < 0), this is a bug. The app may close or fail to close unexpectedly.", active_trays);
|
||||
SDL_SetObjectValid(tray, SDL_OBJECT_TYPE_TRAY, false);
|
||||
|
||||
--active_trays;
|
||||
if (active_trays > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (n = SDL_GetVideoDevice()->windows; n; n = n->next) {
|
||||
if (!n->parent && !(n->flags & SDL_WINDOW_HIDDEN)) {
|
||||
++toplevel_count;
|
||||
int toplevel_count = 0;
|
||||
SDL_Window **windows = SDL_GetWindows(NULL);
|
||||
if (windows) {
|
||||
for (int i = 0; windows[i]; ++i) {
|
||||
SDL_Window *window = windows[i];
|
||||
if (!window->parent && !(window->flags & SDL_WINDOW_HIDDEN)) {
|
||||
++toplevel_count;
|
||||
}
|
||||
}
|
||||
SDL_free(windows);
|
||||
}
|
||||
|
||||
if (toplevel_count < 1) {
|
||||
if (toplevel_count == 0) {
|
||||
SDL_SendQuit();
|
||||
}
|
||||
}
|
||||
|
||||
extern bool SDL_HasNoActiveTrays(void)
|
||||
void SDL_CleanupTrays(void)
|
||||
{
|
||||
return active_trays < 1;
|
||||
if (active_trays == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
void **trays = (void **)SDL_malloc(active_trays * sizeof(*trays));
|
||||
if (!trays) {
|
||||
return;
|
||||
}
|
||||
|
||||
int count = SDL_GetObjects(SDL_OBJECT_TYPE_TRAY, trays, active_trays);
|
||||
SDL_assert(count == active_trays);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SDL_DestroyTray((SDL_Tray *)trays[i]);
|
||||
}
|
||||
SDL_free(trays);
|
||||
}
|
||||
|
||||
bool SDL_HasNoActiveTrays(void)
|
||||
{
|
||||
return active_trays == 0;
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
extern void SDL_IncrementTrayCount(void);
|
||||
extern void SDL_DecrementTrayCount(void);
|
||||
extern void SDL_RegisterTray(SDL_Tray *tray);
|
||||
extern void SDL_UnregisterTray(SDL_Tray *tray);
|
||||
extern void SDL_CleanupTrays(void);
|
||||
extern bool SDL_HasNoActiveTrays(void);
|
||||
|
@@ -80,8 +80,16 @@ static void DestroySDLMenu(SDL_TrayMenu *menu)
|
||||
|
||||
SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
{
|
||||
if (icon) {
|
||||
icon = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!icon) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Tray *tray = (SDL_Tray *)SDL_calloc(1, sizeof(*tray));
|
||||
if (!tray) {
|
||||
SDL_DestroySurface(icon);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -97,22 +105,17 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
}
|
||||
|
||||
if (icon) {
|
||||
SDL_Surface *iconfmt = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!iconfmt) {
|
||||
goto skip_putting_an_icon;
|
||||
}
|
||||
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&iconfmt->pixels
|
||||
pixelsWide:iconfmt->w
|
||||
pixelsHigh:iconfmt->h
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&icon->pixels
|
||||
pixelsWide:icon->w
|
||||
pixelsHigh:icon->h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:iconfmt->pitch
|
||||
bytesPerRow:icon->pitch
|
||||
bitsPerPixel:32];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(iconfmt->w, iconfmt->h)];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(icon->w, icon->h)];
|
||||
[iconimg addRepresentation:bitmap];
|
||||
|
||||
/* A typical icon size is 22x22 on macOS. Failing to resize the icon
|
||||
@@ -125,39 +128,42 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
|
||||
tray->statusItem.button.image = iconimg22;
|
||||
|
||||
SDL_DestroySurface(iconfmt);
|
||||
SDL_DestroySurface(icon);
|
||||
}
|
||||
|
||||
skip_putting_an_icon:
|
||||
SDL_IncrementTrayCount();
|
||||
SDL_RegisterTray(tray);
|
||||
|
||||
return tray;
|
||||
}
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!icon) {
|
||||
tray->statusItem.button.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Surface *iconfmt = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!iconfmt) {
|
||||
icon = SDL_ConvertSurface(icon, SDL_PIXELFORMAT_RGBA32);
|
||||
if (!icon) {
|
||||
tray->statusItem.button.image = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&iconfmt->pixels
|
||||
pixelsWide:iconfmt->w
|
||||
pixelsHigh:iconfmt->h
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:(unsigned char **)&icon->pixels
|
||||
pixelsWide:icon->w
|
||||
pixelsHigh:icon->h
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSCalibratedRGBColorSpace
|
||||
bytesPerRow:iconfmt->pitch
|
||||
bytesPerRow:icon->pitch
|
||||
bitsPerPixel:32];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(iconfmt->w, iconfmt->h)];
|
||||
NSImage *iconimg = [[NSImage alloc] initWithSize:NSMakeSize(icon->w, icon->h)];
|
||||
[iconimg addRepresentation:bitmap];
|
||||
|
||||
/* A typical icon size is 22x22 on macOS. Failing to resize the icon
|
||||
@@ -170,11 +176,15 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
|
||||
tray->statusItem.button.image = iconimg22;
|
||||
|
||||
SDL_DestroySurface(iconfmt);
|
||||
SDL_DestroySurface(icon);
|
||||
}
|
||||
|
||||
void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tooltip) {
|
||||
tray->statusItem.button.toolTip = [NSString stringWithUTF8String:tooltip];
|
||||
} else {
|
||||
@@ -184,6 +194,11 @@ void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *menu = (SDL_TrayMenu *)SDL_calloc(1, sizeof(*menu));
|
||||
if (!menu) {
|
||||
return NULL;
|
||||
@@ -206,11 +221,21 @@ SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tray->menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry->submenu) {
|
||||
SDL_SetError("Tray entry submenu already exists");
|
||||
return NULL;
|
||||
@@ -243,11 +268,21 @@ SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->submenu;
|
||||
}
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
*size = menu->nEntries;
|
||||
}
|
||||
@@ -293,6 +328,11 @@ void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos < -1 || pos > menu->nEntries) {
|
||||
SDL_InvalidParamError("pos");
|
||||
return NULL;
|
||||
@@ -347,28 +387,44 @@ SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *la
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
[entry->nsitem setTitle:[NSString stringWithUTF8String:label]];
|
||||
}
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return [[entry->nsitem title] UTF8String];
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
[entry->nsitem setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)];
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return entry->nsitem.state == NSControlStateValueOn;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot update check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -377,8 +433,7 @@ void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot fetch check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -387,6 +442,10 @@ bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->callback = callback;
|
||||
entry->userdata = userdata;
|
||||
}
|
||||
@@ -408,25 +467,42 @@ void SDL_ClickTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->parent;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return menu->parent_entry;
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return menu->parent_tray;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
if (!tray) {
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_UnregisterTray(tray);
|
||||
|
||||
[[NSStatusBar systemStatusBar] removeStatusItem:tray->statusItem];
|
||||
|
||||
if (tray->menu) {
|
||||
@@ -434,8 +510,6 @@ void SDL_DestroyTray(SDL_Tray *tray)
|
||||
}
|
||||
|
||||
SDL_free(tray);
|
||||
|
||||
SDL_DecrementTrayCount();
|
||||
}
|
||||
|
||||
#endif // SDL_PLATFORM_MACOS
|
||||
|
@@ -33,29 +33,27 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -66,57 +64,50 @@ SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return false;
|
||||
return SDL_InvalidParamError("entry");
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
return false;
|
||||
return SDL_InvalidParamError("entry");
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
void SDL_ClickTrayEntry(SDL_TrayEntry *entry)
|
||||
@@ -125,25 +116,24 @@ void SDL_ClickTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
SDL_Unsupported();
|
||||
}
|
||||
|
||||
#endif // !SDL_PLATFORM_MACOS
|
||||
|
@@ -144,7 +144,7 @@ static void quit_gtk(void)
|
||||
|
||||
static bool init_gtk(void)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -434,13 +434,17 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
|
||||
app_indicator_set_status(tray->indicator, APP_INDICATOR_STATUS_ACTIVE);
|
||||
|
||||
SDL_IncrementTrayCount();
|
||||
SDL_RegisterTray(tray);
|
||||
|
||||
return tray;
|
||||
}
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*tray->icon_path) {
|
||||
SDL_RemovePath(tray->icon_path);
|
||||
}
|
||||
@@ -463,6 +467,11 @@ void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tray->menu = (SDL_TrayMenu *)SDL_calloc(1, sizeof(*tray->menu));
|
||||
if (!tray->menu) {
|
||||
return NULL;
|
||||
@@ -481,11 +490,21 @@ SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tray->menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry->submenu) {
|
||||
SDL_SetError("Tray entry submenu already exists");
|
||||
return NULL;
|
||||
@@ -514,11 +533,21 @@ SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->submenu;
|
||||
}
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
*size = menu->nEntries;
|
||||
}
|
||||
@@ -563,6 +592,11 @@ void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos < -1 || pos > menu->nEntries) {
|
||||
SDL_InvalidParamError("pos");
|
||||
return NULL;
|
||||
@@ -625,18 +659,26 @@ SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *la
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_menu_item_set_label(GTK_MENU_ITEM(entry->item), label);
|
||||
}
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gtk_menu_item_get_label(GTK_MENU_ITEM(entry->item));
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot update check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -647,8 +689,7 @@ void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Cannot fetch check for entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -657,16 +698,28 @@ bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive(entry->item, enabled);
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return gtk_widget_get_sensitive(entry->item);
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->callback = callback;
|
||||
entry->userdata = userdata;
|
||||
}
|
||||
@@ -688,6 +741,11 @@ void SDL_ClickTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->parent;
|
||||
}
|
||||
|
||||
@@ -698,15 +756,22 @@ SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return menu->parent_tray;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
if (!tray) {
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_UnregisterTray(tray);
|
||||
|
||||
if (tray->menu) {
|
||||
DestroySDLMenu(tray->menu);
|
||||
}
|
||||
@@ -725,8 +790,6 @@ void SDL_DestroyTray(SDL_Tray *tray)
|
||||
|
||||
SDL_free(tray);
|
||||
|
||||
SDL_DecrementTrayCount();
|
||||
|
||||
if (SDL_HasNoActiveTrays()) {
|
||||
gtk_main_quit();
|
||||
gtk_thread_active = false;
|
||||
|
@@ -252,13 +252,17 @@ SDL_Tray *SDL_CreateTray(SDL_Surface *icon, const char *tooltip)
|
||||
|
||||
SetWindowLongPtr(tray->hwnd, GWLP_USERDATA, (LONG_PTR) tray);
|
||||
|
||||
SDL_IncrementTrayCount();
|
||||
SDL_RegisterTray(tray);
|
||||
|
||||
return tray;
|
||||
}
|
||||
|
||||
void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tray->icon) {
|
||||
DestroyIcon(tray->icon);
|
||||
}
|
||||
@@ -281,6 +285,10 @@ void SDL_SetTrayIcon(SDL_Tray *tray, SDL_Surface *icon)
|
||||
|
||||
void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tooltip) {
|
||||
wchar_t *tooltipw = WIN_UTF8ToStringW(tooltip);
|
||||
SDL_wcslcpy(tray->nid.szTip, tooltipw, sizeof(tray->nid.szTip) / sizeof(*tray->nid.szTip));
|
||||
@@ -294,6 +302,11 @@ void SDL_SetTrayTooltip(SDL_Tray *tray, const char *tooltip)
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tray->menu = (SDL_TrayMenu *)SDL_calloc(1, sizeof(*tray->menu));
|
||||
|
||||
if (!tray->menu) {
|
||||
@@ -309,13 +322,24 @@ SDL_TrayMenu *SDL_CreateTrayMenu(SDL_Tray *tray)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayMenu(SDL_Tray *tray)
|
||||
{
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
SDL_InvalidParamError("tray");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tray->menu;
|
||||
}
|
||||
|
||||
SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!entry->submenu) {
|
||||
SDL_SetError("Cannot create submenu for entry not created with SDL_TRAYENTRY_SUBMENU");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->submenu;
|
||||
@@ -323,11 +347,21 @@ SDL_TrayMenu *SDL_CreateTraySubmenu(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTraySubmenu(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->submenu;
|
||||
}
|
||||
|
||||
const SDL_TrayEntry **SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
*size = menu->nEntries;
|
||||
}
|
||||
@@ -376,6 +410,11 @@ void SDL_RemoveTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos < -1 || pos > menu->nEntries) {
|
||||
SDL_InvalidParamError("pos");
|
||||
return NULL;
|
||||
@@ -474,6 +513,10 @@ SDL_TrayEntry *SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *la
|
||||
|
||||
void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_snprintf(entry->label_cache, sizeof(entry->label_cache), "%s", label);
|
||||
|
||||
wchar_t *label_w = escape_label(label);
|
||||
@@ -498,13 +541,17 @@ void SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, const char *label)
|
||||
|
||||
const char *SDL_GetTrayEntryLabel(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->label_cache;
|
||||
}
|
||||
|
||||
void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Can't check/uncheck tray entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -513,8 +560,7 @@ void SDL_SetTrayEntryChecked(SDL_TrayEntry *entry, bool checked)
|
||||
|
||||
bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
SDL_SetError("Can't get check status of tray entry not created with SDL_TRAYENTRY_CHECKBOX");
|
||||
if (!entry || !(entry->flags & SDL_TRAYENTRY_CHECKBOX)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -529,11 +575,19 @@ bool SDL_GetTrayEntryChecked(SDL_TrayEntry *entry)
|
||||
|
||||
void SDL_SetTrayEntryEnabled(SDL_TrayEntry *entry, bool enabled)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnableMenuItem(entry->parent->hMenu, (UINT) entry->id, MF_BYCOMMAND | (enabled ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
|
||||
}
|
||||
|
||||
bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MENUITEMINFOW mii;
|
||||
mii.cbSize = sizeof(MENUITEMINFOW);
|
||||
mii.fMask = MIIM_STATE;
|
||||
@@ -545,6 +599,10 @@ bool SDL_GetTrayEntryEnabled(SDL_TrayEntry *entry)
|
||||
|
||||
void SDL_SetTrayEntryCallback(SDL_TrayEntry *entry, SDL_TrayCallback callback, void *userdata)
|
||||
{
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry->callback = callback;
|
||||
entry->userdata = userdata;
|
||||
}
|
||||
@@ -566,25 +624,42 @@ void SDL_ClickTrayEntry(SDL_TrayEntry *entry)
|
||||
|
||||
SDL_TrayMenu *SDL_GetTrayEntryParent(SDL_TrayEntry *entry)
|
||||
{
|
||||
if (!entry) {
|
||||
SDL_InvalidParamError("entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return entry->parent;
|
||||
}
|
||||
|
||||
SDL_TrayEntry *SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return menu->parent_entry;
|
||||
}
|
||||
|
||||
SDL_Tray *SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu)
|
||||
{
|
||||
if (!menu) {
|
||||
SDL_InvalidParamError("menu");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return menu->parent_tray;
|
||||
}
|
||||
|
||||
void SDL_DestroyTray(SDL_Tray *tray)
|
||||
{
|
||||
if (!tray) {
|
||||
if (!SDL_ObjectValid(tray, SDL_OBJECT_TYPE_TRAY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_UnregisterTray(tray);
|
||||
|
||||
Shell_NotifyIconW(NIM_DELETE, &tray->nid);
|
||||
|
||||
if (tray->menu) {
|
||||
@@ -600,6 +675,4 @@ void SDL_DestroyTray(SDL_Tray *tray)
|
||||
}
|
||||
|
||||
SDL_free(tray);
|
||||
|
||||
SDL_DecrementTrayCount();
|
||||
}
|
||||
|
Reference in New Issue
Block a user