ref: 328b1c845f21f5b47ba8156399245f2c3b1a4159
parent: ea7727d3b68920cfa96cae9ada2961a5fe1c0eda
author: laamaa <jonne.kokkonen@gmail.com>
date: Tue Apr 15 06:58:10 EDT 2025
callback based functionality: destroy screensaver resources on exit, avoid unnecessary draw cycles with screensaver
--- a/src/main.c
+++ b/src/main.c
@@ -6,15 +6,14 @@
// #define DEBUG_MSG
#include <SDL3/SDL.h>
+#include <SDL3/SDL_init.h>
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h>
-#include <signal.h>
#include <stdlib.h>
#include "SDL2_inprint.h"
#include "backends/audio.h"
#include "backends/m8.h"
-#include "command.h"
#include "config.h"
#include "gamecontrollers.h"
#include "input.h"
@@ -28,34 +27,31 @@
unsigned char app_suspended;
};
-static void do_wait_for_device(const char *preferred_device, unsigned char *m8_connected,
- config_params_s *conf, enum app_state *app_state) {+static void do_wait_for_device(struct app_context *ctx) {static Uint64 ticks_poll_device = 0;
+ static int screensaver_initialized = 0;
- if (*m8_connected == 0) {- screensaver_init();
- }
-
-#if TARGET_OS_IOS
// Handle app suspension
- if (app_suspended) {- SDL_Delay(conf->idle_ms);
- continue;
+ if (ctx->app_suspended) {+ SDL_Delay(ctx->conf.idle_ms);
+ return;
}
-#endif // TARGET_OS_IOS
+ if (!screensaver_initialized) {+ screensaver_initialized = screensaver_init();
+ }
screensaver_draw();
render_screen();
// Poll for M8 device every second
- if (*m8_connected == 0 && SDL_GetTicks() - ticks_poll_device > 1000) {+ if (ctx->device_connected == 0 && SDL_GetTicks() - ticks_poll_device > 1000) {ticks_poll_device = SDL_GetTicks();
- if (m8_initialize(0, preferred_device) == 1) {+ if (m8_initialize(0, ctx->preferred_device)) {- if (conf->audio_enabled == 1) {- if (audio_initialize(conf->audio_device_name, conf->audio_buffer_size) == 0) {+ if (ctx->conf.audio_enabled) {+ if (!audio_initialize(ctx->conf.audio_device_name, ctx->conf.audio_buffer_size)) {SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Cannot initialize audio");
- conf->audio_enabled = 0;
+ ctx->conf.audio_enabled = 0;
}
}
@@ -62,13 +58,15 @@
const int m8_enabled = m8_enable_and_reset_display();
// Device was found; enable display and proceed to the main loop
if (m8_enabled == 1) {- *app_state = RUN;
- *m8_connected = 1;
+ ctx->app_state = RUN;
+ ctx->device_connected = 1;
screensaver_destroy();
+ screensaver_initialized = 0;
} else {SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Device not detected.");
- *app_state = QUIT;
+ ctx->app_state = QUIT;
screensaver_destroy();
+ screensaver_initialized = 0;
#ifdef USE_RTMIDI
show_error_message(
"Cannot initialize M8 remote display. Make sure you're running "
@@ -114,61 +112,6 @@
return device_connected;
}
-#if TARGET_OS_IOS
-// IOS events handler
-static bool SDLCALL handle_app_events(void *userdata, SDL_Event *event) {- const config_params_s *conf = (config_params_s *)userdata;
- switch (event->type) {- case SDL_EVENT_TERMINATING:
- /* Terminate the app.
- Shut everything down before returning from this function.
- */
- cleanup_resources(device_connected, conf);
- return 0;
- case SDL_EVENT_DID_ENTER_BACKGROUND:
- /* This will get called if the user accepted whatever sent your app to the background.
- If the user got a phone call and canceled it, you'll instead get an
- SDL_EVENT_DID_ENTER_FOREGROUND event and restart your loops. When you get this, you have 5
- seconds to save all your state or the app will be terminated. Your app is NOT active at this
- point.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_BACKGROUND");
- app_suspended = 1;
- if (device_connected)
- m8_pause_processing();
- return 0;
- case SDL_EVENT_LOW_MEMORY:
- /* You will get this when your app is paused and iOS wants more memory.
- Release as much memory as possible.
- */
- return 0;
- case SDL_EVENT_WILL_ENTER_BACKGROUND:
- /* Prepare your app to go into the background. Stop loops, etc.
- This gets called when the user hits the home button, or gets a call.
- */
- return 0;
- case SDL_EVENT_WILL_ENTER_FOREGROUND:
- /* This call happens when your app is coming back to the foreground.
- Restore all your state here.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_WILL_ENTER_FOREGROUND");
- app_suspended = 0;
- if (device_connected)
- m8_resume_processing();
- return 0;
- case SDL_EVENT_DID_ENTER_FOREGROUND:
- /* Restart your loops here.
- Your app is interactive and getting CPU again.
- */
- SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_FOREGROUND");
- return 0;
- default:
- /* No special processing, add it to the event queue */
- return 1;
- }
-}
-#endif // TARGET_OS_IOS
-
SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) {char *config_filename = NULL;
@@ -188,11 +131,6 @@
return SDL_APP_FAILURE;
}
-#if TARGET_OS_IOS
- // IOS events handler
- SDL_SetEventFilter(handle_app_events, &conf);
-#endif
-
#ifndef NDEBUG
SDL_SetLogPriorities(SDL_LOG_PRIORITY_DEBUG);
SDL_LogDebug(SDL_LOG_CATEGORY_TEST, "Running a Debug build");
@@ -201,11 +139,6 @@
gamecontrollers_initialize();
*appstate = ctx;
- return SDL_APP_CONTINUE;
-}
-
-SDL_AppResult SDL_AppIterate(void *appstate) {- struct app_context *ctx = appstate;
if (ctx->app_state == WAIT_FOR_DEVICE) { if (!ctx->device_connected) {ctx->device_connected =
@@ -222,10 +155,33 @@
ctx->device_connected = 0;
ctx->app_state = ctx->conf.wait_for_device ? WAIT_FOR_DEVICE : QUIT;
}
+ }
+
+ return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate) {+ struct app_context *ctx = appstate;
+ SDL_AppResult app_result = SDL_APP_CONTINUE;
+
+ switch (ctx->app_state) {+ case WAIT_FOR_DEVICE: {+ if (ctx->conf.wait_for_device) {+ do_wait_for_device(ctx);
+ }
+ break;
+ }
+
+ case RUN:
+ break;
+ case QUIT:
+ break;
}
+ return app_result;
+
if (ctx->conf.wait_for_device && ctx->app_state == WAIT_FOR_DEVICE) {- do_wait_for_device(ctx->preferred_device, &ctx->device_connected, &ctx->conf, &ctx->app_state);
+ do_wait_for_device(ctx);
} else if (!ctx->device_connected && ctx->app_state != WAIT_FOR_DEVICE) {return SDL_APP_FAILURE;
}
@@ -247,7 +203,10 @@
void SDL_AppQuit(void *appstate, SDL_AppResult result) {struct app_context *app = appstate;
- if (appstate) {+ if (app) {+ if (app->app_state == WAIT_FOR_DEVICE) {+ screensaver_destroy();
+ }
if (app->conf.audio_enabled) {audio_close();
}
@@ -265,10 +224,53 @@
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {- struct app_context *app = appstate;
+ struct app_context *ctx = appstate;
SDL_AppResult ret_val = SDL_APP_CONTINUE;
- if (event->type == SDL_EVENT_QUIT) {- ret_val = SDL_APP_SUCCESS;
- }
+
+ switch (event->type) {+ case SDL_EVENT_QUIT:
+ case SDL_EVENT_TERMINATING:
+ ret_val = SDL_APP_SUCCESS;
+ break;
+ case SDL_EVENT_DID_ENTER_BACKGROUND:
+ /* This will get called if the user accepted whatever sent your app to the background.
+ If the user got a phone call and canceled it, you'll instead get an
+ SDL_EVENT_DID_ENTER_FOREGROUND event and restart your loops. When you get this, you have 5
+ seconds to save all your state or the app will be terminated. Your app is NOT active at this
+ point.
+ */
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_BACKGROUND");
+ ctx->app_suspended = 1;
+ if (ctx->device_connected)
+ m8_pause_processing();
+ break;
+ case SDL_EVENT_LOW_MEMORY:
+ /* You will get this when your app is paused and iOS wants more memory.
+ Release as much memory as possible.
+ */
+ break;
+ case SDL_EVENT_WILL_ENTER_BACKGROUND:
+ /* Prepare your app to go into the background. Stop loops, etc.
+ This gets called when the user hits the home button, or gets a call.
+ */
+ break;
+ case SDL_EVENT_WILL_ENTER_FOREGROUND:
+ /* This call happens when your app is coming back to the foreground.
+ Restore all your state here.
+ */
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_WILL_ENTER_FOREGROUND");
+ break;
+ case SDL_EVENT_DID_ENTER_FOREGROUND:
+ /* Restart your loops here.
+ Your app is interactive and getting CPU again.
+ */
+ SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "Received SDL_EVENT_DID_ENTER_FOREGROUND");
+ ctx->app_suspended = 0;
+ if (ctx->device_connected) {+ m8_resume_processing();
+ }
+ default:
+ break;
+ }
return ret_val;
}
\ No newline at end of file
--- a/src/render.c
+++ b/src/render.c
@@ -37,6 +37,8 @@
static int texture_width = 320;
static int texture_height = 240;
+static int screensaver_initialized = 0;
+
struct inline_font *fonts[5] = {&font_v1_small, &font_v1_large, &font_v2_small, &font_v2_large,&font_v2_huge};
@@ -354,17 +356,21 @@
}
}
-void screensaver_init() {+int screensaver_init() {+ if (screensaver_initialized) {+ return 1;
+ }
renderer_set_font_mode(1);
global_background_color.r = 0, global_background_color.g = 0, global_background_color.b = 0;
fx_cube_init(rend, (SDL_Color){255, 255, 255, 255}, texture_width, texture_height,fonts[font_mode]->glyph_x);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Screensaver initialized");
+ screensaver_initialized = 1;
+ return 1;
}
void screensaver_draw() {- fx_cube_update();
- dirty = 1;
+ dirty = fx_cube_update();
}
void screensaver_destroy() {@@ -371,6 +377,7 @@
fx_cube_destroy();
renderer_set_font_mode(0);
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Screensaver destroyed");
+ screensaver_initialized = 0;
}
void renderer_fix_texture_scaling_after_window_resize(void) {--- a/src/render.h
+++ b/src/render.h
@@ -26,7 +26,7 @@
void show_error_message(const char *message);
-void screensaver_init();
+int screensaver_init();
void screensaver_draw();
void screensaver_destroy();
--
⑨