Skip to content
Permalink
Browse files

events: Let arbitrary signals to simulate iOS/Android backgrounding e…

…vents.

This lets you build a custom embedded device that roughly offers the "this
process is going to the background NOW" semantics of SDL on a mobile device.
  • Loading branch information
icculus committed Mar 15, 2019
1 parent 911bf62 commit 8a5a05c1685c8d3c8a100945d399b43e51106935
Showing with 165 additions and 48 deletions.
  1. +10 −0 CMakeLists.txt
  2. +37 −0 configure
  3. +26 −1 configure.in
  4. +1 −1 src/events/SDL_events.c
  5. +1 −1 src/events/SDL_events_c.h
  6. +90 −45 src/events/SDL_quit.c
@@ -341,6 +341,8 @@ set_option(VIDEO_VIVANTE "Use Vivante EGL video driver" ${UNIX_SYS})
dep_option(VIDEO_VULKAN "Enable Vulkan support" ON "ANDROID OR APPLE OR LINUX OR WINDOWS" OFF)
set_option(VIDEO_KMSDRM "Use KMS DRM video driver" ${UNIX_SYS})
dep_option(KMSDRM_SHARED "Dynamically load KMS DRM support" ON "VIDEO_KMSDRM" OFF)
option_string(BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" "OFF")
option_string(FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" "OFF")

# TODO: We should (should we?) respect cmake's ${BUILD_SHARED_LIBS} flag here
# The options below are for compatibility to configure's default behaviour.
@@ -384,6 +386,14 @@ else()
endif()
set(HAVE_ASSERTIONS ${ASSERTIONS})

if(NOT BACKGROUNDING_SIGNAL STREQUAL "OFF")
add_definitions("-DSDL_BACKGROUNDING_SIGNAL=${BACKGROUNDING_SIGNAL}")
endif()

if(NOT FOREGROUNDING_SIGNAL STREQUAL "OFF")
add_definitions("-DSDL_FOREGROUNDING_SIGNAL=${FOREGROUNDING_SIGNAL}")
endif()

# Compiler option evaluation
if(USE_GCC OR USE_CLANG)
# Check for -Wall first, so later things can override pieces of it.
@@ -870,6 +870,8 @@ enable_sdl_dlopen
enable_hidapi
enable_clock_gettime
enable_rpath
enable_backgrounding_signal
enable_foregrounding_signal
enable_render_d3d
'
ac_precious_vars='build_alias
@@ -1627,6 +1629,12 @@ Optional Features:
--enable-clock_gettime use clock_gettime() instead of gettimeofday() on
UNIX [[default=yes]]
--enable-rpath use an rpath when linking SDL [[default=yes]]
--enable-backgrounding-signal
number to use for magic backgrounding signal or 'no'
[[default=no]]
--enable-foregrounding-signal
number to use for magic foregrounding signal or 'no'
[[default=no]]
--enable-render-d3d enable the Direct3D render driver [[default=yes]]
Optional Packages:

}

CheckEventSignals()
{
# Check whether --enable-backgrounding-signal was given.
if test "${enable_backgrounding_signal+set}" = set; then :
enableval=$enable_backgrounding_signal;
else
enable_backgrounding_signal=no
fi

if test x$enable_backgrounding_signal != xno; then
EXTRA_CFLAGS="$EXTRA_CFLAGS -DSDL_BACKGROUNDING_SIGNAL=$enable_backgrounding_signal"
fi

# Check whether --enable-foregrounding-signal was given.
if test "${enable_foregrounding_signal+set}" = set; then :
enableval=$enable_foregrounding_signal;
else
enable_foregrounding_signal=no
fi

if test x$enable_foregrounding_signal != xno; then
EXTRA_CFLAGS="$EXTRA_CFLAGS -DSDL_FOREGROUNDING_SIGNAL=$enable_foregrounding_signal"
fi
}



CheckWarnAll

CheckEventSignals

case "$host" in
*-*-linux*|*-*-uclinux*|*-*-gnu*|*-*-k*bsd*-gnu|*-*-bsdi*|*-*-freebsd*|*-*-dragonfly*|*-*-netbsd*|*-*-openbsd*|*-*-sysv5*|*-*-solaris*|*-*-hpux*|*-*-aix*|*-*-minix*|*-*-nto*)
case "$host" in
@@ -3344,9 +3344,34 @@ AC_HELP_STRING([--enable-rpath], [use an rpath when linking SDL [[default=yes]]]
, enable_rpath=yes)
}

