SDL_Libretro 0.1.0
SDL3-power libretro frontend.
Loading...
Searching...
No Matches
SDL_libretro_messages.h
Go to the documentation of this file.
1
7#if defined(SDL_LIBRETRO_IMPLEMENTATION) && !defined(SDL_LIBRETRO_MESSAGES_IMPL_ONCE)
8#define SDL_LIBRETRO_MESSAGES_IMPL_ONCE
9
10static void SDL_Libretro_OsdPush(SDL_Libretro* lr, const char* msg, double durationSec, unsigned priority, enum retro_message_type type, int8_t progress) {
11 if (!lr || !msg || msg[0] == '\0') return;
12
13 // Negative (or NaN) durations expire right away, and huge ones are capped so
14 // the conversion to milliseconds stays in range.
15 if (!(durationSec > 0.0)) durationSec = 0.0;
16 if (durationSec > (double)SDL_MAX_UINT32) durationSec = (double)SDL_MAX_UINT32;
17 Uint64 endMs = SDL_GetTicks() + (Uint64)(durationSec * 1000.0);
18
19 for (int i = 0; i < lr->osdQueueCount; i++) {
20 if (lr->osdQueue[i].msg && SDL_strcmp(lr->osdQueue[i].msg, msg) == 0) {
21 lr->osdQueue[i].endTimeMs = endMs;
22 lr->osdQueue[i].priority = priority;
23 lr->osdQueue[i].type = type;
24 lr->osdQueue[i].progress = progress;
25 return;
26 }
27 }
28
29 // Copy first, so an allocation failure never leaves a slot with a NULL msg.
30 char* dup = SDL_strdup(msg);
31 if (!dup) return;
32
33 Uint64 now = SDL_GetTicks();
34 int slot = -1;
35 for (int i = 0; i < lr->osdQueueCount; i++) {
36 if (now > lr->osdQueue[i].endTimeMs) {
37 SDL_free(lr->osdQueue[i].msg);
38 lr->osdQueue[i].msg = NULL;
39 slot = i;
40 break;
41 }
42 }
43
44 if (slot < 0) {
45 if (lr->osdQueueCount >= lr->osdQueueCapacity) {
46 int newCap = lr->osdQueueCapacity ? lr->osdQueueCapacity * 2 : SDL_LIBRETRO_OSD_INITIAL_CAPACITY;
47 SDL_LibretroOsdEntry* newQueue = (SDL_LibretroOsdEntry*)SDL_realloc(lr->osdQueue, (size_t)newCap * sizeof(SDL_LibretroOsdEntry));
48 if (!newQueue) {
49 SDL_free(dup);
50 return;
51 }
52 lr->osdQueue = newQueue;
53 lr->osdQueueCapacity = newCap;
54 }
55 slot = lr->osdQueueCount++;
56 }
57 lr->osdQueue[slot].msg = dup;
58 lr->osdQueue[slot].endTimeMs = endMs;
59 lr->osdQueue[slot].priority = priority;
60 lr->osdQueue[slot].type = type;
61 lr->osdQueue[slot].progress = progress;
62}
63
68static void SDL_Libretro_OsdExpire(SDL_Libretro* lr) {
69 Uint64 now = SDL_GetTicks();
70 int dst = 0;
71
72 for (int i = 0; i < lr->osdQueueCount; i++) {
73 if (now > lr->osdQueue[i].endTimeMs) {
74 SDL_free(lr->osdQueue[i].msg);
75 lr->osdQueue[i].msg = NULL;
76 continue;
77 }
78 if (dst != i) {
79 lr->osdQueue[dst] = lr->osdQueue[i];
80 }
81 dst++;
82 }
83 lr->osdQueueCount = dst;
84}
85
92static int SDL_Libretro_OsdFindTop(const SDL_Libretro* lr) {
93 Uint64 now = SDL_GetTicks();
94 int best = -1;
95 unsigned bestPri = 0;
96
97 for (int i = 0; i < lr->osdQueueCount; i++) {
98 if (now > lr->osdQueue[i].endTimeMs) continue;
99 if (best == -1 || lr->osdQueue[i].priority > bestPri) {
100 bestPri = lr->osdQueue[i].priority;
101 best = i;
102 }
103 }
104 return best;
105}
106
107static void SDL_Libretro_FreeMessages(SDL_Libretro* lr) {
108 for (int i = 0; i < lr->osdQueueCount; i++) {
109 SDL_free(lr->osdQueue[i].msg);
110 }
111 SDL_free(lr->osdQueue);
112 lr->osdQueue = NULL;
113 lr->osdQueueCount = 0;
114 lr->osdQueueCapacity = 0;
115}
116
129void SDL_Libretro_SetMessage(SDL_Libretro* lr, const char* msg, double duration) {
130 if (!lr) return;
131 if (!msg || msg[0] == '\0') {
132 for (int i = 0; i < lr->osdQueueCount; i++) {
133 SDL_free(lr->osdQueue[i].msg);
134 }
135 lr->osdQueueCount = 0;
136 return;
137 }
138 SDL_Libretro_OsdPush(lr, msg, duration, 0, RETRO_MESSAGE_TYPE_NOTIFICATION, -1);
139}
140
153const char* SDL_Libretro_GetMessage(SDL_Libretro* lr) {
154 if (!lr || lr->osdQueueCount == 0) return NULL;
155 int top = SDL_Libretro_OsdFindTop(lr);
156 if (top < 0) return NULL;
157 return lr->osdQueue[top].msg;
158}
159
169int SDL_Libretro_GetMessageProgress(SDL_Libretro* lr) {
170 if (!lr || lr->osdQueueCount == 0) return -1;
171 int top = SDL_Libretro_OsdFindTop(lr);
172 if (top < 0) return -1;
173 return lr->osdQueue[top].progress;
174}
175
186int SDL_Libretro_GetMessageType(SDL_Libretro* lr) {
187 if (!lr || lr->osdQueueCount == 0) return 0;
188 int top = SDL_Libretro_OsdFindTop(lr);
189 if (top < 0) return 0;
190 return (int)lr->osdQueue[top].type;
191}
192
203unsigned SDL_Libretro_GetMessageCount(SDL_Libretro* lr) {
204 if (!lr || lr->osdQueueCount == 0) return 0;
205 SDL_Libretro_OsdExpire(lr);
206 return (unsigned)lr->osdQueueCount;
207}
208
221bool SDL_Libretro_GetMessageByIndex(SDL_Libretro* lr, int index, const char** msg, int* progress, int* type) {
222 if (!lr) return false;
223 if (index < 0) {
224 index = SDL_Libretro_OsdFindTop(lr);
225 }
226 if (index < 0 || index >= lr->osdQueueCount) return false;
227 if (msg) *msg = lr->osdQueue[index].msg;
228 if (progress) *progress = lr->osdQueue[index].progress;
229 if (type) *type = (int)lr->osdQueue[index].type;
230 return true;
231}
232
233#endif /* SDL_LIBRETRO_MESSAGES_IMPL_ONCE */
void SDL_Libretro_SetMessage(SDL_Libretro *lr, const char *msg, double duration)
Add a message to be displayed within the libretro context.
bool SDL_Libretro_GetMessageByIndex(SDL_Libretro *lr, int index, const char **msg, int *progress, int *type)
Retrieves all message details for the given message index.
int SDL_Libretro_GetMessageProgress(SDL_Libretro *lr)
Gets the progress of the message returned by SDL_Libretro_GetMessage().
int SDL_Libretro_GetMessageType(SDL_Libretro *lr)
Gets the type of the message returned by SDL_Libretro_GetMessage().
const char * SDL_Libretro_GetMessage(SDL_Libretro *lr)
Gets the most relevant libretro message to display from the queue.
unsigned SDL_Libretro_GetMessageCount(SDL_Libretro *lr)
Gets the number of messages currently in the queue.