dnl Check if we want to use custom signals to fake iOS/Android's backgrounding
dnl events. These could be useful if you're building a custom embedded
dnl environment, etc, but most people don't need this.
CheckEventSignals()
{
AC_ARG_ENABLE(backgrounding-signal,
AC_HELP_STRING([--enable-backgrounding-signal], [number to use for magic backgrounding signal or 'no' [[default=no]]]),
, enable_backgrounding_signal=no)
if test x$enable_backgrounding_signal != xno; then
EXTRA_CFLAGS="$EXTRA_CFLAGS -DSDL_BACKGROUNDING_SIGNAL=$enable_backgrounding_signal"
fi

AC_ARG_ENABLE(foregrounding-signal,
AC_HELP_STRING([--enable-foregrounding-signal], [number to use for magic foregrounding signal or 'no' [[default=no]]]),
, enable_foregrounding_signal=no)
if test x$enable_foregrounding_signal != xno; then
EXTRA_CFLAGS="$EXTRA_CFLAGS -DSDL_FOREGROUNDING_SIGNAL=$enable_foregrounding_signal"
fi
}



dnl Do this on all platforms, before everything else (other things might want to override it).
CheckWarnAll

dnl Do this for every platform, but for some it doesn't mean anything, but better to catch it here anyhow.
CheckEventSignals

dnl Set up the configuration based on the host platform!
case "$host" in
*-*-linux*|*-*-uclinux*|*-*-gnu*|*-*-k*bsd*-gnu|*-*-bsdi*|*-*-freebsd*|*-*-dragonfly*|*-*-netbsd*|*-*-openbsd*|*-*-sysv5*|*-*-solaris*|*-*-hpux*|*-*-aix*|*-*-minix*|*-*-nto*)
@@ -3923,7 +3948,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
CheckDummyVideo
CheckInputEvents
CheckPTHREAD

# Set up files for the timer library
if test x$enable_timers = xyes; then
AC_DEFINE(SDL_TIMER_UNIX, 1, [ ])
@@ -689,7 +689,7 @@ SDL_PumpEvents(void)
}
#endif

SDL_SendPendingQuit(); /* in case we had a signal handler fire, etc. */
SDL_SendPendingSignalEvents(); /* in case we had a signal handler fire, etc. */
}

/* Public functions */
@@ -52,7 +52,7 @@ extern int SDL_SendQuit(void);
extern int SDL_EventsInit(void);
extern void SDL_EventsQuit(void);

extern void SDL_SendPendingQuit(void);
extern void SDL_SendPendingSignalEvents(void);

#endif /* SDL_events_c_h_ */

@@ -34,6 +34,14 @@
static SDL_bool disable_signals = SDL_FALSE;
static SDL_bool send_quit_pending = SDL_FALSE;

#ifdef SDL_BACKGROUNDING_SIGNAL
static SDL_bool send_backgrounding_pending = SDL_FALSE;
#endif

#ifdef SDL_FOREGROUNDING_SIGNAL
static SDL_bool send_foregrounding_pending = SDL_FALSE;
#endif

#ifdef HAVE_SIGNAL_H
static void
SDL_HandleSIG(int sig)
@@ -43,46 +51,81 @@ SDL_HandleSIG(int sig)

/* Send a quit event next time the event loop pumps. */
/* We can't send it in signal handler; malloc() might be interrupted! */
send_quit_pending = SDL_TRUE;
if ((sig == SIGINT) || (sig == SIGTERM)) {
send_quit_pending = SDL_TRUE;
}

#ifdef SDL_BACKGROUNDING_SIGNAL
else if (sig == SDL_BACKGROUNDING_SIGNAL) {
send_backgrounding_pending = SDL_TRUE;
}
#endif

#ifdef SDL_FOREGROUNDING_SIGNAL
else if (sig == SDL_FOREGROUNDING_SIGNAL) {
send_foregrounding_pending = SDL_TRUE;
}
#endif
}
#endif /* HAVE_SIGNAL_H */

/* Public functions */
static int
SDL_QuitInit_Internal(void)
static void
SDL_EventSignal_Init(const int sig)
{
#ifdef HAVE_SIGACTION
struct sigaction action;
sigaction(SIGINT, NULL, &action);

sigaction(sig, NULL, &action);
#ifdef HAVE_SA_SIGACTION
if ( action.sa_handler == SIG_DFL && (void (*)(int))action.sa_sigaction == SIG_DFL ) {
#else
if ( action.sa_handler == SIG_DFL ) {
#endif
action.sa_handler = SDL_HandleSIG;
sigaction(SIGINT, &action, NULL);
sigaction(sig, &action, NULL);
}
#elif HAVE_SIGNAL_H
void (*ohandler) (int) = signal(sig, SDL_HandleSIG);
if (ohandler != SIG_DFL) {
signal(sig, ohandler);
}
sigaction(SIGTERM, NULL, &action);

#ifdef HAVE_SA_SIGACTION
if ( action.sa_handler == SIG_DFL && (void (*)(int))action.sa_sigaction == SIG_DFL ) {
#else
if ( action.sa_handler == SIG_DFL ) {
#endif
action.sa_handler = SDL_HandleSIG;
sigaction(SIGTERM, &action, NULL);
}

static void
SDL_EventSignal_Quit(const int sig)
{
#ifdef HAVE_SIGACTION
struct sigaction action;
sigaction(sig, NULL, &action);
if ( action.sa_handler == SDL_HandleSIG ) {
action.sa_handler = SIG_DFL;
sigaction(sig, &action, NULL);
}
#elif HAVE_SIGNAL_H
void (*ohandler) (int);
void (*ohandler) (int) = signal(sig, SIG_DFL);
if (ohandler != SDL_HandleSIG) {
signal(sig, ohandler);
}
#endif /* HAVE_SIGNAL_H */
}

/* Public functions */
static int
SDL_QuitInit_Internal(void)
{
/* Both SIGINT and SIGTERM are translated into quit interrupts */
ohandler = signal(SIGINT, SDL_HandleSIG);
if (ohandler != SIG_DFL)
signal(SIGINT, ohandler);
ohandler = signal(SIGTERM, SDL_HandleSIG);
if (ohandler != SIG_DFL)
signal(SIGTERM, ohandler);
#endif /* HAVE_SIGNAL_H */
/* and SDL can be built to simulate iOS/Android semantics with arbitrary signals. */
SDL_EventSignal_Init(SIGINT);
SDL_EventSignal_Init(SIGTERM);

#ifdef SDL_BACKGROUNDING_SIGNAL
SDL_EventSignal_Init(SDL_BACKGROUNDING_SIGNAL);
#endif

#ifdef SDL_FOREGROUNDING_SIGNAL
SDL_EventSignal_Init(SDL_FOREGROUNDING_SIGNAL);
#endif

/* That's it! */
return 0;
@@ -100,28 +143,16 @@ SDL_QuitInit(void)
static void
SDL_QuitQuit_Internal(void)
{
#ifdef HAVE_SIGACTION
struct sigaction action;
sigaction(SIGINT, NULL, &action);
if ( action.sa_handler == SDL_HandleSIG ) {
action.sa_handler = SIG_DFL;
sigaction(SIGINT, &action, NULL);
}
sigaction(SIGTERM, NULL, &action);
if ( action.sa_handler == SDL_HandleSIG ) {
action.sa_handler = SIG_DFL;
sigaction(SIGTERM, &action, NULL);
}
#elif HAVE_SIGNAL_H
void (*ohandler) (int);

ohandler = signal(SIGINT, SIG_DFL);
if (ohandler != SDL_HandleSIG)
signal(SIGINT, ohandler);
ohandler = signal(SIGTERM, SIG_DFL);
if (ohandler != SDL_HandleSIG)
signal(SIGTERM, ohandler);
#endif /* HAVE_SIGNAL_H */
SDL_EventSignal_Quit(SIGINT);
SDL_EventSignal_Quit(SIGTERM);

#ifdef SDL_BACKGROUNDING_SIGNAL
SDL_EventSignal_Quit(SDL_BACKGROUNDING_SIGNAL);
#endif

#ifdef SDL_FOREGROUNDING_SIGNAL
SDL_EventSignal_Quit(SDL_FOREGROUNDING_SIGNAL);
#endif
}

void
@@ -141,12 +172,26 @@ SDL_SendQuit(void)
}

void
SDL_SendPendingQuit(void)
SDL_SendPendingSignalEvents(void)
{
if (send_quit_pending) {
SDL_SendQuit();
SDL_assert(!send_quit_pending);
}

#ifdef SDL_BACKGROUNDING_SIGNAL
if (send_backgrounding_pending) {
send_backgrounding_pending = SDL_FALSE;
SDL_OnApplicationWillResignActive();
}
#endif

#ifdef SDL_FOREGROUNDING_SIGNAL
if (send_foregrounding_pending) {
send_foregrounding_pending = SDL_FALSE;
SDL_OnApplicationDidBecomeActive();
}
#endif
}

/* vi: set ts=4 sw=4 expandtab: */

0 comments on commit 8a5a05c

Please sign in to comment.