diff --git a/CMakeLists.txt b/CMakeLists.txt index 6baff8a0a..d24a95bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,9 +118,9 @@ else() endif() if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN) # JavaScript does not yet have threading support, so disable pthreads when building for Emscripten. - set(PTHREADS_ENABLED_BY_DEFAULT ON) + set(SDL_PTHREADS_ENABLED_BY_DEFAULT ON) else() - set(PTHREADS_ENABLED_BY_DEFAULT OFF) + set(SDL_PTHREADS_ENABLED_BY_DEFAULT OFF) endif() # Default option knobs @@ -202,6 +202,7 @@ include_directories(${SDL2_BINARY_DIR}/include ${SDL2_SOURCE_DIR}/include) # All these ENABLED_BY_DEFAULT vars will default to ON if not specified, so # you only need to have a platform override them if they are disabling. +set(OPT_DEF_ASM TRUE) if(EMSCRIPTEN) # Set up default values for the currently supported set of subsystems: # Emscripten/Javascript does not have assembly support, a dynamic library @@ -212,12 +213,12 @@ if(EMSCRIPTEN) set(SDL_THREADS_ENABLED_BY_DEFAULT OFF) set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF) set(SDL_CPUINFO_ENABLED_BY_DEFAULT OFF) - set(DLOPEN_ENABLED_BY_DEFAULT OFF) + set(SDL_DLOPEN_ENABLED_BY_DEFAULT OFF) endif() set(SDL_SUBSYSTEMS Atomic Audio Video Render Events Joystick Haptic Power Threads Timers - File Loadso CPUinfo Filesystem) + File Loadso CPUinfo Filesystem Dlopen) foreach(_SUB ${SDL_SUBSYSTEMS}) string(TOUPPER ${_SUB} _OPT) if (NOT DEFINED SDL_${_OPT}_ENABLED_BY_DEFAULT) @@ -246,9 +247,9 @@ dep_option(FUSIONSOUND_SHARED "Dynamically load fusionsound audio support" ON " set_option(VIDEO_DUMMY "Use dummy video driver" ON) set_option(VIDEO_OPENGL "Include OpenGL support" ON) set_option(VIDEO_OPENGLES "Include OpenGL ES support" ON) -set_option(PTHREADS "Use POSIX threads for multi-threading" ${PTHREADS_ENABLED_BY_DEFAULT}) +set_option(PTHREADS "Use POSIX threads for multi-threading" ${SDL_PTHREADS_ENABLED_BY_DEFAULT}) dep_option(PTHREADS_SEM "Use pthread semaphores" ON "PTHREADS" OFF) -set_option(SDL_DLOPEN "Use dlopen for shared object loading" ${DLOPEN_ENABLED_BY_DEFAULT}) +set_option(SDL_DLOPEN "Use dlopen for shared object loading" ${SDL_DLOPEN_ENABLED_BY_DEFAULT}) set_option(OSS "Support the OSS audio API" ${UNIX_SYS}) set_option(ALSA "Support the ALSA audio API" ${UNIX_SYS}) dep_option(ALSA_SHARED "Dynamically load ALSA audio support" ON "ALSA" OFF) @@ -266,7 +267,10 @@ set_option(CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" O set_option(INPUT_TSLIB "Use the Touchscreen library for input" ${UNIX_SYS}) set_option(VIDEO_X11 "Use X11 video driver" ${UNIX_SYS}) set_option(VIDEO_WAYLAND "Use Wayland video driver" ${UNIX_SYS}) +dep_option(WAYLAND_SHARED "Dynamically load Wayland support" ON "VIDEO_WAYLAND" OFF) +dep_option(VIDEO_WAYLAND_QT_TOUCH "QtWayland server support for Wayland video driver" ON "VIDEO_WAYLAND" OFF) set_option(VIDEO_MIR "Use Mir video driver" ${UNIX_SYS}) +dep_option(MIR_SHARED "Dynamically load Mir support" ON "VIDEO_MIR" OFF) set_option(VIDEO_RPI "Use Raspberry Pi video driver" ${UNIX_SYS}) dep_option(X11_SHARED "Dynamically load X11 support" ON "VIDEO_X11" OFF) set(SDL_X11_OPTIONS Xcursor Xinerama XInput Xrandr Xscrnsaver XShape Xvm) @@ -585,7 +589,7 @@ if(LIBC) set(CMAKE_REQUIRED_LIBRARIES m) foreach(_FN atan atan2 ceil copysign cos cosf fabs floor log pow scalbn sin - sinf sqrt sqrtf tan tanf) + sinf sqrt sqrtf tan tanf acos asin) string(TOUPPER ${_FN} _UPPER) set(_HAVEVAR "HAVE_${_UPPER}") check_function_exists("${_FN}" ${_HAVEVAR}) @@ -597,6 +601,15 @@ if(LIBC) check_library_exists(iconv iconv_open "" HAVE_LIBICONV) if(HAVE_LIBICONV) list(APPEND EXTRA_LIBS iconv) + set(HAVE_ICONV 1) + endif() + + if(NOT APPLE) + check_include_file(alloca.h HAVE_ALLOCA_H) + check_function_exists(alloca HAVE_ALLOCA) + else() + set(HAVE_ALLOCA_H 1) + set(HAVE_ALLOCA 1) endif() check_struct_has_member("struct sigaction" "sa_sigaction" "signal.h" HAVE_SA_SIGACTION) @@ -1140,10 +1153,6 @@ elseif(APPLE) set(SDL_VIDEO_OPENGL 1) set(SDL_VIDEO_OPENGL_CGL 1) set(SDL_VIDEO_RENDER_OGL 1) - if(DARWIN) - find_library(OpenGL_LIBRARY OpenGL) - list(APPEND EXTRA_LIBRARIES ${OpenGL_LIBRARY}) - endif() set(HAVE_VIDEO_OPENGL TRUE) endif() endif() diff --git a/SDL2.spec.in b/SDL2.spec.in index 2a5c47924..628a9a0c6 100644 --- a/SDL2.spec.in +++ b/SDL2.spec.in @@ -1,7 +1,7 @@ Summary: Simple DirectMedia Layer Name: SDL2 Version: @SDL_VERSION@ -Release: 1 +Release: 2 Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz URL: http://www.libsdl.org/ License: zlib @@ -63,12 +63,12 @@ rm -rf $RPM_BUILD_ROOT %files %{__defattr} -%doc README-SDL.txt COPYING.txt CREDITS.txt BUGS.txt +%doc README*.txt COPYING.txt CREDITS.txt BUGS.txt %{_libdir}/lib*.%{__soext}.* %files devel %{__defattr} -%doc README README-SDL.txt COPYING CREDITS BUGS WhatsNew +%doc README*.txt COPYING.txt CREDITS.txt BUGS.txt WhatsNew.txt %{_bindir}/*-config %{_libdir}/lib*.a %{_libdir}/lib*.la @@ -78,13 +78,16 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/aclocal/* %changelog +* Sun Dec 07 2014 Simone Contini +- Fixed changelog date issue and docs filenames + * Sun Jan 22 2012 Sam Lantinga - Updated for SDL 2.0 * Tue May 16 2006 Sam Lantinga - Removed support for Darwin, due to build problems on ps2linux -* Mon Jan 03 2004 Anders Bjorklund +* Sat Jan 03 2004 Anders Bjorklund - Added support for Darwin, updated spec file * Wed Jan 19 2000 Sam Lantinga diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index a864aa07a..bd047d638 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -41,6 +41,10 @@ public class SDLActivity extends Activity { /** If shared libraries (e.g. SDL or the native application) could not be loaded. */ public static boolean mBrokenLibraries; + // If we want to separate mouse and touch events. + // This is only toggled in native code when a hint is set! + public static boolean mSeparateMouseAndTouch; + // Main components protected static SDLActivity mSingleton; protected static SDLSurface mSurface; @@ -81,7 +85,6 @@ public class SDLActivity extends Activity { } /** - * This method is called by SDL using JNI. * This method is called by SDL before starting the native application thread. * It can be overridden to provide the arguments after the application name. * The default implementation returns an empty array. It never returns null. @@ -402,6 +405,7 @@ public class SDLActivity extends Activity { public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeKeyboardFocusLost(); + public static native void onNativeMouse(int button, int action, float x, float y); public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p); @@ -1088,8 +1092,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // Dispatch the different events depending on where they come from // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD - - if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */ + + if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) { @@ -1126,50 +1130,65 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, final int pointerCount = event.getPointerCount(); int action = event.getActionMasked(); int pointerFingerId; + int mouseButton; int i = -1; float x,y,p; - - switch(action) { - case MotionEvent.ACTION_MOVE: - for (i = 0; i < pointerCount; i++) { + + // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14. + if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) { + if (Build.VERSION.SDK_INT < 14) { + mouseButton = 1; // For Android==12 all mouse buttons are the left button + } else { + try { + mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event); + } catch(Exception e) { + mouseButton = 1; // oh well. + } + } + SDLActivity.onNativeMouse(mouseButton, action, event.getX(0), event.getY(0)); + } else { + switch(action) { + case MotionEvent.ACTION_MOVE: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_DOWN: + // Primary pointer up/down, the index is always zero + i = 0; + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_POINTER_DOWN: + // Non primary pointer up/down + if (i == -1) { + i = event.getActionIndex(); + } + pointerFingerId = event.getPointerId(i); x = event.getX(i) / mWidth; y = event.getY(i) / mHeight; p = event.getPressure(i); SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - } - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_DOWN: - // Primary pointer up/down, the index is always zero - i = 0; - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: - // Non primary pointer up/down - if (i == -1) { - i = event.getActionIndex(); - } + break; - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - break; - - case MotionEvent.ACTION_CANCEL: - for (i = 0; i < pointerCount; i++) { - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); - } - break; + case MotionEvent.ACTION_CANCEL: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); + } + break; - default: - break; + default: + break; + } } return true; @@ -1500,9 +1519,44 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { // Generic Motion (mouse hover, joystick...) events go here - // We only have joysticks yet @Override public boolean onGenericMotion(View v, MotionEvent event) { - return SDLActivity.handleJoystickMotionEvent(event); + float x, y; + int mouseButton; + int action; + + switch ( event.getSource() ) { + case InputDevice.SOURCE_JOYSTICK: + case InputDevice.SOURCE_GAMEPAD: + case InputDevice.SOURCE_DPAD: + SDLActivity.handleJoystickMotionEvent(event); + return true; + + case InputDevice.SOURCE_MOUSE: + action = event.getActionMasked(); + switch(event.getActionMasked()) { + case MotionEvent.ACTION_SCROLL: + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + x = event.getX(0); + y = event.getY(0); + + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + default: + break; + } + + default: + break; + } + + // Event was not managed + return false; } } diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index e8d746f96..f390fcbd0 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -505,8 +505,13 @@ macro(CheckX11) endif() endmacro() +# Requires: +# - EGL +# - PkgCheckModules +# Optional: +# - MIR_SHARED opt +# - HAVE_DLOPEN opt macro(CheckMir) -# !!! FIXME: hook up dynamic loading here. if(VIDEO_MIR) find_library(MIR_LIB mirclient mircommon egl) pkg_check_modules(MIR_TOOLKIT mirclient mircommon) @@ -522,15 +527,31 @@ macro(CheckMir) set(SDL_VIDEO_DRIVER_MIR 1) list(APPEND EXTRA_CFLAGS ${MIR_TOOLKIT_CFLAGS} ${EGL_CLFAGS} ${XKB_CLFLAGS}) - list(APPEND EXTRA_LDFLAGS ${MIR_TOOLKIT_LDFLAGS} ${EGL_LDLAGS} ${XKB_LDLAGS}) - endif (MIR_LIB AND MIR_TOOLKIT_FOUND AND EGL_FOUND AND XKB_FOUND) + + if(MIR_SHARED) + if(NOT HAVE_DLOPEN) + message_warn("You must have SDL_LoadObject() support for dynamic Mir loading") + else() + FindLibraryAndSONAME(mirclient) + FindLibraryAndSONAME(xkbcommon) + set(SDL_VIDEO_DRIVER_MIR_DYNAMIC "\"${MIRCLIENT_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON "\"${XKBCOMMON_LIB_SONAME}\"") + set(HAVE_MIR_SHARED TRUE) + endif() + else() + set(EXTRA_LIBS ${MIR_TOOLKIT_LIBRARIES} ${EXTRA_LIBS}) + endif() + endif() endif() endmacro() # Requires: # - EGL +# - PkgCheckModules +# Optional: +# - WAYLAND_SHARED opt +# - HAVE_DLOPEN opt macro(CheckWayland) -# !!! FIXME: hook up dynamic loading here. if(VIDEO_WAYLAND) pkg_check_modules(WAYLAND wayland-client wayland-cursor wayland-egl egl xkbcommon) if(WAYLAND_FOUND) @@ -540,12 +561,34 @@ macro(CheckWayland) include_directories( ${WAYLAND_INCLUDE_DIRS} ) - set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS}) set(HAVE_VIDEO_WAYLAND TRUE) set(HAVE_SDL_VIDEO TRUE) file(GLOB WAYLAND_SOURCES ${SDL2_SOURCE_DIR}/src/video/wayland/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${WAYLAND_SOURCES}) + + if(VIDEO_WAYLAND_QT_TOUCH) + set(SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH 1) + endif() + + if(WAYLAND_SHARED) + if(NOT HAVE_DLOPEN) + message_warn("You must have SDL_LoadObject() support for dynamic Wayland loading") + else() + FindLibraryAndSONAME(wayland-client) + FindLibraryAndSONAME(wayland-egl) + FindLibraryAndSONAME(wayland-cursor) + FindLibraryAndSONAME(xkbcommon) + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC "\"${WAYLAND_CLIENT_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL "\"${WAYLAND_EGL_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR "\"${WAYLAND_CURSOR_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON "\"${XKBCOMMON_LIB_SONAME}\"") + set(HAVE_WAYLAND_SHARED TRUE) + endif() + else() + set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS}) + endif() + set(SDL_VIDEO_DRIVER_WAYLAND 1) endif() endif() @@ -682,7 +725,7 @@ macro(CheckOpenGLESX11) endif() endmacro() -# Rquires: +# Requires: # - nada # Optional: # - THREADS opt @@ -733,13 +776,17 @@ macro(CheckPTHREAD) # Run some tests set(CMAKE_REQUIRED_FLAGS "${PTHREAD_CFLAGS} ${PTHREAD_LDFLAGS}") - check_c_source_runs(" + if(CMAKE_CROSSCOMPILING) + set(HAVE_PTHREADS 1) + else() + check_c_source_runs(" #include int main(int argc, char** argv) { pthread_attr_t type; pthread_attr_init(&type); return 0; }" HAVE_PTHREADS) + endif() if(HAVE_PTHREADS) set(SDL_THREAD_PTHREAD 1) list(APPEND EXTRA_CFLAGS ${PTHREAD_CFLAGS}) @@ -788,8 +835,8 @@ macro(CheckPTHREAD) #include #include int main(int argc, char** argv) { return 0; }" HAVE_PTHREAD_NP_H) - check_function_exists(pthread_setname_np HAVE_PTHREAD_setNAME_NP) - check_function_exists(pthread_set_name_np HAVE_PTHREAD_set_NAME_NP) + check_function_exists(pthread_setname_np HAVE_PTHREAD_SETNAME_NP) + check_function_exists(pthread_set_name_np HAVE_PTHREAD_SET_NAME_NP) set(CMAKE_REQUIRED_FLAGS) set(SOURCE_FILES ${SOURCE_FILES} diff --git a/configure b/configure index d365902ad..e220948ad 100755 --- a/configure +++ b/configure @@ -21916,6 +21916,7 @@ $as_echo_n "checking for recursive mutexes... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ + #define _GNU_SOURCE 1 #include int @@ -21929,7 +21930,7 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : has_recursive_mutexes=yes @@ -21937,12 +21938,14 @@ $as_echo "#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi if test x$has_recursive_mutexes = xno; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ + #define _GNU_SOURCE 1 #include int @@ -21956,7 +21959,7 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : has_recursive_mutexes=yes @@ -21964,7 +21967,8 @@ $as_echo "#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_recursive_mutexes" >&5 $as_echo "$has_recursive_mutexes" >&6; } @@ -23091,11 +23095,22 @@ $as_echo "#define SDL_POWER_ANDROID 1" >>confdefs.h fi # Set up files for the filesystem library if test x$enable_filesystem = xyes; then + case $ARCH in + android) + +$as_echo "#define SDL_FILESYSTEM_ANDROID 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/filesystem/android/*.c" + have_filesystem=yes + ;; + *) $as_echo "#define SDL_FILESYSTEM_UNIX 1" >>confdefs.h - SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" - have_filesystem=yes + SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" + have_filesystem=yes + ;; + esac fi # Set up files for the timer library if test x$enable_timers = xyes; then diff --git a/configure.in b/configure.in index c546abec1..6e3878247 100644 --- a/configure.in +++ b/configure.in @@ -2424,7 +2424,8 @@ AC_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [[default=yes]]]) AC_MSG_CHECKING(for recursive mutexes) has_recursive_mutexes=no if test x$has_recursive_mutexes = xno; then - AC_TRY_COMPILE([ + AC_TRY_LINK([ + #define _GNU_SOURCE 1 #include ],[ pthread_mutexattr_t attr; @@ -2435,7 +2436,8 @@ AC_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [[default=yes]]]) ]) fi if test x$has_recursive_mutexes = xno; then - AC_TRY_COMPILE([ + AC_TRY_LINK([ + #define _GNU_SOURCE 1 #include ],[ pthread_mutexattr_t attr; @@ -2971,9 +2973,18 @@ case "$host" in fi # Set up files for the filesystem library if test x$enable_filesystem = xyes; then - AC_DEFINE(SDL_FILESYSTEM_UNIX, 1, [ ]) - SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" - have_filesystem=yes + case $ARCH in + android) + AC_DEFINE(SDL_FILESYSTEM_ANDROID, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/filesystem/android/*.c" + have_filesystem=yes + ;; + *) + AC_DEFINE(SDL_FILESYSTEM_UNIX, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" + have_filesystem=yes + ;; + esac fi # Set up files for the timer library if test x$enable_timers = xyes; then diff --git a/docs/README-platforms.md b/docs/README-platforms.md index 4bf77b206..14454ec5d 100644 --- a/docs/README-platforms.md +++ b/docs/README-platforms.md @@ -1,34 +1,8 @@ Platforms ========= - -This is a list of the platforms SDL supports, and who maintains them. - -Officially supported platforms -============================== -(code compiles, and thoroughly tested for release) -============================== -* Windows XP/Vista/7/8 -* Mac OS X 10.5+ -* Linux 2.6+ -* iOS 5.1.1+ -* Android 2.3.3+ - -Unofficially supported platforms -================================ -(code compiles, but not thoroughly tested) -================================ -* FreeBSD -* NetBSD -* OpenBSD -* Solaris - -Platforms supported by volunteers -================================= -* Haiku - maintained by Axel Dörfler -* PSP - maintained by 527721088@qq.com -* Pandora - maintained by Scott Smith -* NaCl - maintained by Gabriel Jacobo - -Platforms that need maintainers -=============================== +We maintain the list of supported platforms on our wiki now, and how to +build and install SDL for those platforms: + + https://wiki.libsdl.org/Installation + diff --git a/docs/README-porting.md b/docs/README-porting.md index d93c65bd3..cf2d3eaca 100644 --- a/docs/README-porting.md +++ b/docs/README-porting.md @@ -15,7 +15,7 @@ There are two basic ways of building SDL at the moment: If you have a GNUish system, then you might try this. Edit configure.in, take a look at the large section labelled: - "Set up the configuration based on the target platform!" + "Set up the configuration based on the host platform!" Add a section for your platform, and then re-run autogen.sh and build! 2. Using an IDE: diff --git a/docs/README-winrt.md b/docs/README-winrt.md index fdc669f10..75cd7cd2b 100644 --- a/docs/README-winrt.md +++ b/docs/README-winrt.md @@ -90,10 +90,12 @@ Here is a rough list of what works, and what doens't: * keyboard input. Most of WinRT's documented virtual keys are supported, as well as many keys with documented hardware scancodes. * OpenGL. Experimental support for OpenGL ES 2 is available via the ANGLE - project, using either MS Open Technologies' repository, at - https://github.com/msopentech/angle (both the "winrt" and "future-dev" - branches are supported), or the official ANGLE repository, at - https://chromium.googlesource.com/angle/angle + project, using either: + * MS Open Technologies' "ms-master" repository, at https://github.com/MSOpenTech/angle + (for use with Windows 8.1+ or Windows Phone 8.1+) + * MS Open Technologies' "angle-win8.0" repository, at https://github.com/MSOpenTech/angle-win8.0 + (for Windows 8.0 only!) + * Google's main ANGLE repository, at https://chromium.googlesource.com/angle/angle * SDLmain. WinRT uses a different signature for each app's main() function. SDL-based apps that use this port must compile in SDL_winrt_main_NonXAML.cpp (in `SDL\src\main\winrt\`) directly in order for their C-style main() @@ -112,6 +114,11 @@ Here is a rough list of what works, and what doens't: supported by WinRT itself. * joysticks and game controllers that aren't supported by Microsoft's XInput API. + * turning off VSync when rendering on Windows Phone. Attempts to turn VSync + off on Windows Phone result either in Direct3D not drawing anything, or it + forcing VSync back on. As such, SDL_RENDERER_PRESENTVSYNC will always get + turned-on on Windows Phone. This limitation is not present in non-Phone + WinRT (such as Windows 8.x), where turning off VSync appears to work. * probably anything else that's not listed as supported diff --git a/include/SDL_assert.h b/include/SDL_assert.h index 94d998770..0be90470f 100644 --- a/include/SDL_assert.h +++ b/include/SDL_assert.h @@ -102,9 +102,9 @@ typedef enum SDL_ASSERTION_ABORT, /**< Terminate the program. */ SDL_ASSERTION_IGNORE, /**< Ignore the assert. */ SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */ -} SDL_assert_state; +} SDL_AssertState; -typedef struct SDL_assert_data +typedef struct SDL_AssertData { int always_ignore; unsigned int trigger_count; @@ -112,13 +112,13 @@ typedef struct SDL_assert_data const char *filename; int linenum; const char *function; - const struct SDL_assert_data *next; -} SDL_assert_data; + const struct SDL_AssertData *next; +} SDL_AssertData; #if (SDL_ASSERT_LEVEL > 0) /* Never call this directly. Use the SDL_assert* macros. */ -extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, +extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *, const char *, const char *, int) #if defined(__clang__) @@ -141,10 +141,10 @@ extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, #define SDL_enabled_assert(condition) \ do { \ while ( !(condition) ) { \ - static struct SDL_assert_data sdl_assert_data = { \ + static struct SDL_AssertData sdl_assert_data = { \ 0, 0, #condition, 0, 0, 0, 0 \ }; \ - const SDL_assert_state sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \ + const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \ if (sdl_assert_state == SDL_ASSERTION_RETRY) { \ continue; /* go again. */ \ } else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \ @@ -181,8 +181,8 @@ extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, #define SDL_assert_always(condition) SDL_enabled_assert(condition) -typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)( - const SDL_assert_data* data, void* userdata); +typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)( + const SDL_AssertData* data, void* userdata); /** * \brief Set an application-defined assertion handler. @@ -199,7 +199,7 @@ typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)( * * This callback is NOT reset to SDL's internal handler upon SDL_Quit()! * - * \return SDL_assert_state value of how to handle the assertion failure. + * \return SDL_AssertState value of how to handle the assertion failure. * * \param handler Callback function, called when an assertion fails. * \param userdata A pointer passed to the callback as-is. @@ -246,7 +246,7 @@ extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puse * The proper way to examine this data looks something like this: * * - * const SDL_assert_data *item = SDL_GetAssertionReport(); + * const SDL_AssertData *item = SDL_GetAssertionReport(); * while (item) { * printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", * item->condition, item->function, item->filename, @@ -259,7 +259,7 @@ extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puse * \return List of all assertions. * \sa SDL_ResetAssertionReport */ -extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void); +extern DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void); /** * \brief Reset the list of all assertion failures. @@ -270,6 +270,12 @@ extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void); */ extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void); + +/* these had wrong naming conventions until 2.0.4. Please update your app! */ +#define SDL_assert_state SDL_AssertState +#define SDL_assert_data SDL_AssertData + + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index b12ea524b..db245aa49 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -269,14 +269,11 @@ #cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@ #cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@ -#if 0 -/* !!! FIXME: in configure script version, missing here: */ -#undef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH -#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC -#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL -#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR -#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON -#endif +#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH@ +#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC@ +#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@ +#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR@ +#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON@ #cmakedefine SDL_VIDEO_DRIVER_MIR @SDL_VIDEO_DRIVER_MIR@ #cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC @SDL_VIDEO_DRIVER_MIR_DYNAMIC@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 2c50ba406..925bfaa1a 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -349,6 +349,7 @@ #undef SDL_FILESYSTEM_UNIX #undef SDL_FILESYSTEM_WINDOWS #undef SDL_FILESYSTEM_NACL +#undef SDL_FILESYSTEM_ANDROID #undef SDL_FILESYSTEM_EMSCRIPTEN /* Enable assembly routines */ diff --git a/include/SDL_events.h b/include/SDL_events.h index 09ab9c2f2..ee61421f6 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -134,6 +134,10 @@ typedef enum /* Drag and drop events */ SDL_DROPFILE = 0x1000, /**< The system requests a file open */ + /* Audio hotplug events */ + SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */ + SDL_AUDIODEVICEREMOVED, /**< An audio device has been removed. */ + /* Render events */ SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */ SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */ @@ -382,6 +386,20 @@ typedef struct SDL_ControllerDeviceEvent Sint32 which; /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */ } SDL_ControllerDeviceEvent; +/** + * \brief Audio device event structure (event.adevice.*) + */ +typedef struct SDL_AudioDeviceEvent +{ + Uint32 type; /**< ::SDL_AUDIODEVICEADDED, or ::SDL_AUDIODEVICEREMOVED */ + Uint32 timestamp; + Uint32 which; /**< The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event */ + Uint8 iscapture; /**< zero if an output device, non-zero if a capture device. */ + Uint8 padding1; + Uint8 padding2; + Uint8 padding3; +} SDL_AudioDeviceEvent; + /** * \brief Touch finger event structure (event.tfinger.*) @@ -422,7 +440,7 @@ typedef struct SDL_MultiGestureEvent */ typedef struct SDL_DollarGestureEvent { - Uint32 type; /**< ::SDL_DOLLARGESTURE */ + Uint32 type; /**< ::SDL_DOLLARGESTURE or ::SDL_DOLLARRECORD */ Uint32 timestamp; SDL_TouchID touchId; /**< The touch device id */ SDL_GestureID gestureId; @@ -516,6 +534,7 @@ typedef union SDL_Event SDL_ControllerAxisEvent caxis; /**< Game Controller axis event data */ SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */ SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */ + SDL_AudioDeviceEvent adevice; /**< Audio device event data */ SDL_QuitEvent quit; /**< Quit request event data */ SDL_UserEvent user; /**< Custom event data */ SDL_SysWMEvent syswm; /**< System dependent window event data */ diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index 9df526a76..5c9082ced 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -241,7 +241,8 @@ SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, /** * Get the current state of an axis control on a game controller. * - * The state is a value ranging from -32768 to 32767. + * The state is a value ranging from -32768 to 32767 (except for the triggers, + * which range from 0 to 32767). * * The axis indices start at index 0. */ diff --git a/include/SDL_hints.h b/include/SDL_hints.h index f24955cc3..5eaba8f5a 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -533,6 +533,18 @@ extern "C" { */ #define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING" + /** + * \brief A variable to control whether mouse and touch events are to be treated together or separately + * + * The variable can be set to the following values: + * "0" - Mouse events will be handled as touch events, and touch will raise fake mouse + * events. This is the behaviour of SDL <= 2.0.3. (default) + * "1" - Mouse events will be handled separately from pure touch events. + * + * The value of this hint is used at runtime, so it can be changed at any time. + */ +#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH" + /** * \brief override the binding element for keyboard inputs for Emscripten builds * @@ -547,6 +559,18 @@ extern "C" { */ #define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT" +/** + * \brief Tell SDL not to catch the SIGINT or SIGTERM signals. + * + * This hint only applies to Unix-like platforms. + * + * The variable can be set to the following values: + * "0" - SDL will install a SIGINT and SIGTERM handler, and when it + * catches a signal, convert it into an SDL_QUIT event. + * "1" - SDL will not install a signal handler at all. + */ +#define SDL_HINT_NO_SIGNAL_HANDLERS "SDL_NO_SIGNAL_HANDLERS" + /** * \brief An enumeration of hint priorities */ diff --git a/include/SDL_opengl_glext.h b/include/SDL_opengl_glext.h index 7e840f72a..cd3869fe7 100644 --- a/include/SDL_opengl_glext.h +++ b/include/SDL_opengl_glext.h @@ -2988,6 +2988,11 @@ GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); #define GL_ARB_framebuffer_sRGB 1 #endif /* GL_ARB_framebuffer_sRGB */ +#ifndef GL_KHR_context_flush_control +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC +#endif /* GL_KHR_context_flush_control */ + #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 #define GL_LINES_ADJACENCY_ARB 0x000A diff --git a/include/SDL_render.h b/include/SDL_render.h index e6084e9e7..12da6f8b3 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -81,8 +81,8 @@ typedef struct SDL_RendererInfo Uint32 flags; /**< Supported ::SDL_RendererFlags */ Uint32 num_texture_formats; /**< The number of available texture formats */ Uint32 texture_formats[16]; /**< The available texture formats */ - int max_texture_width; /**< The maximimum texture width */ - int max_texture_height; /**< The maximimum texture height */ + int max_texture_width; /**< The maximum texture width */ + int max_texture_height; /**< The maximum texture height */ } SDL_RendererInfo; /** @@ -792,7 +792,7 @@ extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer, * \param dstrect A pointer to the destination rectangle, or NULL for the * entire rendering target. * \param angle An angle in degrees that indicates the rotation that will be applied to dstrect - * \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done aroud dstrect.w/2, dstrect.h/2) + * \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done around dstrect.w/2, dstrect.h/2). * \param flip An SDL_RendererFlip value stating which flipping actions should be performed on the texture * * \return 0 on success, or -1 on error diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 7a061a9c8..7cf020841 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -173,6 +173,8 @@ typedef uint64_t Uint64; #define SDL_PRIs64 PRIs64 #elif defined(__WIN32__) #define SDL_PRIs64 "I64d" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIs64 "ld" #else #define SDL_PRIs64 "lld" #endif @@ -182,6 +184,8 @@ typedef uint64_t Uint64; #define SDL_PRIu64 PRIu64 #elif defined(__WIN32__) #define SDL_PRIu64 "I64u" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIu64 "lu" #else #define SDL_PRIu64 "llu" #endif @@ -191,6 +195,8 @@ typedef uint64_t Uint64; #define SDL_PRIx64 PRIx64 #elif defined(__WIN32__) #define SDL_PRIx64 "I64x" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIx64 "lx" #else #define SDL_PRIx64 "llx" #endif @@ -200,6 +206,8 @@ typedef uint64_t Uint64; #define SDL_PRIX64 PRIX64 #elif defined(__WIN32__) #define SDL_PRIX64 "I64X" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIX64 "lX" #else #define SDL_PRIX64 "llX" #endif diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index 03c3b025d..c26533384 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -186,6 +186,7 @@ struct SDL_SysWMinfo struct { HWND window; /**< The window handle */ + HDC hdc; /**< The window device context */ } win; #endif #if defined(SDL_VIDEO_DRIVER_WINRT) diff --git a/include/SDL_video.h b/include/SDL_video.h index 4a2fb0458..fe1386889 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -189,7 +189,8 @@ typedef enum SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_SHARE_WITH_CURRENT_CONTEXT, - SDL_GL_FRAMEBUFFER_SRGB_CAPABLE + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, + SDL_GL_CONTEXT_RELEASE_BEHAVIOR } SDL_GLattr; typedef enum @@ -207,6 +208,12 @@ typedef enum SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008 } SDL_GLcontextFlag; +typedef enum +{ + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000, + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001 +} SDL_GLcontextReleaseFlag; + /* Function prototypes */ @@ -715,6 +722,9 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window, * \param window The window for which the input grab mode should be set. * \param grabbed This is SDL_TRUE to grab input, and SDL_FALSE to release input. * + * If the caller enables a grab while another window is currently grabbed, + * the other window loses its grab in favor of the caller's window. + * * \sa SDL_GetWindowGrab() */ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, @@ -729,6 +739,15 @@ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, */ extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window); +/** + * \brief Get the window that currently has an input grab enabled. + * + * \return This returns the window if input is grabbed, and NULL otherwise. + * + * \sa SDL_SetWindowGrab() + */ +extern DECLSPEC SDL_Window * SDLCALL SDL_GetGrabbedWindow(void); + /** * \brief Set the brightness (gamma correction) for a window. * diff --git a/src/SDL.c b/src/SDL.c index 69872dd6c..0e3512009 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -405,6 +405,8 @@ SDL_GetPlatform() return "BSDI"; #elif __DREAMCAST__ return "Dreamcast"; +#elif __EMSCRIPTEN__ + return "Emscripten"; #elif __FREEBSD__ return "FreeBSD"; #elif __HAIKU__ diff --git a/src/SDL_error.c b/src/SDL_error.c index 2df29aa13..80e8620f8 100644 --- a/src/SDL_error.c +++ b/src/SDL_error.c @@ -120,7 +120,7 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) so that it supports internationalization and thread-safe errors. */ static char * -SDL_GetErrorMsg(char *errstr, unsigned int maxlen) +SDL_GetErrorMsg(char *errstr, int maxlen) { SDL_error *error; @@ -163,37 +163,55 @@ SDL_GetErrorMsg(char *errstr, unsigned int maxlen) len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_i); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 'f': len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_f); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 'p': len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_ptr); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 's': len = SDL_snprintf(msg, maxlen, tmp, SDL_LookupString(error->args[argi++]. buf)); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + } } else { *msg++ = *fmt++; maxlen -= 1; } } + + /* slide back if we've overshot the end of our buffer. */ + if (maxlen < 0) { + msg -= (-maxlen) + 1; + } + *msg = 0; /* NULL terminate the string */ } return (errstr); diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 2f69335be..dfc55fa62 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -51,9 +51,7 @@ extern AudioBootStrap QSAAUDIO_bootstrap; extern AudioBootStrap SUNAUDIO_bootstrap; extern AudioBootStrap ARTS_bootstrap; extern AudioBootStrap ESD_bootstrap; -#if SDL_AUDIO_DRIVER_NACL extern AudioBootStrap NACLAUD_bootstrap; -#endif extern AudioBootStrap NAS_bootstrap; extern AudioBootStrap XAUDIO2_bootstrap; extern AudioBootStrap DSOUND_bootstrap; @@ -163,8 +161,16 @@ get_audio_device(SDL_AudioDeviceID id) /* stubs for audio drivers that don't need a specific entry point... */ static void -SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn) -{ /* no-op. */ +SDL_AudioDetectDevices_Default(void) +{ + /* you have to write your own implementation if these assertions fail. */ + SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice); + SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport); + + SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1)); + if (current_audio.impl.HasCaptureSupport) { + SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2)); + } } static void @@ -209,10 +215,16 @@ SDL_AudioDeinitialize_Default(void) { /* no-op. */ } +static void +SDL_AudioFreeDeviceHandle_Default(void *handle) +{ /* no-op. */ +} + + static int -SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture) +SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture) { - return -1; + return SDL_Unsupported(); } static SDL_INLINE SDL_bool @@ -269,71 +281,139 @@ finalize_audio_entry_points(void) FILL_STUB(CloseDevice); FILL_STUB(LockDevice); FILL_STUB(UnlockDevice); + FILL_STUB(FreeDeviceHandle); FILL_STUB(Deinitialize); #undef FILL_STUB } -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ -/* Streaming functions (for when the input and output buffer sizes are different) */ -/* Write [length] bytes from buf into the streamer */ -static void -SDL_StreamWrite(SDL_AudioStreamer * stream, Uint8 * buf, int length) -{ - int i; - for (i = 0; i < length; ++i) { - stream->buffer[stream->write_pos] = buf[i]; - ++stream->write_pos; - } -} - -/* Read [length] bytes out of the streamer into buf */ -static void -SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length) -{ - int i; - - for (i = 0; i < length; ++i) { - buf[i] = stream->buffer[stream->read_pos]; - ++stream->read_pos; - } -} +/* device hotplug support... */ static int -SDL_StreamLength(SDL_AudioStreamer * stream) +add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount) { - return (stream->write_pos - stream->read_pos) % stream->max_len; -} - -/* Initialize the stream by allocating the buffer and setting the read/write heads to the beginning */ -#if 0 -static int -SDL_StreamInit(SDL_AudioStreamer * stream, int max_len, Uint8 silence) -{ - /* First try to allocate the buffer */ - stream->buffer = (Uint8 *) SDL_malloc(max_len); - if (stream->buffer == NULL) { + int retval = -1; + const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1; + SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size); + if (item == NULL) { return -1; } - stream->max_len = max_len; - stream->read_pos = 0; - stream->write_pos = 0; + SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */ - /* Zero out the buffer */ - SDL_memset(stream->buffer, silence, max_len); + item->handle = handle; + SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem)); - return 0; + SDL_LockMutex(current_audio.detectionLock); + item->next = *devices; + *devices = item; + retval = (*devCount)++; + SDL_UnlockMutex(current_audio.detectionLock); + + return retval; } -#endif -/* Deinitialize the stream simply by freeing the buffer */ -static void -SDL_StreamDeinit(SDL_AudioStreamer * stream) +static SDL_INLINE int +add_capture_device(const char *name, void *handle) { - SDL_free(stream->buffer); + /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/ + return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); } -#endif + +static SDL_INLINE int +add_output_device(const char *name, void *handle) +{ + return add_audio_device(name, handle, ¤t_audio.outputDevices, ¤t_audio.outputDeviceCount); +} + +static void +free_device_list(SDL_AudioDeviceItem **devices, int *devCount) +{ + SDL_AudioDeviceItem *item, *next; + for (item = *devices; item != NULL; item = next) { + next = item->next; + if (item->handle != NULL) { + current_audio.impl.FreeDeviceHandle(item->handle); + } + SDL_free(item); + } + *devices = NULL; + *devCount = 0; +} + + +/* The audio backends call this when a new device is plugged in. */ +void +SDL_AddAudioDevice(const int iscapture, const char *name, void *handle) +{ + const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle); + if (device_index != -1) { + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) { + SDL_Event event; + SDL_zero(event); + event.adevice.type = SDL_AUDIODEVICEADDED; + event.adevice.which = device_index; + event.adevice.iscapture = iscapture; + SDL_PushEvent(&event); + } + } +} + +/* The audio backends call this when a currently-opened device is lost. */ +void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device) +{ + SDL_assert(get_audio_device(device->id) == device); + + if (!device->enabled) { + return; + } + + /* Ends the audio callback and mark the device as STOPPED, but the + app still needs to close the device to free resources. */ + current_audio.impl.LockDevice(device); + device->enabled = 0; + current_audio.impl.UnlockDevice(device); + + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) { + SDL_Event event; + SDL_zero(event); + event.adevice.type = SDL_AUDIODEVICEREMOVED; + event.adevice.which = device->id; + event.adevice.iscapture = device->iscapture ? 1 : 0; + SDL_PushEvent(&event); + } +} + +static void +mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag) +{ + SDL_AudioDeviceItem *item; + SDL_assert(handle != NULL); + for (item = devices; item != NULL; item = item->next) { + if (item->handle == handle) { + item->handle = NULL; + *removedFlag = SDL_TRUE; + return; + } + } +} + +/* The audio backends call this when a device is removed from the system. */ +void +SDL_RemoveAudioDevice(const int iscapture, void *handle) +{ + SDL_LockMutex(current_audio.detectionLock); + if (iscapture) { + mark_device_removed(handle, current_audio.inputDevices, ¤t_audio.captureDevicesRemoved); + } else { + mark_device_removed(handle, current_audio.outputDevices, ¤t_audio.outputDevicesRemoved); + } + SDL_UnlockMutex(current_audio.detectionLock); + current_audio.impl.FreeDeviceHandle(handle); +} + /* buffer queueing support... */ @@ -510,26 +590,17 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid) } -#if defined(__ANDROID__) -#include -#endif - /* The general mixing thread function */ int SDLCALL SDL_RunAudio(void *devicep) { SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; + const int silence = (int) device->spec.silence; + const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq); + const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size; Uint8 *stream; - int stream_len; - void *udata; - void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); - Uint32 delay; - -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - /* For streaming when the buffer sizes don't match up */ - Uint8 *istream; - int istream_len = 0; -#endif + void *udata = device->spec.userdata; + void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback; /* The audio mixing is always a high priority thread */ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); @@ -538,197 +609,60 @@ SDL_RunAudio(void *devicep) device->threadid = SDL_ThreadID(); current_audio.impl.ThreadInit(device); - /* Set up the mixing function */ - fill = device->spec.callback; - udata = device->spec.userdata; - - /* By default do not stream */ - device->use_streamer = 0; - - if (device->convert.needed) { -#if 0 /* !!! FIXME: I took len_div out of the structure. Use rate_incr instead? */ - /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */ - if (device->convert.len_mult != 1 || device->convert.len_div != 1) { - /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */ - stream_max_len = 2 * device->spec.size; - if (device->convert.len_mult > device->convert.len_div) { - stream_max_len *= device->convert.len_mult; - stream_max_len /= device->convert.len_div; - } - if (SDL_StreamInit(&device->streamer, stream_max_len, silence) < - 0) - return -1; - device->use_streamer = 1; - - /* istream_len should be the length of what we grab from the callback and feed to conversion, - so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d - */ - istream_len = - device->spec.size * device->convert.len_div / - device->convert.len_mult; + /* Loop, filling the audio buffers */ + while (!device->shutdown) { + /* Fill the current buffer with sound */ + if (device->convert.needed) { + stream = device->convert.buf; + } else if (device->enabled) { + stream = current_audio.impl.GetDeviceBuf(device); + } else { + /* if the device isn't enabled, we still write to the + fake_stream, so the app's callback will fire with + a regular frequency, in case they depend on that + for timing or progress. They can use hotplug + now to know if the device failed. */ + stream = NULL; } -#endif - stream_len = device->convert.len; - } else { - stream_len = device->spec.size; - } - - /* Calculate the delay while paused */ - delay = ((device->spec.samples * 1000) / device->spec.freq); - - /* Determine if the streamer is necessary here */ -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - if (device->use_streamer == 1) { - /* This code is almost the same as the old code. The difference is, instead of reading - directly from the callback into "stream", then converting and sending the audio off, - we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device. - However, reading and writing with streamer are done separately: - - We only call the callback and write to the streamer when the streamer does not - contain enough samples to output to the device. - - We only read from the streamer and tell the device to play when the streamer - does have enough samples to output. - This allows us to perform resampling in the conversion step, where the output of the - resampling process can be any number. We will have to see what a good size for the - stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure. - */ - while (device->enabled) { - - if (device->paused) { - SDL_Delay(delay); - continue; - } - - /* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */ - if (SDL_StreamLength(&device->streamer) < stream_len) { - /* Set up istream */ - if (device->convert.needed) { - if (device->convert.buf) { - istream = device->convert.buf; - } else { - continue; - } - } else { -/* FIXME: Ryan, this is probably wrong. I imagine we don't want to get - * a device buffer both here and below in the stream output. - */ - istream = current_audio.impl.GetDeviceBuf(device); - if (istream == NULL) { - istream = device->fake_stream; - } - } - - /* Read from the callback into the _input_ stream */ - SDL_LockMutex(device->mixer_lock); - (*fill) (udata, istream, istream_len); - SDL_UnlockMutex(device->mixer_lock); - - /* Convert the audio if necessary and write to the streamer */ - if (device->convert.needed) { - SDL_ConvertAudio(&device->convert); - if (istream == NULL) { - istream = device->fake_stream; - } - /* SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt); */ - SDL_StreamWrite(&device->streamer, device->convert.buf, - device->convert.len_cvt); - } else { - SDL_StreamWrite(&device->streamer, istream, istream_len); - } - } - - /* Only output audio if the streamer has enough to output */ - if (SDL_StreamLength(&device->streamer) >= stream_len) { - /* Set up the output stream */ - if (device->convert.needed) { - if (device->convert.buf) { - stream = device->convert.buf; - } else { - continue; - } - } else { - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } - } - - /* Now read from the streamer */ - SDL_StreamRead(&device->streamer, stream, stream_len); - - /* Ready current buffer for play and change current buffer */ - if (stream != device->fake_stream) { - current_audio.impl.PlayDevice(device); - /* Wait for an audio buffer to become available */ - current_audio.impl.WaitDevice(device); - } else { - SDL_Delay(delay); - } - } + if (stream == NULL) { + stream = device->fake_stream; } - } else -#endif - { - /* Otherwise, do not use the streamer. This is the old code. */ - const int silence = (int) device->spec.silence; - /* Loop, filling the audio buffers */ - while (device->enabled) { + /* !!! FIXME: this should be LockDevice. */ + SDL_LockMutex(device->mixer_lock); + if (device->paused) { + SDL_memset(stream, silence, stream_len); + } else { + (*fill) (udata, stream, stream_len); + } + SDL_UnlockMutex(device->mixer_lock); - /* Fill the current buffer with sound */ - if (device->convert.needed) { - if (device->convert.buf) { - stream = device->convert.buf; - } else { - continue; - } + /* Convert the audio if necessary */ + if (device->enabled && device->convert.needed) { + SDL_ConvertAudio(&device->convert); + stream = current_audio.impl.GetDeviceBuf(device); + if (stream == NULL) { + stream = device->fake_stream; } else { - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } - } - - SDL_LockMutex(device->mixer_lock); - if (device->paused) { - SDL_memset(stream, silence, stream_len); - } else { - (*fill) (udata, stream, stream_len); - } - SDL_UnlockMutex(device->mixer_lock); - - /* Convert the audio if necessary */ - if (device->convert.needed) { - SDL_ConvertAudio(&device->convert); - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt); } + } - /* Ready current buffer for play and change current buffer */ - if (stream != device->fake_stream) { - current_audio.impl.PlayDevice(device); - /* Wait for an audio buffer to become available */ - current_audio.impl.WaitDevice(device); - } else { - SDL_Delay(delay); - } + /* Ready current buffer for play and change current buffer */ + if (stream == device->fake_stream) { + SDL_Delay(delay); + } else { + current_audio.impl.PlayDevice(device); + current_audio.impl.WaitDevice(device); } } - /* Wait for the audio to drain.. */ + /* Wait for the audio to drain. */ current_audio.impl.WaitDone(device); - /* If necessary, deinit the streamer */ -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - if (device->use_streamer == 1) - SDL_StreamDeinit(&device->streamer); -#endif - - return (0); + return 0; } @@ -761,16 +695,16 @@ SDL_ParseAudioFormat(const char *string) int SDL_GetNumAudioDrivers(void) { - return (SDL_arraysize(bootstrap) - 1); + return SDL_arraysize(bootstrap) - 1; } const char * SDL_GetAudioDriver(int index) { if (index >= 0 && index < SDL_GetNumAudioDrivers()) { - return (bootstrap[index]->name); + return bootstrap[index]->name; } - return (NULL); + return NULL; } int @@ -784,8 +718,8 @@ SDL_AudioInit(const char *driver_name) SDL_AudioQuit(); /* shutdown driver if already running. */ } - SDL_memset(¤t_audio, '\0', sizeof(current_audio)); - SDL_memset(open_devices, '\0', sizeof(open_devices)); + SDL_zero(current_audio); + SDL_zero(open_devices); /* Select the proper audio driver */ if (driver_name == NULL) { @@ -801,7 +735,7 @@ SDL_AudioInit(const char *driver_name) } tried_to_init = 1; - SDL_memset(¤t_audio, 0, sizeof(current_audio)); + SDL_zero(current_audio); current_audio.name = backend->name; current_audio.desc = backend->desc; initialized = backend->init(¤t_audio.impl); @@ -817,13 +751,18 @@ SDL_AudioInit(const char *driver_name) } } - SDL_memset(¤t_audio, 0, sizeof(current_audio)); - return (-1); /* No driver was available, so fail. */ + SDL_zero(current_audio); + return -1; /* No driver was available, so fail. */ } + current_audio.detectionLock = SDL_CreateMutex(); + finalize_audio_entry_points(); - return (0); + /* Make sure we have a list of devices available at startup. */ + current_audio.impl.DetectDevices(); + + return 0; } /* @@ -835,50 +774,32 @@ SDL_GetCurrentAudioDriver() return current_audio.name; } +/* Clean out devices that we've removed but had to keep around for stability. */ static void -free_device_list(char ***devices, int *devCount) +clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *removedFlag) { - int i = *devCount; - if ((i > 0) && (*devices != NULL)) { - while (i--) { - SDL_free((*devices)[i]); + SDL_AudioDeviceItem *item = *devices; + SDL_AudioDeviceItem *prev = NULL; + int total = 0; + + while (item) { + SDL_AudioDeviceItem *next = item->next; + if (item->handle != NULL) { + total++; + prev = item; + } else { + if (prev) { + prev->next = next; + } else { + *devices = next; + } + SDL_free(item); } + item = next; } - SDL_free(*devices); - - *devices = NULL; - *devCount = 0; -} - -static -void SDL_AddCaptureAudioDevice(const char *_name) -{ - char *name = NULL; - void *ptr = SDL_realloc(current_audio.inputDevices, - (current_audio.inputDeviceCount+1) * sizeof(char*)); - if (ptr == NULL) { - return; /* oh well. */ - } - - current_audio.inputDevices = (char **) ptr; - name = SDL_strdup(_name); /* if this returns NULL, that's okay. */ - current_audio.inputDevices[current_audio.inputDeviceCount++] = name; -} - -static -void SDL_AddOutputAudioDevice(const char *_name) -{ - char *name = NULL; - void *ptr = SDL_realloc(current_audio.outputDevices, - (current_audio.outputDeviceCount+1) * sizeof(char*)); - if (ptr == NULL) { - return; /* oh well. */ - } - - current_audio.outputDevices = (char **) ptr; - name = SDL_strdup(_name); /* if this returns NULL, that's okay. */ - current_audio.outputDevices[current_audio.outputDeviceCount++] = name; + *devCount = total; + *removedFlag = SDL_FALSE; } @@ -891,29 +812,18 @@ SDL_GetNumAudioDevices(int iscapture) return -1; } - if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) { - return 0; + SDL_LockMutex(current_audio.detectionLock); + if (iscapture && current_audio.captureDevicesRemoved) { + clean_out_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount, ¤t_audio.captureDevicesRemoved); } - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { - return 1; + if (!iscapture && current_audio.outputDevicesRemoved) { + clean_out_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount, ¤t_audio.outputDevicesRemoved); + current_audio.outputDevicesRemoved = SDL_FALSE; } - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { - return 1; - } - - if (iscapture) { - free_device_list(¤t_audio.inputDevices, - ¤t_audio.inputDeviceCount); - current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice); - retval = current_audio.inputDeviceCount; - } else { - free_device_list(¤t_audio.outputDevices, - ¤t_audio.outputDeviceCount); - current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice); - retval = current_audio.outputDeviceCount; - } + retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + SDL_UnlockMutex(current_audio.detectionLock); return retval; } @@ -922,6 +832,8 @@ SDL_GetNumAudioDevices(int iscapture) const char * SDL_GetAudioDeviceName(int index, int iscapture) { + const char *retval = NULL; + if (!SDL_WasInit(SDL_INIT_AUDIO)) { SDL_SetError("Audio subsystem is not initialized"); return NULL; @@ -932,39 +844,28 @@ SDL_GetAudioDeviceName(int index, int iscapture) return NULL; } - if (index < 0) { - goto no_such_device; + if (index >= 0) { + SDL_AudioDeviceItem *item; + int i; + + SDL_LockMutex(current_audio.detectionLock); + item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; + i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + if (index < i) { + for (i--; i > index; i--, item = item->next) { + SDL_assert(item != NULL); + } + SDL_assert(item != NULL); + retval = item->name; + } + SDL_UnlockMutex(current_audio.detectionLock); } - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { - if (index > 0) { - goto no_such_device; - } - return DEFAULT_INPUT_DEVNAME; + if (retval == NULL) { + SDL_SetError("No such device"); } - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { - if (index > 0) { - goto no_such_device; - } - return DEFAULT_OUTPUT_DEVNAME; - } - - if (iscapture) { - if (index >= current_audio.inputDeviceCount) { - goto no_such_device; - } - return current_audio.inputDevices[index]; - } else { - if (index >= current_audio.outputDeviceCount) { - goto no_such_device; - } - return current_audio.outputDevices[index]; - } - -no_such_device: - SDL_SetError("No such device"); - return NULL; + return retval; } @@ -972,6 +873,7 @@ static void close_audio_device(SDL_AudioDevice * device) { device->enabled = 0; + device->shutdown = 1; if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); } @@ -1065,6 +967,8 @@ open_audio_device(const char *devname, int iscapture, SDL_AudioSpec _obtained; SDL_AudioDevice *device; SDL_bool build_cvt; + void *handle = NULL; + Uint32 stream_len; int i = 0; if (!SDL_WasInit(SDL_INIT_AUDIO)) { @@ -1077,6 +981,18 @@ open_audio_device(const char *devname, int iscapture, return 0; } + /* Find an available device ID... */ + for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) { + if (open_devices[id] == NULL) { + break; + } + } + + if (id == SDL_arraysize(open_devices)) { + SDL_SetError("Too many open audio devices"); + return 0; + } + if (!obtained) { obtained = &_obtained; } @@ -1112,9 +1028,7 @@ open_audio_device(const char *devname, int iscapture, return 0; } } - } - - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { + } else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) { SDL_SetError("No such device"); return 0; @@ -1127,6 +1041,30 @@ open_audio_device(const char *devname, int iscapture, return 0; } } + } else if (devname != NULL) { + /* if the app specifies an exact string, we can pass the backend + an actual device handle thingey, which saves them the effort of + figuring out what device this was (such as, reenumerating + everything again to find the matching human-readable name). + It might still need to open a device based on the string for, + say, a network audio server, but this optimizes some cases. */ + SDL_AudioDeviceItem *item; + SDL_LockMutex(current_audio.detectionLock); + for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) { + if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) { + handle = item->handle; + break; + } + } + SDL_UnlockMutex(current_audio.detectionLock); + } + + if (!current_audio.impl.AllowsArbitraryDeviceNames) { + /* has to be in our device list, or the default device. */ + if ((handle == NULL) && (devname != NULL)) { + SDL_SetError("No such device."); + return 0; + } } device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice)); @@ -1135,12 +1073,13 @@ open_audio_device(const char *devname, int iscapture, return 0; } SDL_zerop(device); + device->id = id + 1; device->spec = *obtained; device->enabled = 1; device->paused = 1; device->iscapture = iscapture; - /* Create a semaphore for locking the sound buffers */ + /* Create a mutex for locking the sound buffers */ if (!current_audio.impl.SkipMixerLock) { device->mixer_lock = SDL_CreateMutex(); if (device->mixer_lock == NULL) { @@ -1150,26 +1089,12 @@ open_audio_device(const char *devname, int iscapture, } } - /* force a device detection if we haven't done one yet. */ - if ( ((iscapture) && (current_audio.inputDevices == NULL)) || - ((!iscapture) && (current_audio.outputDevices == NULL)) ) { - SDL_GetNumAudioDevices(iscapture); - } - - if (current_audio.impl.OpenDevice(device, devname, iscapture) < 0) { + if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) { close_audio_device(device); return 0; } device->opened = 1; - /* Allocate a fake audio memory buffer */ - device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size); - if (device->fake_stream == NULL) { - close_audio_device(device); - SDL_OutOfMemory(); - return 0; - } - /* See if we need to do any conversion */ build_cvt = SDL_FALSE; if (obtained->freq != device->spec.freq) { @@ -1228,6 +1153,19 @@ open_audio_device(const char *devname, int iscapture, } } + /* Allocate a fake audio memory buffer */ + stream_len = (device->convert.needed) ? device->convert.len_cvt : 0; + if (device->spec.size > stream_len) { + stream_len = device->spec.size; + } + SDL_assert(stream_len > 0); + device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len); + if (device->fake_stream == NULL) { + close_audio_device(device); + SDL_OutOfMemory(); + return 0; + } + if (device->spec.callback == NULL) { /* use buffer queueing? */ /* pool a few packets to start. Enough for two callbacks. */ const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN; @@ -1247,25 +1185,14 @@ open_audio_device(const char *devname, int iscapture, device->spec.userdata = device; } - /* Find an available device ID and store the structure... */ - for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) { - if (open_devices[id] == NULL) { - open_devices[id] = device; - break; - } - } - - if (id == SDL_arraysize(open_devices)) { - SDL_SetError("Too many open audio devices"); - close_audio_device(device); - return 0; - } + /* add it to our list of open devices. */ + open_devices[id] = device; /* Start the audio thread if necessary */ if (!current_audio.impl.ProvidesOwnCallbackThread) { /* Start the audio thread */ char name[64]; - SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) (id + 1)); + SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); /* !!! FIXME: this is nasty. */ #if defined(__WIN32__) && !defined(HAVE_LIBC) #undef SDL_CreateThread @@ -1278,13 +1205,13 @@ open_audio_device(const char *devname, int iscapture, device->thread = SDL_CreateThread(SDL_RunAudio, name, device); #endif if (device->thread == NULL) { - SDL_CloseAudioDevice(id + 1); + SDL_CloseAudioDevice(device->id); SDL_SetError("Couldn't create audio thread"); return 0; } } - return id + 1; + return device->id; } @@ -1296,14 +1223,14 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) /* Start up the audio driver, if necessary. This is legacy behaviour! */ if (!SDL_WasInit(SDL_INIT_AUDIO)) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { - return (-1); + return -1; } } /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */ if (open_devices[0] != NULL) { SDL_SetError("Audio device is already opened"); - return (-1); + return -1; } if (obtained) { @@ -1314,7 +1241,7 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) } SDL_assert((id == 0) || (id == 1)); - return ((id == 0) ? -1 : 0); + return (id == 0) ? -1 : 0; } SDL_AudioDeviceID @@ -1338,7 +1265,7 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid) status = SDL_AUDIO_PLAYING; } } - return (status); + return status; } @@ -1429,14 +1356,16 @@ SDL_AudioQuit(void) } } + free_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount); + free_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); + /* Free the driver data */ current_audio.impl.Deinitialize(); - free_device_list(¤t_audio.outputDevices, - ¤t_audio.outputDeviceCount); - free_device_list(¤t_audio.inputDevices, - ¤t_audio.inputDeviceCount); - SDL_memset(¤t_audio, '\0', sizeof(current_audio)); - SDL_memset(open_devices, '\0', sizeof(open_devices)); + + SDL_DestroyMutex(current_audio.detectionLock); + + SDL_zero(current_audio); + SDL_zero(open_devices); } #define NUM_FORMATS 10 @@ -1474,16 +1403,16 @@ SDL_FirstAudioFormat(SDL_AudioFormat format) } } format_idx_sub = 0; - return (SDL_NextAudioFormat()); + return SDL_NextAudioFormat(); } SDL_AudioFormat SDL_NextAudioFormat(void) { if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) { - return (0); + return 0; } - return (format_list[format_idx][format_idx_sub++]); + return format_list[format_idx][format_idx_sub++]; } void diff --git a/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c index e9af62119..4a50c097d 100644 --- a/src/audio/SDL_audiodev.c +++ b/src/audio/SDL_audiodev.c @@ -46,18 +46,21 @@ #define _PATH_DEV_AUDIO "/dev/audio" #endif -static SDL_INLINE void -test_device(const char *fname, int flags, int (*test) (int fd), - SDL_AddAudioDevice addfn) +static void +test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd)) { struct stat sb; if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) { const int audio_fd = open(fname, flags, 0); if (audio_fd >= 0) { - if (test(audio_fd)) { - addfn(fname); - } + const int okay = test(audio_fd); close(audio_fd); + if (okay) { + static size_t dummyhandle = 0; + dummyhandle++; + SDL_assert(dummyhandle != 0); + SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle); + } } } } @@ -68,11 +71,10 @@ test_stub(int fd) return 1; } -void -SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd), - SDL_AddAudioDevice addfn) +static void +SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int)) { - const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT; const char *audiodev; char audiopath[1024]; @@ -97,17 +99,25 @@ SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd), } } } - test_device(audiodev, flags, test, addfn); + test_device(iscapture, audiodev, flags, test); if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) { int instance = 0; while (instance++ <= 64) { SDL_snprintf(audiopath, SDL_arraysize(audiopath), "%s%d", audiodev, instance); - test_device(audiopath, flags, test, addfn); + test_device(iscapture, audiopath, flags, test); } } } +void +SDL_EnumUnixAudioDevices(const int classic, int (*test)(int)) +{ + SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test); + SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test); +} + #endif /* Audio driver selection */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/SDL_audiodev_c.h b/src/audio/SDL_audiodev_c.h index 1ad0dc101..3544bfab8 100644 --- a/src/audio/SDL_audiodev_c.h +++ b/src/audio/SDL_audiodev_c.h @@ -33,7 +33,6 @@ #define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK) #endif -void SDL_EnumUnixAudioDevices(int iscapture, int classic, - int (*test) (int fd), SDL_AddAudioDevice addfn); +extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int)); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 4f933205d..502a0d317 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -30,8 +30,21 @@ typedef struct SDL_AudioDevice SDL_AudioDevice; #define _THIS SDL_AudioDevice *_this -/* Used by audio targets during DetectDevices() */ -typedef void (*SDL_AddAudioDevice)(const char *name); +/* Audio targets should call this as devices are added to the system (such as + a USB headset being plugged in), and should also be called for + for every device found during DetectDevices(). */ +extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle); + +/* Audio targets should call this as devices are removed, so SDL can update + its list of available devices. */ +extern void SDL_RemoveAudioDevice(const int iscapture, void *handle); + +/* Audio targets should call this if an opened audio device is lost while + being used. This can happen due to i/o errors, or a device being unplugged, + etc. If the device is totally gone, please also call SDL_RemoveAudioDevice() + as appropriate so SDL's list of devices is accurate. */ +extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device); + /* This is the size of a packet when using SDL_QueueAudio(). We allocate these as necessary and pool them, under the assumption that we'll @@ -55,8 +68,8 @@ typedef struct SDL_AudioBufferQueue typedef struct SDL_AudioDriverImpl { - void (*DetectDevices) (int iscapture, SDL_AddAudioDevice addfn); - int (*OpenDevice) (_THIS, const char *devname, int iscapture); + void (*DetectDevices) (void); + int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture); void (*ThreadInit) (_THIS); /* Called by audio thread at start */ void (*WaitDevice) (_THIS); void (*PlayDevice) (_THIS); @@ -66,19 +79,34 @@ typedef struct SDL_AudioDriverImpl void (*CloseDevice) (_THIS); void (*LockDevice) (_THIS); void (*UnlockDevice) (_THIS); + void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */ void (*Deinitialize) (void); /* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */ /* Some flags to push duplicate code into the core and reduce #ifdefs. */ + /* !!! FIXME: these should be SDL_bool */ int ProvidesOwnCallbackThread; int SkipMixerLock; /* !!! FIXME: do we need this anymore? */ int HasCaptureSupport; int OnlyHasDefaultOutputDevice; int OnlyHasDefaultInputDevice; + int AllowsArbitraryDeviceNames; } SDL_AudioDriverImpl; +typedef struct SDL_AudioDeviceItem +{ + void *handle; + struct SDL_AudioDeviceItem *next; + #if (defined(__GNUC__) && (__GNUC__ <= 2)) + char name[1]; /* actually variable length. */ + #else + char name[]; + #endif +} SDL_AudioDeviceItem; + + typedef struct SDL_AudioDriver { /* * * */ @@ -91,11 +119,14 @@ typedef struct SDL_AudioDriver SDL_AudioDriverImpl impl; - char **outputDevices; + /* A mutex for device detection */ + SDL_mutex *detectionLock; + SDL_bool captureDevicesRemoved; + SDL_bool outputDevicesRemoved; int outputDeviceCount; - - char **inputDevices; int inputDeviceCount; + SDL_AudioDeviceItem *outputDevices; + SDL_AudioDeviceItem *inputDevices; } SDL_AudioDriver; @@ -113,6 +144,7 @@ struct SDL_AudioDevice { /* * * */ /* Data common to all devices */ + SDL_AudioDeviceID id; /* The current audio specification (shared with audio thread) */ SDL_AudioSpec spec; @@ -125,15 +157,17 @@ struct SDL_AudioDevice SDL_AudioStreamer streamer; /* Current state flags */ + /* !!! FIXME: should be SDL_bool */ int iscapture; - int enabled; + int enabled; /* true if device is functioning and connected. */ + int shutdown; /* true if we are signaling the play thread to end. */ int paused; int opened; /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; - /* A semaphore for locking the mixing buffers */ + /* A mutex for locking the mixing buffers */ SDL_mutex *mixer_lock; /* A thread to feed the audio device */ diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 1f3def3f6..216383cae 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -320,7 +320,7 @@ ALSA_PlayDevice(_THIS) /* Hmm, not much we can do - abort */ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", ALSA_snd_strerror(status)); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); return; } continue; @@ -465,7 +465,7 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override) } static int -ALSA_OpenDevice(_THIS, const char *devname, int iscapture) +ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int status = 0; snd_pcm_t *pcm_handle = NULL; diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index fe66763b8..00537baa3 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -35,7 +35,7 @@ static SDL_AudioDevice* audioDevice = NULL; static int -AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture) +AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format; diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 72fba70cc..628d6e6ec 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -151,7 +151,7 @@ ARTS_WaitDevice(_THIS) /* Check every 10 loops */ if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } } @@ -179,7 +179,7 @@ ARTS_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -229,7 +229,7 @@ ARTS_Suspend(void) } static int -ARTS_OpenDevice(_THIS, const char *devname, int iscapture) +ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int rc = 0; int bits = 0, frag_spec = 0; diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index f415fe040..d1159e995 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -51,9 +51,9 @@ static void -BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +BSDAUDIO_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); + SDL_EnumUnixAudioDevices(0, NULL); } @@ -150,7 +150,7 @@ BSDAUDIO_WaitDevice(_THIS) the user know what happened. */ fprintf(stderr, "SDL: %s\n", message); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); /* Don't try to close - may hang */ this->hidden->audio_fd = -1; #ifdef DEBUG_AUDIO @@ -195,7 +195,7 @@ BSDAUDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -224,7 +224,7 @@ BSDAUDIO_CloseDevice(_THIS) } static int -BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); SDL_AudioFormat format = 0; @@ -348,6 +348,8 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->CloseDevice = BSDAUDIO_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 7fc9ea94b..22210b050 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -19,6 +19,9 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_COREAUDIO + #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "../SDL_sysaudio.h" @@ -37,31 +40,48 @@ static void COREAUDIO_CloseDevice(_THIS); } #if MACOSX_COREAUDIO -typedef void (*addDevFn)(const char *name, AudioDeviceID devId, void *data); +static const AudioObjectPropertyAddress devlist_address = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; -static void -addToDevList(const char *name, AudioDeviceID devId, void *data) +typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data); + +typedef struct AudioDeviceList { - SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data; - addfn(name); + AudioDeviceID devid; + SDL_bool alive; + struct AudioDeviceList *next; +} AudioDeviceList; + +static AudioDeviceList *output_devs = NULL; +static AudioDeviceList *capture_devs = NULL; + +static SDL_bool +add_to_internal_dev_list(const int iscapture, AudioDeviceID devId) +{ + AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList)); + if (item == NULL) { + return SDL_FALSE; + } + item->devid = devId; + item->alive = SDL_TRUE; + item->next = iscapture ? capture_devs : output_devs; + if (iscapture) { + capture_devs = item; + } else { + output_devs = item; + } + + return SDL_TRUE; } -typedef struct -{ - const char *findname; - AudioDeviceID devId; - int found; -} FindDevIdData; - static void -findDevId(const char *name, AudioDeviceID devId, void *_data) +addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data) { - FindDevIdData *data = (FindDevIdData *) _data; - if (!data->found) { - if (SDL_strcmp(name, data->findname) == 0) { - data->found = 1; - data->devId = devId; - } + if (add_to_internal_dev_list(iscapture, devId)) { + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); } } @@ -74,14 +94,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) UInt32 i = 0; UInt32 max = 0; - AudioObjectPropertyAddress addr = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, - 0, NULL, &size); + result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size); if (result != kAudioHardwareNoError) return; @@ -89,8 +103,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) if (devs == NULL) return; - result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - 0, NULL, &size, devs); + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size, devs); if (result != kAudioHardwareNoError) return; @@ -102,10 +116,17 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) AudioBufferList *buflist = NULL; int usable = 0; CFIndex len = 0; + const AudioObjectPropertyAddress addr = { + kAudioDevicePropertyStreamConfiguration, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; - addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : - kAudioDevicePropertyScopeOutput; - addr.mSelector = kAudioDevicePropertyStreamConfiguration; + const AudioObjectPropertyAddress nameaddr = { + kAudioObjectPropertyName, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size); if (result != noErr) @@ -133,9 +154,9 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) if (!usable) continue; - addr.mSelector = kAudioObjectPropertyName; + size = sizeof (CFStringRef); - result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, &cfstr); + result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr); if (result != kAudioHardwareNoError) continue; @@ -166,79 +187,84 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) ((iscapture) ? "capture" : "output"), (int) *devCount, ptr, (int) dev); #endif - addfn(ptr, dev, addfndata); + addfn(ptr, iscapture, dev, addfndata); } SDL_free(ptr); /* addfn() would have copied the string. */ } } static void -COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +free_audio_device_list(AudioDeviceList **list) { - build_device_list(iscapture, addToDevList, addfn); + AudioDeviceList *item = *list; + while (item) { + AudioDeviceList *next = item->next; + SDL_free(item); + item = next; + } + *list = NULL; } -static int -find_device_by_name(_THIS, const char *devname, int iscapture) +static void +COREAUDIO_DetectDevices(void) { - AudioDeviceID devid = 0; - OSStatus result = noErr; - UInt32 size = 0; - UInt32 alive = 0; - pid_t pid = 0; + build_device_list(SDL_TRUE, addToDevList, NULL); + build_device_list(SDL_FALSE, addToDevList, NULL); +} - AudioObjectPropertyAddress addr = { - 0, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - if (devname == NULL) { - size = sizeof (AudioDeviceID); - addr.mSelector = - ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice : - kAudioHardwarePropertyDefaultOutputDevice); - result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - 0, NULL, &size, &devid); - CHECK_RESULT("AudioHardwareGetProperty (default device)"); - } else { - FindDevIdData data; - SDL_zero(data); - data.findname = devname; - build_device_list(iscapture, findDevId, &data); - if (!data.found) { - SDL_SetError("CoreAudio: No such audio device."); - return 0; +static void +build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data) +{ + AudioDeviceList **list = (AudioDeviceList **) data; + AudioDeviceList *item; + for (item = *list; item != NULL; item = item->next) { + if (item->devid == devId) { + item->alive = SDL_TRUE; + return; } - devid = data.devId; } - addr.mSelector = kAudioDevicePropertyDeviceIsAlive; - addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : - kAudioDevicePropertyScopeOutput; + add_to_internal_dev_list(iscapture, devId); /* new device, add it. */ + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); +} - size = sizeof (alive); - result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive); - CHECK_RESULT - ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)"); - - if (!alive) { - SDL_SetError("CoreAudio: requested device exists, but isn't alive."); - return 0; +static void +reprocess_device_list(const int iscapture, AudioDeviceList **list) +{ + AudioDeviceList *item; + AudioDeviceList *prev = NULL; + for (item = *list; item != NULL; item = item->next) { + item->alive = SDL_FALSE; } - addr.mSelector = kAudioDevicePropertyHogMode; - size = sizeof (pid); - result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid); + build_device_list(iscapture, build_device_change_list, list); - /* some devices don't support this property, so errors are fine here. */ - if ((result == noErr) && (pid != -1)) { - SDL_SetError("CoreAudio: requested device is being hogged."); - return 0; + /* free items in the list that aren't still alive. */ + item = *list; + while (item != NULL) { + AudioDeviceList *next = item->next; + if (item->alive) { + prev = item; + } else { + SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid)); + if (prev) { + prev->next = item->next; + } else { + *list = item->next; + } + SDL_free(item); + } + item = next; } +} - this->hidden->deviceID = devid; - return 1; +/* this is called when the system's list of available audio devices changes. */ +static OSStatus +device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data) +{ + reprocess_device_list(SDL_TRUE, &capture_devs); + reprocess_device_list(SDL_FALSE, &output_devs); + return 0; } #endif @@ -314,11 +340,54 @@ inputCallback(void *inRefCon, } +#if MACOSX_COREAUDIO +static const AudioObjectPropertyAddress alive_address = +{ + kAudioDevicePropertyDeviceIsAlive, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; + +static OSStatus +device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) data; + SDL_bool dead = SDL_FALSE; + UInt32 isAlive = 1; + UInt32 size = sizeof (isAlive); + OSStatus error; + + if (!this->enabled) { + return 0; /* already known to be dead. */ + } + + error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address, + 0, NULL, &size, &isAlive); + + if (error == kAudioHardwareBadDeviceError) { + dead = SDL_TRUE; /* device was unplugged. */ + } else if ((error == kAudioHardwareNoError) && (!isAlive)) { + dead = SDL_TRUE; /* device died in some other way. */ + } + + if (dead) { + SDL_OpenedAudioDeviceDisconnected(this); + } + + return 0; +} +#endif + static void COREAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { if (this->hidden->audioUnitOpened) { + #if MACOSX_COREAUDIO + /* Unregister our disconnect callback. */ + AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); + #endif + AURenderCallbackStruct callback; const AudioUnitElement output_bus = 0; const AudioUnitElement input_bus = 1; @@ -352,9 +421,63 @@ COREAUDIO_CloseDevice(_THIS) } } +#if MACOSX_COREAUDIO +static int +prepare_device(_THIS, void *handle, int iscapture) +{ + AudioDeviceID devid = (AudioDeviceID) ((size_t) handle); + OSStatus result = noErr; + UInt32 size = 0; + UInt32 alive = 0; + pid_t pid = 0; + + AudioObjectPropertyAddress addr = { + 0, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (handle == NULL) { + size = sizeof (AudioDeviceID); + addr.mSelector = + ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice : + kAudioHardwarePropertyDefaultOutputDevice); + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, + 0, NULL, &size, &devid); + CHECK_RESULT("AudioHardwareGetProperty (default device)"); + } + + addr.mSelector = kAudioDevicePropertyDeviceIsAlive; + addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : + kAudioDevicePropertyScopeOutput; + + size = sizeof (alive); + result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive); + CHECK_RESULT + ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)"); + + if (!alive) { + SDL_SetError("CoreAudio: requested device exists, but isn't alive."); + return 0; + } + + addr.mSelector = kAudioDevicePropertyHogMode; + size = sizeof (pid); + result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid); + + /* some devices don't support this property, so errors are fine here. */ + if ((result == noErr) && (pid != -1)) { + SDL_SetError("CoreAudio: requested device is being hogged."); + return 0; + } + + this->hidden->deviceID = devid; + return 1; +} +#endif static int -prepare_audiounit(_THIS, const char *devname, int iscapture, +prepare_audiounit(_THIS, void *handle, int iscapture, const AudioStreamBasicDescription * strdesc) { OSStatus result = noErr; @@ -373,8 +496,7 @@ prepare_audiounit(_THIS, const char *devname, int iscapture, kAudioUnitScope_Input); #if MACOSX_COREAUDIO - if (!find_device_by_name(this, devname, iscapture)) { - SDL_SetError("Couldn't find requested CoreAudio device"); + if (!prepare_device(this, handle, iscapture)) { return 0; } #endif @@ -451,13 +573,18 @@ prepare_audiounit(_THIS, const char *devname, int iscapture, result = AudioOutputUnitStart(this->hidden->audioUnit); CHECK_RESULT("AudioOutputUnitStart"); +#if MACOSX_COREAUDIO + /* Fire a callback if the device stops being "alive" (disconnected, etc). */ + AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); +#endif + /* We're running! */ return 1; } static int -COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { AudioStreamBasicDescription strdesc; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); @@ -516,7 +643,7 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; - if (!prepare_audiounit(this, devname, iscapture, &strdesc)) { + if (!prepare_audiounit(this, handle, iscapture, &strdesc)) { COREAUDIO_CloseDevice(this); return -1; /* prepare_audiounit() will call SDL_SetError()... */ } @@ -524,15 +651,27 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return 0; /* good to go. */ } +static void +COREAUDIO_Deinitialize(void) +{ +#if MACOSX_COREAUDIO + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); + free_audio_device_list(&capture_devs); + free_audio_device_list(&output_devs); +#endif +} + static int COREAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ impl->OpenDevice = COREAUDIO_OpenDevice; impl->CloseDevice = COREAUDIO_CloseDevice; + impl->Deinitialize = COREAUDIO_Deinitialize; #if MACOSX_COREAUDIO impl->DetectDevices = COREAUDIO_DetectDevices; + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); #else impl->OnlyHasDefaultOutputDevice = 1; @@ -554,4 +693,6 @@ AudioBootStrap COREAUDIO_bootstrap = { "coreaudio", "CoreAudio", COREAUDIO_Init, 0 }; +#endif /* SDL_AUDIO_DRIVER_COREAUDIO */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 067683ccc..99e34521f 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -144,15 +144,22 @@ SetDSerror(const char *function, int code) return SDL_SetError("%s", errbuf); } +static void +DSOUND_FreeDeviceHandle(void *handle) +{ + SDL_free(handle); +} static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) { - SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data; + const int iscapture = (int) ((size_t) data); if (guid != NULL) { /* skip default device */ char *str = WIN_StringToUTF8(desc); if (str != NULL) { - addfn(str); + LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID)); + SDL_memcpy(cpyguid, guid, sizeof (GUID)); + SDL_AddAudioDevice(iscapture, str, cpyguid); SDL_free(str); /* addfn() makes a copy of this string. */ } } @@ -160,13 +167,10 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) } static void -DSOUND_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +DSOUND_DetectDevices(void) { - if (iscapture) { - pDirectSoundCaptureEnumerateW(FindAllDevs, addfn); - } else { - pDirectSoundEnumerateW(FindAllDevs, addfn); - } + pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1)); + pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0)); } @@ -419,53 +423,14 @@ CreateSecondary(_THIS, HWND focus) return (numchunks); } -typedef struct FindDevGUIDData -{ - const char *devname; - GUID guid; - int found; -} FindDevGUIDData; - -static BOOL CALLBACK -FindDevGUID(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID _data) -{ - if (guid != NULL) { /* skip the default device. */ - FindDevGUIDData *data = (FindDevGUIDData *) _data; - char *str = WIN_StringToUTF8(desc); - const int match = (SDL_strcmp(str, data->devname) == 0); - SDL_free(str); - if (match) { - data->found = 1; - SDL_memcpy(&data->guid, guid, sizeof (data->guid)); - return FALSE; /* found it! stop enumerating. */ - } - } - return TRUE; /* keep enumerating. */ -} - static int -DSOUND_OpenDevice(_THIS, const char *devname, int iscapture) +DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { HRESULT result; SDL_bool valid_format = SDL_FALSE; SDL_bool tried_format = SDL_FALSE; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - FindDevGUIDData devguid; - LPGUID guid = NULL; - - if (devname != NULL) { - devguid.found = 0; - devguid.devname = devname; - if (iscapture) - pDirectSoundCaptureEnumerateW(FindDevGUID, &devguid); - else - pDirectSoundEnumerateW(FindDevGUID, &devguid); - - if (!devguid.found) { - return SDL_SetError("DirectSound: Requested device not found"); - } - guid = &devguid.guid; - } + LPGUID guid = (LPGUID) handle; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -536,6 +501,8 @@ DSOUND_Init(SDL_AudioDriverImpl * impl) impl->WaitDone = DSOUND_WaitDone; impl->GetDeviceBuf = DSOUND_GetDeviceBuf; impl->CloseDevice = DSOUND_CloseDevice; + impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; + impl->Deinitialize = DSOUND_Deinitialize; return 1; /* this audio target is available. */ diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index cc4e3efc6..1577b6f23 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -71,7 +71,7 @@ DISKAUD_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written != this->hidden->mixlen) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -100,7 +100,7 @@ DISKAUD_CloseDevice(_THIS) } static int -DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture) +DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const char *envr = SDL_getenv(DISKENVR_WRITEDELAY); const char *fname = DISKAUD_GetOutputFilename(devname); @@ -151,6 +151,8 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; impl->CloseDevice = DISKAUD_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index eea5a5f86..0d34e9512 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -51,9 +51,9 @@ static void -DSP_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +DSP_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); + SDL_EnumUnixAudioDevices(0, NULL); } @@ -74,7 +74,7 @@ DSP_CloseDevice(_THIS) static int -DSP_OpenDevice(_THIS, const char *devname, int iscapture) +DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); int format; @@ -270,7 +270,7 @@ DSP_PlayDevice(_THIS) const int mixlen = this->hidden->mixlen; if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { perror("Audio write"); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); @@ -293,6 +293,8 @@ DSP_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = DSP_GetDeviceBuf; impl->CloseDevice = DSP_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index 671e222cf..965b4ce56 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -27,7 +27,7 @@ #include "SDL_dummyaudio.h" static int -DUMMYAUD_OpenDevice(_THIS, const char *devname, int iscapture) +DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { return 0; /* always succeeds. */ } diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index d9334daec..2147baedb 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -151,12 +151,13 @@ Emscripten_CloseDevice(_THIS) } static int -Emscripten_OpenDevice(_THIS, const char *devname, int iscapture) +Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_bool valid_format = SDL_FALSE; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); int i; float f; + int result; while ((!valid_format) && (test_format)) { switch (test_format) { @@ -185,7 +186,7 @@ Emscripten_OpenDevice(_THIS, const char *devname, int iscapture) /* based on parts of library_sdl.js */ /* create context (TODO: this puts stuff in the global namespace...)*/ - EM_ASM({ + result = EM_ASM_INT_V({ if(typeof(SDL2) === 'undefined') SDL2 = {}; @@ -198,10 +199,14 @@ Emscripten_OpenDevice(_THIS, const char *devname, int iscapture) } else if (typeof(webkitAudioContext) !== 'undefined') { SDL2.audioContext = new webkitAudioContext(); } else { - throw 'Web Audio API is not available!'; + return -1; } } + return 0; }); + if (result < 0) { + return SDL_SetError("Web Audio API is not available!"); + } /* limit to native freq */ int sampleRate = EM_ASM_INT_V({ diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index e675272dc..7f18337d9 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -129,7 +129,7 @@ ESD_WaitDevice(_THIS) /* Check every 10 loops */ if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } } @@ -161,7 +161,7 @@ ESD_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -215,7 +215,7 @@ get_progname(void) static int -ESD_OpenDevice(_THIS, const char *devname, int iscapture) +ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { esd_format_t format = (ESD_STREAM | ESD_PLAY); SDL_AudioFormat test_format = 0; diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index b8367715f..dae4f4afa 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -143,7 +143,7 @@ SDL_FS_PlayDevice(_THIS) this->hidden->mixsamples); /* If we couldn't write, assume fatal error for now */ if (ret) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); @@ -186,7 +186,7 @@ SDL_FS_CloseDevice(_THIS) static int -SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture) +SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int bytes; SDL_AudioFormat test_format = 0, format = 0; diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index dddb77922..648987a14 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -111,7 +111,7 @@ UnmaskSignals(sigset_t * omask) static int -HAIKUAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int valid_datatype = 0; media_raw_audio_format format; diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index d9179f272..643666d6a 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -20,6 +20,9 @@ */ #include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_NACL + #include "SDL_naclaudio.h" #include "SDL_audio.h" @@ -40,7 +43,7 @@ #define SAMPLE_FRAME_COUNT 4096 /* Audio driver functions */ -static int NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture); +static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture); static void NACLAUD_CloseDevice(_THIS); static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data); @@ -82,7 +85,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) { } static int -NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture) { +NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { PP_Instance instance = PSGetInstanceId(); const PPB_Audio *ppb_audio = PSInterfaceAudio(); const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig(); @@ -127,9 +130,7 @@ NACLAUD_Init(SDL_AudioDriverImpl * impl) /* Set the function pointers */ impl->OpenDevice = NACLAUD_OpenDevice; impl->CloseDevice = NACLAUD_CloseDevice; - impl->HasCaptureSupport = 0; impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; impl->ProvidesOwnCallbackThread = 1; /* * impl->WaitDevice = NACLAUD_WaitDevice; @@ -145,3 +146,7 @@ AudioBootStrap NACLAUD_bootstrap = { NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver", NACLAUD_Init, 0 }; + +#endif /* SDL_AUDIO_DRIVER_NACL */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index a41a480f2..fe5bd8eda 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -276,7 +276,7 @@ find_device(_THIS, int nch) } static int -NAS_OpenDevice(_THIS, const char *devname, int iscapture) +NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { AuElement elms[3]; int buffer_size; diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 032d8d2cd..5f7d26c92 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -176,7 +176,7 @@ PAUDIO_WaitDevice(_THIS) * the user know what happened. */ fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); /* Don't try to close - may hang */ this->hidden->audio_fd = -1; #ifdef DEBUG_AUDIO @@ -212,7 +212,7 @@ PAUDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -241,7 +241,7 @@ PAUDIO_CloseDevice(_THIS) } static int -PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); char audiodev[1024]; diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 5b1705926..59cbeb41c 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_PSP #include #include @@ -40,7 +43,7 @@ #define PSPAUD_DRIVER_NAME "psp" static int -PSPAUD_OpenDevice(_THIS, const char *devname, int iscapture) +PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int format, mixlen, i; this->hidden = (struct SDL_PrivateAudioData *) @@ -191,5 +194,6 @@ AudioBootStrap PSPAUD_bootstrap = { /* SDL_AUDI */ +#endif /* SDL_AUDIO_DRIVER_PSP */ - +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/psp/SDL_pspaudio.h b/src/audio/psp/SDL_pspaudio.h index 8e420f313..3b7ffb0a0 100644 --- a/src/audio/psp/SDL_pspaudio.h +++ b/src/audio/psp/SDL_pspaudio.h @@ -24,7 +24,7 @@ #include "../SDL_sysaudio.h" -/* Hidden "this" pointer for the video functions */ +/* Hidden "this" pointer for the audio functions */ #define _THIS SDL_AudioDevice *this #define NUM_BUFFERS 2 diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index c3e1238b4..adcbdee2d 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -26,6 +26,7 @@ Stéphan Kochen: stephan .a.t. kochen.nl */ #include "../../SDL_internal.h" +#include "SDL_assert.h" #if SDL_AUDIO_DRIVER_PULSEAUDIO @@ -38,7 +39,6 @@ #include #include #include -#include #include "SDL_timer.h" #include "SDL_audio.h" @@ -66,16 +66,14 @@ static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t x) { static const char *(*PULSEAUDIO_pa_get_library_version) (void); -static pa_simple *(*PULSEAUDIO_pa_simple_new) (const char *, const char *, - pa_stream_direction_t, const char *, const char *, const pa_sample_spec *, - const pa_channel_map *, const pa_buffer_attr *, int *); -static void (*PULSEAUDIO_pa_simple_free) (pa_simple *); static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) ( pa_channel_map *, unsigned, pa_channel_map_def_t); static const char * (*PULSEAUDIO_pa_strerror) (int); static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (void); static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *); static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int, int *); +static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *, int *); +static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int); static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *); static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) ( @@ -87,7 +85,13 @@ static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *, const char *); static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *, pa_context_flags_t, const pa_spawn_api *); +static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *, uint32_t, pa_sink_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *, uint32_t, pa_source_info_cb_t, void *); static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *); +static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t, void *); +static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t, void *); static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *); static void (*PULSEAUDIO_pa_context_unref) (pa_context *); @@ -179,18 +183,24 @@ static int load_pulseaudio_syms(void) { SDL_PULSEAUDIO_SYM(pa_get_library_version); - SDL_PULSEAUDIO_SYM(pa_simple_new); - SDL_PULSEAUDIO_SYM(pa_simple_free); SDL_PULSEAUDIO_SYM(pa_mainloop_new); SDL_PULSEAUDIO_SYM(pa_mainloop_get_api); SDL_PULSEAUDIO_SYM(pa_mainloop_iterate); + SDL_PULSEAUDIO_SYM(pa_mainloop_run); + SDL_PULSEAUDIO_SYM(pa_mainloop_quit); SDL_PULSEAUDIO_SYM(pa_mainloop_free); SDL_PULSEAUDIO_SYM(pa_operation_get_state); SDL_PULSEAUDIO_SYM(pa_operation_cancel); SDL_PULSEAUDIO_SYM(pa_operation_unref); SDL_PULSEAUDIO_SYM(pa_context_new); SDL_PULSEAUDIO_SYM(pa_context_connect); + SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list); + SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list); + SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index); + SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index); SDL_PULSEAUDIO_SYM(pa_context_get_state); + SDL_PULSEAUDIO_SYM(pa_context_subscribe); + SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback); SDL_PULSEAUDIO_SYM(pa_context_disconnect); SDL_PULSEAUDIO_SYM(pa_context_unref); SDL_PULSEAUDIO_SYM(pa_stream_new); @@ -206,122 +216,6 @@ load_pulseaudio_syms(void) return 0; } - -/* Check to see if we can connect to PulseAudio */ -static SDL_bool -CheckPulseAudioAvailable() -{ - pa_simple *s; - pa_sample_spec ss; - - ss.format = PA_SAMPLE_S16NE; - ss.channels = 1; - ss.rate = 22050; - - s = PULSEAUDIO_pa_simple_new(NULL, "SDL", PA_STREAM_PLAYBACK, NULL, - "Test", &ss, NULL, NULL, NULL); - if (s) { - PULSEAUDIO_pa_simple_free(s); - return SDL_TRUE; - } else { - return SDL_FALSE; - } -} - -/* This function waits until it is possible to write a full sound buffer */ -static void -PULSEAUDIO_WaitDevice(_THIS) -{ - struct SDL_PrivateAudioData *h = this->hidden; - - while(1) { - if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || - PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || - PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - this->enabled = 0; - return; - } - if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { - return; - } - } -} - -static void -PULSEAUDIO_PlayDevice(_THIS) -{ - /* Write the audio data */ - struct SDL_PrivateAudioData *h = this->hidden; - if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, - PA_SEEK_RELATIVE) < 0) { - this->enabled = 0; - } -} - -static void -stream_drain_complete(pa_stream *s, int success, void *userdata) -{ - /* no-op for pa_stream_drain() to use for callback. */ -} - -static void -PULSEAUDIO_WaitDone(_THIS) -{ - struct SDL_PrivateAudioData *h = this->hidden; - pa_operation *o; - - o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); - if (!o) { - return; - } - - while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || - PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || - PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_pa_operation_cancel(o); - break; - } - } - - PULSEAUDIO_pa_operation_unref(o); -} - - - -static Uint8 * -PULSEAUDIO_GetDeviceBuf(_THIS) -{ - return (this->hidden->mixbuf); -} - - -static void -PULSEAUDIO_CloseDevice(_THIS) -{ - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); - PULSEAUDIO_pa_stream_unref(this->hidden->stream); - this->hidden->stream = NULL; - } - if (this->hidden->context != NULL) { - PULSEAUDIO_pa_context_disconnect(this->hidden->context); - PULSEAUDIO_pa_context_unref(this->hidden->context); - this->hidden->context = NULL; - } - if (this->hidden->mainloop != NULL) { - PULSEAUDIO_pa_mainloop_free(this->hidden->mainloop); - this->hidden->mainloop = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; - } -} - - static SDL_INLINE int squashVersion(const int major, const int minor, const int patch) { @@ -344,8 +238,193 @@ getAppName(void) return "SDL Application"; /* oh well. */ } +static void +WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o) +{ + /* This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about. */ + if (mainloop && o) { + SDL_bool okay = SDL_TRUE; + while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) { + okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) >= 0); + } + PULSEAUDIO_pa_operation_unref(o); + } +} + +static void +DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *context) +{ + if (context) { + PULSEAUDIO_pa_context_disconnect(context); + PULSEAUDIO_pa_context_unref(context); + } + if (mainloop != NULL) { + PULSEAUDIO_pa_mainloop_free(mainloop); + } +} + static int -PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context) +{ + pa_mainloop *mainloop = NULL; + pa_context *context = NULL; + pa_mainloop_api *mainloop_api = NULL; + int state = 0; + + *_mainloop = NULL; + *_context = NULL; + + /* Set up a new main loop */ + if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) { + return SDL_SetError("pa_mainloop_new() failed"); + } + + *_mainloop = mainloop; + + mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop); + SDL_assert(mainloop_api); /* this never fails, right? */ + + context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName()); + if (!context) { + return SDL_SetError("pa_context_new() failed"); + } + *_context = context; + + /* Connect to the PulseAudio server */ + if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) { + return SDL_SetError("Could not setup connection to PulseAudio"); + } + + do { + if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) { + return SDL_SetError("pa_mainloop_iterate() failed"); + } + state = PULSEAUDIO_pa_context_get_state(context); + if (!PA_CONTEXT_IS_GOOD(state)) { + return SDL_SetError("Could not connect to PulseAudio"); + } + } while (state != PA_CONTEXT_READY); + + return 0; /* connected and ready! */ +} + +static int +ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context) +{ + const int retval = ConnectToPulseServer_Internal(_mainloop, _context); + if (retval < 0) { + DisconnectFromPulseServer(*_mainloop, *_context); + } + return retval; +} + + +/* This function waits until it is possible to write a full sound buffer */ +static void +PULSEAUDIO_WaitDevice(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + + while (this->enabled) { + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + return; + } + if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { + return; + } + } +} + +static void +PULSEAUDIO_PlayDevice(_THIS) +{ + /* Write the audio data */ + struct SDL_PrivateAudioData *h = this->hidden; + if (this->enabled) { + if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + } + } +} + +static void +stream_drain_complete(pa_stream *s, int success, void *userdata) +{ + /* no-op for pa_stream_drain() to use for callback. */ +} + +static void +PULSEAUDIO_WaitDone(_THIS) +{ + if (this->enabled) { + struct SDL_PrivateAudioData *h = this->hidden; + pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); + if (o) { + while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + PULSEAUDIO_pa_operation_cancel(o); + break; + } + } + PULSEAUDIO_pa_operation_unref(o); + } + } +} + + + +static Uint8 * +PULSEAUDIO_GetDeviceBuf(_THIS) +{ + return (this->hidden->mixbuf); +} + + +static void +PULSEAUDIO_CloseDevice(_THIS) +{ + if (this->hidden != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->device_name); + if (this->hidden->stream) { + PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); + PULSEAUDIO_pa_stream_unref(this->hidden->stream); + } + DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); + SDL_free(this->hidden); + this->hidden = NULL; + } +} + +static void +DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + char **devname = (char **) data; + *devname = SDL_strdup(i->name); + } +} + +static SDL_bool +FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) +{ + const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; + + if (handle == NULL) { /* NULL == default device. */ + return SDL_TRUE; + } + + WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name)); + return (h->device_name != NULL); +} + +static int +PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { struct SDL_PrivateAudioData *h = NULL; Uint16 test_format = 0; @@ -442,42 +521,21 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) paattr.minreq = h->mixlen; #endif + if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) { + PULSEAUDIO_CloseDevice(this); + return SDL_SetError("Could not connect to PulseAudio server"); + } + + if (!FindDeviceName(h, handle)) { + PULSEAUDIO_CloseDevice(this); + return SDL_SetError("Requested PulseAudio sink missing?"); + } + /* The SDL ALSA output hints us that we use Windows' channel mapping */ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */ PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels, PA_CHANNEL_MAP_WAVEEX); - /* Set up a new main loop */ - if (!(h->mainloop = PULSEAUDIO_pa_mainloop_new())) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_new() failed"); - } - - h->mainloop_api = PULSEAUDIO_pa_mainloop_get_api(h->mainloop); - h->context = PULSEAUDIO_pa_context_new(h->mainloop_api, getAppName()); - if (!h->context) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_context_new() failed"); - } - - /* Connect to the PulseAudio server */ - if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not setup connection to PulseAudio"); - } - - do { - if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_iterate() failed"); - } - state = PULSEAUDIO_pa_context_get_state(h->context); - if (!PA_CONTEXT_IS_GOOD(state)) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not connect to PulseAudio"); - } - } while (state != PA_CONTEXT_READY); - h->stream = PULSEAUDIO_pa_stream_new( h->context, "Simple DirectMedia Layer", /* stream description */ @@ -490,7 +548,13 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return SDL_SetError("Could not set up PulseAudio stream"); } - if (PULSEAUDIO_pa_stream_connect_playback(h->stream, NULL, &paattr, flags, + /* now that we have multi-device support, don't move a stream from + a device that was unplugged to something else, unless we're default. */ + if (h->device_name != NULL) { + flags |= PA_STREAM_DONT_MOVE; + } + + if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL) < 0) { PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); @@ -504,7 +568,7 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) state = PULSEAUDIO_pa_stream_get_state(h->stream); if (!PA_STREAM_IS_GOOD(state)) { PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not create to PulseAudio stream"); + return SDL_SetError("Could not connect PulseAudio stream"); } } while (state != PA_STREAM_READY); @@ -512,10 +576,92 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return 0; } +static pa_mainloop *hotplug_mainloop = NULL; +static pa_context *hotplug_context = NULL; +static SDL_Thread *hotplug_thread = NULL; + +/* device handles are device index + 1, cast to void*, so we never pass a NULL. */ + +/* This is called when PulseAudio adds an output ("sink") device. */ +static void +SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1)); + } +} + +/* This is called when PulseAudio adds a capture ("source") device. */ +static void +SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data) +{ + if (i) { + /* Skip "monitor" sources. These are just output from other sinks. */ + if (i->monitor_of_sink == PA_INVALID_INDEX) { + SDL_AddAudioDevice(SDL_TRUE, i->description, (void *) ((size_t) i->index+1)); + } + } +} + +/* This is called when PulseAudio has a device connected/removed/changed. */ +static void +HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *data) +{ + const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW); + const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE); + + if (added || removed) { /* we only care about add/remove events. */ + const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK); + const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE); + + /* adds need sink details from the PulseAudio server. Another callback... */ + if (added && sink) { + PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback, NULL); + } else if (added && source) { + PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback, NULL); + } else if (removed && (sink || source)) { + /* removes we can handle just with the device index. */ + SDL_RemoveAudioDevice(source != 0, (void *) ((size_t) idx+1)); + } + } +} + +/* this runs as a thread while the Pulse target is initialized to catch hotplug events. */ +static int SDLCALL +HotplugThread(void *data) +{ + pa_operation *o; + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW); + PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback, NULL); + o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL); + PULSEAUDIO_pa_operation_unref(o); /* don't wait for it, just do our thing. */ + PULSEAUDIO_pa_mainloop_run(hotplug_mainloop, NULL); + return 0; +} + +static void +PULSEAUDIO_DetectDevices() +{ + WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback, NULL)); + WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback, NULL)); + + /* ok, we have a sane list, let's set up hotplug notifications now... */ + hotplug_thread = SDL_CreateThread(HotplugThread, "PulseHotplug", NULL); +} static void PULSEAUDIO_Deinitialize(void) { + if (hotplug_thread) { + PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0); + SDL_WaitThread(hotplug_thread, NULL); + hotplug_thread = NULL; + } + + DisconnectFromPulseServer(hotplug_mainloop, hotplug_context); + hotplug_mainloop = NULL; + hotplug_context = NULL; + UnloadPulseAudioLibrary(); } @@ -526,12 +672,13 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) return 0; } - if (!CheckPulseAudioAvailable()) { + if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) { UnloadPulseAudioLibrary(); return 0; } /* Set the function pointers */ + impl->DetectDevices = PULSEAUDIO_DetectDevices; impl->OpenDevice = PULSEAUDIO_OpenDevice; impl->PlayDevice = PULSEAUDIO_PlayDevice; impl->WaitDevice = PULSEAUDIO_WaitDevice; @@ -539,12 +686,10 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = PULSEAUDIO_CloseDevice; impl->WaitDone = PULSEAUDIO_WaitDone; impl->Deinitialize = PULSEAUDIO_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; return 1; /* this audio target is available. */ } - AudioBootStrap PULSEAUDIO_bootstrap = { "pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0 }; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.h b/src/audio/pulseaudio/SDL_pulseaudio.h index a75409bc0..10568ffb9 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.h +++ b/src/audio/pulseaudio/SDL_pulseaudio.h @@ -32,9 +32,10 @@ struct SDL_PrivateAudioData { + char *device_name; + /* pulseaudio structures */ pa_mainloop *mainloop; - pa_mainloop_api *mainloop_api; pa_context *context; pa_stream *stream; diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index d6b8a6800..dcb7d38da 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -19,6 +19,15 @@ 3. This notice may not be removed or altered from any source distribution. */ +/* + * !!! FIXME: streamline this a little by removing all the + * !!! FIXME: if (capture) {} else {} sections that are identical + * !!! FIXME: except for one flag. + */ + +/* !!! FIXME: can this target support hotplugging? */ +/* !!! FIXME: ...does SDL2 even support QNX? */ + #include "../../SDL_internal.h" #if SDL_AUDIO_DRIVER_QSA @@ -300,7 +309,7 @@ QSA_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (towrite != 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -337,8 +346,9 @@ QSA_CloseDevice(_THIS) } static int -QSA_OpenDevice(_THIS, const char *devname, int iscapture) +QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { + const QSA_Device *device = (const QSA_Device *) handle; int status = 0; int format = 0; SDL_AudioFormat test_format = 0; @@ -363,80 +373,19 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture) /* Initialize channel direction: capture or playback */ this->hidden->iscapture = iscapture; - /* Find deviceid and cardid by device name for playback */ - if ((!this->hidden->iscapture) && (devname != NULL)) { - uint32_t device; - int32_t status; - - /* Search in the playback devices */ - device = 0; - do { - status = SDL_strcmp(qsa_playback_device[device].name, devname); - if (status == 0) { - /* Found requested device */ - this->hidden->deviceno = qsa_playback_device[device].deviceno; - this->hidden->cardno = qsa_playback_device[device].cardno; - break; - } - device++; - if (device >= qsa_playback_devices) { - QSA_CloseDevice(this); - return SDL_SetError("No such playback device"); - } - } while (1); - } - - /* Find deviceid and cardid by device name for capture */ - if ((this->hidden->iscapture) && (devname != NULL)) { - /* Search in the capture devices */ - uint32_t device; - int32_t status; - - /* Searching in the playback devices */ - device = 0; - do { - status = SDL_strcmp(qsa_capture_device[device].name, devname); - if (status == 0) { - /* Found requested device */ - this->hidden->deviceno = qsa_capture_device[device].deviceno; - this->hidden->cardno = qsa_capture_device[device].cardno; - break; - } - device++; - if (device >= qsa_capture_devices) { - QSA_CloseDevice(this); - return SDL_SetError("No such capture device"); - } - } while (1); - } - - /* Check if SDL requested default audio device */ - if (devname == NULL) { - /* Open system default audio device */ - if (!this->hidden->iscapture) { - status = snd_pcm_open_preferred(&this->hidden->audio_handle, - &this->hidden->cardno, - &this->hidden->deviceno, - SND_PCM_OPEN_PLAYBACK); - } else { - status = snd_pcm_open_preferred(&this->hidden->audio_handle, - &this->hidden->cardno, - &this->hidden->deviceno, - SND_PCM_OPEN_CAPTURE); - } - } else { + if (device != NULL) { /* Open requested audio device */ - if (!this->hidden->iscapture) { - status = - snd_pcm_open(&this->hidden->audio_handle, - this->hidden->cardno, this->hidden->deviceno, - SND_PCM_OPEN_PLAYBACK); - } else { - status = - snd_pcm_open(&this->hidden->audio_handle, - this->hidden->cardno, this->hidden->deviceno, - SND_PCM_OPEN_CAPTURE); - } + this->hidden->deviceno = device->deviceno; + this->hidden->cardno = device->cardno; + status = snd_pcm_open(&this->hidden->audio_handle, + device->cardno, device->deviceno, + iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE); + } else { + /* Open system default audio device */ + status = snd_pcm_open_preferred(&this->hidden->audio_handle, + &this->hidden->cardno, + &this->hidden->deviceno, + iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE); } /* Check if requested device is opened */ @@ -638,7 +587,7 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture) } static void -QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +QSA_DetectDevices(void) { uint32_t it; uint32_t cards; @@ -656,8 +605,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) return; } + /* !!! FIXME: code duplication */ /* Find requested devices by type */ - if (!iscapture) { + { /* output devices */ /* Playback devices enumeration requested */ for (it = 0; it < cards; it++) { devices = 0; @@ -688,7 +638,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) devices; status = snd_pcm_close(handle); if (status == EOK) { - addfn(qsa_playback_device[qsa_playback_devices].name); + SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]); qsa_playback_devices++; } } else { @@ -713,7 +663,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) break; } } - } else { + } + + { /* capture devices */ /* Capture devices enumeration requested */ for (it = 0; it < cards; it++) { devices = 0; @@ -744,7 +696,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) devices; status = snd_pcm_close(handle); if (status == EOK) { - addfn(qsa_capture_device[qsa_capture_devices].name); + SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]); qsa_capture_devices++; } } else { diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 5c0636500..f8757d127 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -158,7 +158,7 @@ SNDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if ( written == 0 ) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -193,7 +193,7 @@ SNDIO_CloseDevice(_THIS) } static int -SNDIO_OpenDevice(_THIS, const char *devname, int iscapture) +SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); struct sio_par par; diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index 7efe30ece..ff35b6b1c 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -56,9 +56,9 @@ static Uint8 snd2au(int sample); /* Audio driver bootstrap functions */ static void -SUNAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +SUNAUDIO_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 1, (int (*)(int fd)) NULL, addfn); + SDL_EnumUnixAudioDevices(1, (int (*)(int)) NULL); } #ifdef DEBUG_AUDIO @@ -158,7 +158,7 @@ SUNAUDIO_PlayDevice(_THIS) if (write(this->hidden->audio_fd, this->hidden->ulaw_buf, this->hidden->fragsize) < 0) { /* Assume fatal error, for now */ - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } this->hidden->written += this->hidden->fragsize; } else { @@ -168,7 +168,7 @@ SUNAUDIO_PlayDevice(_THIS) if (write(this->hidden->audio_fd, this->hidden->mixbuf, this->spec.size) < 0) { /* Assume fatal error, for now */ - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } this->hidden->written += this->hidden->fragsize; } @@ -198,7 +198,7 @@ SUNAUDIO_CloseDevice(_THIS) } static int -SUNAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); SDL_AudioFormat format = 0; @@ -414,6 +414,8 @@ SUNAUDIO_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf; impl->CloseDevice = SUNAUDIO_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 88a8154ec..a61ac237d 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -36,8 +36,9 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -#define DETECT_DEV_IMPL(typ, capstyp) \ -static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \ +#define DETECT_DEV_IMPL(iscap, typ, capstyp) \ +static void DetectWave##typ##Devs(void) { \ + const UINT iscapture = iscap ? 1 : 0; \ const UINT devcount = wave##typ##GetNumDevs(); \ capstyp caps; \ UINT i; \ @@ -45,24 +46,21 @@ static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \ if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ char *name = WIN_StringToUTF8(caps.szPname); \ if (name != NULL) { \ - addfn(name); \ + SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \ SDL_free(name); \ } \ } \ } \ } -DETECT_DEV_IMPL(Out, WAVEOUTCAPS) -DETECT_DEV_IMPL(In, WAVEINCAPS) +DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS) +DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS) static void -WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +WINMM_DetectDevices(void) { - if (iscapture) { - DetectWaveInDevs(addfn); - } else { - DetectWaveOutDevs(addfn); - } + DetectWaveInDevs(); + DetectWaveOutDevs(); } static void CALLBACK @@ -220,48 +218,19 @@ PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture) } static int -WINMM_OpenDevice(_THIS, const char *devname, int iscapture) +WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); int valid_datatype = 0; MMRESULT result; WAVEFORMATEX waveformat; UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */ - char *utf8 = NULL; UINT i; - if (devname != NULL) { /* specific device requested? */ - if (iscapture) { - const UINT devcount = waveInGetNumDevs(); - WAVEINCAPS caps; - for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { - result = waveInGetDevCaps(i, &caps, sizeof (caps)); - if (result != MMSYSERR_NOERROR) - continue; - else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) - continue; - else if (SDL_strcmp(devname, utf8) == 0) - devId = i; - SDL_free(utf8); - } - } else { - const UINT devcount = waveOutGetNumDevs(); - WAVEOUTCAPS caps; - for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { - result = waveOutGetDevCaps(i, &caps, sizeof (caps)); - if (result != MMSYSERR_NOERROR) - continue; - else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) - continue; - else if (SDL_strcmp(devname, utf8) == 0) - devId = i; - SDL_free(utf8); - } - } - - if (devId == WAVE_MAPPER) { - return SDL_SetError("Requested device not found"); - } + if (handle != NULL) { /* specific device requested? */ + /* -1 because we increment the original value to avoid NULL. */ + const size_t val = ((size_t) handle) - 1; + devId = (UINT) val; } /* Initialize all variables that we clean on shutdown */ @@ -279,10 +248,6 @@ WINMM_OpenDevice(_THIS, const char *devname, int iscapture) if (this->spec.channels > 2) this->spec.channels = 2; /* !!! FIXME: is this right? */ - /* Check the buffer size -- minimum of 1/4 second (word aligned) */ - if (this->spec.samples < (this->spec.freq / 4)) - this->spec.samples = ((this->spec.freq / 4) + 3) & ~3; - while ((!valid_datatype) && (test_format)) { switch (test_format) { case AUDIO_U8: diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index 85ac14602..15fce4a8d 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -126,16 +126,13 @@ struct SDL_PrivateAudioData static void -XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +XAUDIO2_DetectDevices(void) { IXAudio2 *ixa2 = NULL; UINT32 devcount = 0; UINT32 i = 0; - if (iscapture) { - SDL_SetError("XAudio2: capture devices unsupported."); - return; - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { + if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { SDL_SetError("XAudio2: XAudio2Create() failed at detection."); return; } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { @@ -149,8 +146,8 @@ XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { char *str = WIN_StringToUTF8(details.DisplayName); if (str != NULL) { - addfn(str); - SDL_free(str); /* addfn() made a copy of the string. */ + SDL_AddAudioDevice(SDL_FALSE, str, (void *) ((size_t) i+1)); + SDL_free(str); /* SDL_AddAudioDevice made a copy of the string. */ } } } @@ -169,8 +166,8 @@ VoiceCBOnBufferEnd(THIS_ void *data) static void STDMETHODCALLTYPE VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error) { - /* !!! FIXME: attempt to recover, or mark device disconnected. */ - SDL_assert(0 && "write me!"); + SDL_AudioDevice *this = (SDL_AudioDevice *) data; + SDL_OpenedAudioDeviceDisconnected(this); } /* no-op callbacks... */ @@ -221,7 +218,7 @@ XAUDIO2_PlayDevice(_THIS) if (result != S_OK) { /* uhoh, panic! */ IXAudio2SourceVoice_FlushSourceBuffers(source); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -289,7 +286,7 @@ XAUDIO2_CloseDevice(_THIS) } static int -XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) +XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { HRESULT result = S_OK; WAVEFORMATEX waveformat; @@ -315,9 +312,17 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) static IXAudio2VoiceCallback callbacks = { &callbacks_vtable }; - if (iscapture) { - return SDL_SetError("XAudio2: capture devices unsupported."); - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { +#if defined(SDL_XAUDIO2_WIN8) + /* !!! FIXME: hook up hotplugging. */ +#else + if (handle != NULL) { /* specific device requested? */ + /* -1 because we increment the original value to avoid NULL. */ + const size_t val = ((size_t) handle) - 1; + devId = (UINT32) val; + } +#endif + + if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { return SDL_SetError("XAudio2: XAudio2Create() failed at open."); } @@ -332,37 +337,6 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) ixa2->SetDebugConfiguration(&debugConfig); */ -#if ! defined(__WINRT__) - if (devname != NULL) { - UINT32 devcount = 0; - UINT32 i = 0; - - if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed."); - } - for (i = 0; i < devcount; i++) { - XAUDIO2_DEVICE_DETAILS details; - if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { - char *str = WIN_StringToUTF8(details.DisplayName); - if (str != NULL) { - const int match = (SDL_strcmp(str, devname) == 0); - SDL_free(str); - if (match) { - devId = i; - break; - } - } - } - } - - if (i == devcount) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: Requested device not found."); - } - } -#endif - /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -529,6 +503,16 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = XAUDIO2_CloseDevice; impl->Deinitialize = XAUDIO2_Deinitialize; + /* !!! FIXME: We can apparently use a C++ interface on Windows 8 + * !!! FIXME: (Windows::Devices::Enumeration::DeviceInformation) for device + * !!! FIXME: detection, but it's not implemented here yet. + * !!! FIXME: see http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx + * !!! FIXME: for now, force the default device. + */ +#if defined(SDL_XAUDIO2_WIN8) || defined(__WINRT__) + impl->OnlyHasDefaultOutputDevice = 1; +#endif + return 1; /* this audio target is available. */ #endif } diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index a9089548b..e7f90bacd 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -32,6 +32,7 @@ #include "../../events/SDL_events_c.h" #include "../../video/android/SDL_androidkeyboard.h" +#include "../../video/android/SDL_androidmouse.h" #include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidvideo.h" #include "../../video/android/SDL_androidwindow.h" @@ -293,6 +294,14 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeTouch( Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p); } +/* Mouse */ +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse( + JNIEnv* env, jclass jcls, + jint button, jint action, jfloat x, jfloat y) +{ + Android_OnMouse(button, action, x, y); +} + /* Accelerometer */ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeAccel( JNIEnv* env, jclass jcls, @@ -548,12 +557,12 @@ int Android_JNI_SetupThread(void) * Audio support */ static jboolean audioBuffer16Bit = JNI_FALSE; -static jboolean audioBufferStereo = JNI_FALSE; static jobject audioBuffer = NULL; static void* audioBufferPinned = NULL; int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) { + jboolean audioBufferStereo; int audioBufferFrames; JNIEnv *env = Android_JNI_GetEnv(); @@ -1601,6 +1610,11 @@ const char * SDL_AndroidGetExternalStoragePath() return s_AndroidExternalFilesPath; } +jclass Android_JNI_GetActivityClass(void) +{ + return mActivityClass; +} + #endif /* __ANDROID__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 051958a49..d749bf101 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -78,6 +78,7 @@ int Android_JNI_GetTouchDeviceIds(int **ids); #include JNIEnv *Android_JNI_GetEnv(void); int Android_JNI_SetupThread(void); +jclass Android_JNI_GetActivityClass(void); /* Generic messages */ int Android_JNI_SendMessage(int command, int param); diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index 1a0729f26..6b84be2e9 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -462,6 +462,9 @@ SDL_IBus_Init(void) ibus_addr_file = SDL_strdup(addr_file); addr = IBus_ReadAddressFromFile(addr_file); + if (!addr) { + return SDL_FALSE; + } if (inotify_fd < 0) { inotify_fd = inotify_init(); diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index d00fd82a7..b1310bc3f 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -350,17 +350,19 @@ guess_device_class(struct udev_device *dev) devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ } else if (test_bit(BTN_TOUCH, bitmask_key)) { ; /* ID_INPUT_TOUCHSCREEN */ - } else if (test_bit(BTN_TRIGGER, bitmask_key) || - test_bit(BTN_A, bitmask_key) || - test_bit(BTN_1, bitmask_key) || - test_bit(ABS_RX, bitmask_abs) || - test_bit(ABS_RY, bitmask_abs) || - test_bit(ABS_RZ, bitmask_abs) || - test_bit(ABS_THROTTLE, bitmask_abs) || - test_bit(ABS_RUDDER, bitmask_abs) || - test_bit(ABS_WHEEL, bitmask_abs) || - test_bit(ABS_GAS, bitmask_abs) || - test_bit(ABS_BRAKE, bitmask_abs)) { + } + + if (test_bit(BTN_TRIGGER, bitmask_key) || + test_bit(BTN_A, bitmask_key) || + test_bit(BTN_1, bitmask_key) || + test_bit(ABS_RX, bitmask_abs) || + test_bit(ABS_RY, bitmask_abs) || + test_bit(ABS_RZ, bitmask_abs) || + test_bit(ABS_THROTTLE, bitmask_abs) || + test_bit(ABS_RUDDER, bitmask_abs) || + test_bit(ABS_WHEEL, bitmask_abs) || + test_bit(ABS_GAS, bitmask_abs) || + test_bit(ABS_BRAKE, bitmask_abs)) { devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */ } } diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h index df8760019..5f4ea8d28 100644 --- a/src/dynapi/SDL_dynapi.h +++ b/src/dynapi/SDL_dynapi.h @@ -49,7 +49,10 @@ #define SDL_DYNAMIC_API 0 #elif defined(__clang_analyzer__) #define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */ -#else /* everyone else. */ +#endif + +/* everyone else. This is where we turn on the API if nothing forced it off. */ +#ifndef SDL_DYNAMIC_API #define SDL_DYNAMIC_API 1 #endif diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8bcde6312..dcc6d4677 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -591,3 +591,4 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index c41cdc9f0..6408e3f89 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -623,3 +623,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX2,(void),(),return) SDL_DYNAPI_PROC(int,SDL_QueueAudio,(SDL_AudioDeviceID a, const void *b, Uint32 c),(a,b,c),return) SDL_DYNAPI_PROC(Uint32,SDL_GetQueuedAudioSize,(SDL_AudioDeviceID a),(a),return) SDL_DYNAPI_PROC(void,SDL_ClearQueuedAudio,(SDL_AudioDeviceID a),(a),) +SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 963b9bd7c..cfbdcf89a 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -75,12 +75,13 @@ static struct SDL_mutex *lock; volatile SDL_bool active; volatile int count; + volatile int max_events_seen; SDL_EventEntry *head; SDL_EventEntry *tail; SDL_EventEntry *free; SDL_SysWMEntry *wmmsg_used; SDL_SysWMEntry *wmmsg_free; -} SDL_EventQ = { NULL, SDL_TRUE }; +} SDL_EventQ = { NULL, SDL_TRUE, 0, 0, NULL, NULL, NULL, NULL, NULL }; /* Public functions */ @@ -88,6 +89,7 @@ static struct void SDL_StopEventLoop(void) { + const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS"); int i; SDL_EventEntry *entry; SDL_SysWMEntry *wmmsg; @@ -98,6 +100,11 @@ SDL_StopEventLoop(void) SDL_EventQ.active = SDL_FALSE; + if (report && SDL_atoi(report)) { + SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n", + SDL_EventQ.max_events_seen); + } + /* Clean out EventQ */ for (entry = SDL_EventQ.head; entry; ) { SDL_EventEntry *next = entry->next; @@ -119,7 +126,9 @@ SDL_StopEventLoop(void) SDL_free(wmmsg); wmmsg = next; } + SDL_EventQ.count = 0; + SDL_EventQ.max_events_seen = 0; SDL_EventQ.head = NULL; SDL_EventQ.tail = NULL; SDL_EventQ.free = NULL; @@ -218,6 +227,10 @@ SDL_AddEvent(SDL_Event * event) } ++SDL_EventQ.count; + if (SDL_EventQ.count > SDL_EventQ.max_events_seen) { + SDL_EventQ.max_events_seen = SDL_EventQ.count; + } + return 1; } diff --git a/src/events/SDL_gesture.c b/src/events/SDL_gesture.c index 46a554635..746d11630 100644 --- a/src/events/SDL_gesture.c +++ b/src/events/SDL_gesture.c @@ -24,6 +24,7 @@ /* General mouse handling code for SDL */ #include "SDL_events.h" +#include "SDL_endian.h" #include "SDL_events_c.h" #include "SDL_gesture_c.h" @@ -114,14 +115,34 @@ static unsigned long SDL_HashDollar(SDL_FloatPoint* points) static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops *dst) { - if (dst == NULL) return 0; + if (dst == NULL) { + return 0; + } /* No Longer storing the Hash, rehash on load */ /* if (SDL_RWops.write(dst, &(templ->hash), sizeof(templ->hash), 1) != 1) return 0; */ +#if SDL_BYTEORDER == SDL_LIL_ENDIAN if (SDL_RWwrite(dst, templ->path, - sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) + sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) { return 0; + } +#else + { + SDL_DollarTemplate copy = *templ; + SDL_FloatPoint *p = copy.path; + int i; + for (i = 0; i < DOLLARNPOINTS; i++, p++) { + p->x = SDL_SwapFloatLE(p->x); + p->y = SDL_SwapFloatLE(p->y); + } + + if (SDL_RWwrite(dst, copy.path, + sizeof(copy.path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) { + return 0; + } + } +#endif return 1; } @@ -184,7 +205,7 @@ static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path) int index = -1; int i = 0; if (inTouch == NULL) { - if (SDL_numGestureTouches == 0) return -1; + if (SDL_numGestureTouches == 0) return SDL_SetError("no gesture touch devices registered"); for (i = 0; i < SDL_numGestureTouches; i++) { inTouch = &SDL_gestureTouch[i]; index = SDL_AddDollarGesture_one(inTouch, path); @@ -203,17 +224,33 @@ int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) SDL_GestureTouch *touch = NULL; if (src == NULL) return 0; if (touchId >= 0) { - for (i = 0; i < SDL_numGestureTouches; i++) - if (SDL_gestureTouch[i].id == touchId) + for (i = 0; i < SDL_numGestureTouches; i++) { + if (SDL_gestureTouch[i].id == touchId) { touch = &SDL_gestureTouch[i]; - if (touch == NULL) return -1; + } + } + if (touch == NULL) { + return SDL_SetError("given touch id not found"); + } } while (1) { SDL_DollarTemplate templ; - if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < - DOLLARNPOINTS) break; + if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < DOLLARNPOINTS) { + if (loaded == 0) { + return SDL_SetError("could not read any dollar gesture from rwops"); + } + break; + } + +#if SDL_BYTEORDER != SDL_LIL_ENDIAN + for (i = 0; i < DOLLARNPOINTS; i++) { + SDL_FloatPoint *p = &templ.path[i]; + p->x = SDL_SwapFloatLE(p->x); + p->y = SDL_SwapFloatLE(p->y); + } +#endif if (touchId >= 0) { /* printf("Adding loaded gesture to 1 touch\n"); */ diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 32eb0f902..326bbbadc 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -293,9 +293,14 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ event.motion.yrel = yrel; posted = (SDL_PushEvent(&event) > 0); } - /* Use unclamped values if we're getting events outside the window */ - mouse->last_x = x; - mouse->last_y = y; + if (relative) { + mouse->last_x = mouse->x; + mouse->last_y = mouse->y; + } else { + /* Use unclamped values if we're getting events outside the window */ + mouse->last_x = x; + mouse->last_y = y; + } return posted; } @@ -303,10 +308,11 @@ static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button) { if (button >= mouse->num_clickstates) { int i, count = button + 1; - mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); - if (!mouse->clickstate) { + SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); + if (!clickstate) { return NULL; } + mouse->clickstate = clickstate; for (i = mouse->num_clickstates; i < count; ++i) { SDL_zero(mouse->clickstate[i]); diff --git a/src/events/SDL_quit.c b/src/events/SDL_quit.c index db7af98fa..c80812202 100644 --- a/src/events/SDL_quit.c +++ b/src/events/SDL_quit.c @@ -19,6 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../SDL_internal.h" +#include "SDL_hints.h" /* General quit handling code for SDL */ @@ -30,6 +31,8 @@ #include "SDL_events_c.h" +static SDL_bool disable_signals = SDL_FALSE; + #ifdef HAVE_SIGNAL_H static void SDL_HandleSIG(int sig) @@ -43,8 +46,8 @@ SDL_HandleSIG(int sig) #endif /* HAVE_SIGNAL_H */ /* Public functions */ -int -SDL_QuitInit(void) +static int +SDL_QuitInit_Internal(void) { #ifdef HAVE_SIGACTION struct sigaction action; @@ -80,11 +83,22 @@ SDL_QuitInit(void) #endif /* HAVE_SIGNAL_H */ /* That's it! */ - return (0); + return 0; } -void -SDL_QuitQuit(void) +int +SDL_QuitInit(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_NO_SIGNAL_HANDLERS); + disable_signals = hint && (SDL_atoi(hint) == 1); + if (!disable_signals) { + return SDL_QuitInit_Internal(); + } + return 0; +} + +static void +SDL_QuitQuit_Internal(void) { #ifdef HAVE_SIGACTION struct sigaction action; @@ -110,6 +124,14 @@ SDL_QuitQuit(void) #endif /* HAVE_SIGNAL_H */ } +void +SDL_QuitQuit(void) +{ + if (!disable_signals) { + SDL_QuitQuit_Internal(); + } +} + /* This function returns 1 if it's okay to close the application window */ int SDL_SendQuit(void) diff --git a/src/filesystem/nacl/SDL_sysfilesystem.c b/src/filesystem/nacl/SDL_sysfilesystem.c index ff55b2ba9..0111683a2 100644 --- a/src/filesystem/nacl/SDL_sysfilesystem.c +++ b/src/filesystem/nacl/SDL_sysfilesystem.c @@ -38,4 +38,5 @@ SDL_GetPrefPath(const char *org, const char *app) return NULL; } -#endif /* __NACL__ */ \ No newline at end of file +#endif /* SDL_FILESYSTEM_NACL */ + diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c index 63c81ab9b..fba536b48 100644 --- a/src/haptic/linux/SDL_syshaptic.c +++ b/src/haptic/linux/SDL_syshaptic.c @@ -288,8 +288,7 @@ MaybeAddDevice(const char *path) } item->fname = SDL_strdup(path); - if ( (item->fname == NULL) ) { - SDL_free(item->fname); + if (item->fname == NULL) { SDL_free(item); return -1; } diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index d151e95ef..4906262a1 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -63,6 +63,8 @@ static const char *s_ControllerMappings [] = "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", "050000003620000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", "030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", @@ -73,12 +75,13 @@ static const char *s_ControllerMappings [] = "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e040000d102000001010000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", #endif #if defined(__ANDROID__) "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", #endif #if defined(SDL_JOYSTICK_EMSCRIPTEN) - "emscripten,Standard Gamepad,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,lefttrigger:b6,righttrigger:b7,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftx:a0,lefty:a1,rightx:a2,righty:a3,", + "emscripten,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", #endif NULL }; diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 2a60c0036..44cc21677 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -206,10 +206,6 @@ SDL_PrivateJoystickValid(SDL_Joystick * joystick) valid = 1; } - if (joystick && joystick->closed) { - valid = 0; - } - return valid; } @@ -412,6 +408,7 @@ SDL_JoystickClose(SDL_Joystick * joystick) } SDL_SYS_JoystickClose(joystick); + joystick->hwdata = NULL; joysticklist = SDL_joysticks; joysticklistprev = NULL; @@ -668,7 +665,7 @@ SDL_JoystickUpdate(void) SDL_SYS_JoystickUpdate(joystick); - if (joystick->closed && joystick->uncentered) { + if (joystick->force_recentering) { int i; /* Tell the app that everything is centered/unpressed... */ @@ -681,7 +678,7 @@ SDL_JoystickUpdate(void) for (i = 0; i < joystick->nhats; i++) SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); - joystick->uncentered = SDL_FALSE; + joystick->force_recentering = SDL_FALSE; } SDL_updating_joystick = NULL; diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index a39869575..f126e7519 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -53,8 +53,7 @@ struct _SDL_Joystick int ref_count; /* Reference count for multiple opens */ - SDL_bool closed; /* SDL_TRUE if this device is no longer valid */ - SDL_bool uncentered; /* SDL_TRUE if this device needs to have its state reset to 0 */ + SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */ struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */ }; @@ -78,14 +77,14 @@ extern const char *SDL_SYS_JoystickNameForDeviceIndex(int device_index); extern SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index); /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ extern int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index); /* Function to query if the joystick is currently attached - * It returns 1 if attached, 0 otherwise. + * It returns SDL_TRUE if attached, SDL_FALSE otherwise. */ extern SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick); diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index cce94b80c..3d82fcb5b 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -467,7 +467,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -498,7 +498,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) /* Function to determine is this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return !joystick->closed && (joystick->hwdata != NULL); + return joystick->hwdata != NULL; } void @@ -529,11 +529,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - if (joystick->hwdata) { - ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL; - joystick->hwdata = NULL; - } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/android/SDL_sysjoystick_c.h b/src/joystick/android/SDL_sysjoystick_c.h index 3d56b0b99..6ad6aa7a5 100644 --- a/src/joystick/android/SDL_sysjoystick_c.h +++ b/src/joystick/android/SDL_sysjoystick_c.h @@ -19,7 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include "SDL_config.h" +#include "../../SDL_internal.h" #ifdef SDL_JOYSTICK_ANDROID #include "../SDL_sysjoystick.h" diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c index 65a32ed2e..efbd79c59 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -558,8 +558,6 @@ SDL_SYS_JoystickClose(SDL_Joystick * joy) close(joy->hwdata->fd); SDL_free(joy->hwdata->path); SDL_free(joy->hwdata); - - return; } void diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 0518cc75b..fc7ae7554 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -138,7 +138,7 @@ static void JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender) { recDevice *device = (recDevice *) ctx; - device->removed = 1; + device->removed = SDL_TRUE; device->deviceRef = NULL; // deviceRef was invalidated due to the remove #if SDL_HAPTIC_IOKIT MacHaptic_MaybeRemoveDevice(device->ffservice); @@ -412,12 +412,12 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */ const io_service_t ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); +#if SDL_HAPTIC_IOKIT if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { device->ffservice = ioservice; -#if SDL_HAPTIC_IOKIT MacHaptic_MaybeAddDevice(ioservice); -#endif } +#endif } device->send_open_event = 1; @@ -446,9 +446,9 @@ ConfigHIDManager(CFArrayRef matchingArray) return SDL_FALSE; } + IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray); IOHIDManagerRegisterDeviceMatchingCallback(hidman, JoystickDeviceWasAddedCallback, NULL); IOHIDManagerScheduleWithRunLoop(hidman, runloop, SDL_JOYSTICK_RUNLOOP_MODE); - IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray); while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { /* no-op. Callback fires once per existing device. */ @@ -560,10 +560,6 @@ SDL_SYS_NumJoysticks() void SDL_SYS_JoystickDetect() { - while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { - /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */ - } - if (s_bDeviceAdded || s_bDeviceRemoved) { recDevice *device = gpDeviceList; s_bDeviceAdded = SDL_FALSE; @@ -613,6 +609,12 @@ SDL_SYS_JoystickDetect() } } } + + // run this after the checks above so we don't set device->removed and delete the device before + // SDL_SYS_JoystickUpdate can run to clean up the SDL_Joystick object that owns this device + while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { + /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */ + } } /* Function to get the device-dependent name of a joystick */ @@ -644,7 +646,7 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - * The joystick to open is specified by the index field of the joystick. + * The joystick to open is specified by the device index. * This should fill the nbuttons and naxes fields of the joystick structure. * It returns 0, or -1 if there is an error. */ @@ -670,21 +672,12 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) } /* Function to query if the joystick is currently attached - * It returns 1 if attached, 0 otherwise. + * It returns SDL_TRUE if attached, SDL_FALSE otherwise. */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick) { - recDevice *device = gpDeviceList; - - while (device) { - if (joystick->instance_id == device->instance_id) { - return SDL_TRUE; - } - device = device->pNext; - } - - return SDL_FALSE; + return joystick->hwdata != NULL; } /* Function to update the state of a joystick - called as a device poll. @@ -705,9 +698,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) } if (device->removed) { /* device was unplugged; ignore it. */ - joystick->closed = 1; - joystick->uncentered = 1; - joystick->hwdata = NULL; + if (joystick->hwdata) { + joystick->force_recentering = SDL_TRUE; + joystick->hwdata = NULL; + } return; } @@ -795,7 +789,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/darwin/SDL_sysjoystick_c.h b/src/joystick/darwin/SDL_sysjoystick_c.h index 0a15ba18d..4c3300dca 100644 --- a/src/joystick/darwin/SDL_sysjoystick_c.h +++ b/src/joystick/darwin/SDL_sysjoystick_c.h @@ -58,8 +58,7 @@ struct joystick_hwdata recElement *firstButton; recElement *firstHat; - int removed; - int uncentered; + SDL_bool removed; int instance_id; SDL_JoystickGUID guid; diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c index 9baa79500..a046e0e5f 100644 --- a/src/joystick/dummy/SDL_sysjoystick.c +++ b/src/joystick/dummy/SDL_sysjoystick.c @@ -34,7 +34,7 @@ int SDL_SYS_JoystickInit(void) { - return (0); + return 0; } int SDL_SYS_NumJoysticks() @@ -61,7 +61,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -85,21 +85,18 @@ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { - return; } /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - return; } /* Function to perform any system-specific joystick related cleanup */ void SDL_SYS_JoystickQuit(void) { - return; } SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 62283c9f6..a1e9c1552 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -46,7 +46,7 @@ static SDL_joylist_item *SDL_joylist_tail = NULL; static int numjoysticks = 0; static int instance_counter = 0; -int +EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { int i; @@ -105,12 +105,14 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa } ++numjoysticks; - SDL_Log("%d",numjoysticks); +#ifdef DEBUG_JOYSTICK + SDL_Log("Number of joysticks is %d", numjoysticks); +#endif #if !SDL_EVENTS_DISABLED event.type = SDL_JOYDEVICEADDED; if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = item->device_instance - 1; + event.jdevice.which = numjoysticks - 1; if ( (SDL_EventOK == NULL) || (*SDL_EventOK) (SDL_EventOKParam, &event) ) { SDL_PushEvent(&event); @@ -118,12 +120,14 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa } #endif /* !SDL_EVENTS_DISABLED */ +#ifdef DEBUG_JOYSTICK SDL_Log("Added joystick with index %d", item->index); +#endif return 1; } -int +EM_BOOL Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { SDL_joylist_item *item = SDL_joylist; @@ -144,7 +148,6 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam return 1; } - const int retval = item->device_instance; if (item->joystick) { item->joystick->hwdata = NULL; } @@ -174,7 +177,9 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam } #endif /* !SDL_EVENTS_DISABLED */ - SDL_Log("Removed joystick with index %d", retval); +#ifdef DEBUG_JOYSTICK + SDL_Log("Removed joystick with id %d", item->device_instance); +#endif SDL_free(item->name); SDL_free(item->mapping); SDL_free(item); @@ -215,6 +220,7 @@ SDL_SYS_JoystickInit(void) Emscripten_JoyStickConnected); if(retval != EMSCRIPTEN_RESULT_SUCCESS) { + SDL_SYS_JoystickQuit(); return -1; } @@ -222,12 +228,28 @@ SDL_SYS_JoystickInit(void) 0, Emscripten_JoyStickDisconnected); if(retval != EMSCRIPTEN_RESULT_SUCCESS) { + SDL_SYS_JoystickQuit(); return -1; } return 0; } +/* Returns item matching given SDL device index. */ +static SDL_joylist_item * +JoystickByDeviceIndex(int device_index) +{ + SDL_joylist_item *item = SDL_joylist; + + while (0 < device_index) { + --device_index; + item = item->next; + } + + return item; +} + +/* Returns item matching given HTML gamepad index. */ static SDL_joylist_item * JoystickByIndex(int index) { @@ -256,46 +278,28 @@ void SDL_SYS_JoystickDetect() { } -// we need to poll to see if the gamepad state has changed -SDL_bool SDL_SYS_JoystickNeedsPolling() -{ - return SDL_TRUE; -} - /* Function to get the device-dependent name of a joystick */ const char * -SDL_SYS_JoystickNameForDeviceIndex(int index) +SDL_SYS_JoystickNameForDeviceIndex(int device_index) { - SDL_joylist_item *item = JoystickByIndex(index); - if (item == NULL) { - SDL_SetError("Joystick with index %d not found", index); - return NULL; - } - - return item->name; + return JoystickByDeviceIndex(device_index)->name; } /* Function to perform the mapping from device index to the instance id for this index */ -SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int index) +SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) { - SDL_joylist_item *item = JoystickByIndex(index); - if (item == NULL) { - SDL_SetError("Joystick with index %d not found", index); - return 0; - } - - return item->device_instance; + return JoystickByDeviceIndex(device_index)->device_instance; } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ int -SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int index) +SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) { - SDL_joylist_item *item = JoystickByIndex(index); + SDL_joylist_item *item = JoystickByDeviceIndex(device_index); if (item == NULL ) { return SDL_SetError("No such device"); @@ -322,7 +326,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int index) /* Function to determine is this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return !joystick->closed && (joystick->hwdata != NULL); + return joystick->hwdata != NULL; } /* Function to update the state of a joystick - called as a device poll. @@ -334,10 +338,10 @@ void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { EmscriptenGamepadEvent gamepadState; - SDL_joylist_item *item = SDL_joylist; + SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; int i, result, buttonState; - while (item != NULL) { + if (item) { result = emscripten_get_gamepad_status(item->index, &gamepadState); if( result == EMSCRIPTEN_RESULT_SUCCESS) { if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) { @@ -367,7 +371,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) } } } - item = item->next; } } @@ -375,11 +378,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - if (joystick->hwdata) { - ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL; - joystick->hwdata = NULL; - } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ @@ -400,20 +398,24 @@ SDL_SYS_JoystickQuit(void) numjoysticks = 0; instance_counter = 0; + + emscripten_set_gamepadconnected_callback(NULL, 0, NULL); + emscripten_set_gamepaddisconnected_callback(NULL, 0, NULL); } -SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int index) +SDL_JoystickGUID +SDL_SYS_JoystickGetDeviceGUID(int device_index) { SDL_JoystickGUID guid; /* the GUID is just the first 16 chars of the name for now */ - const char *name = SDL_SYS_JoystickNameForDeviceIndex(index); + const char *name = SDL_SYS_JoystickNameForDeviceIndex(device_index); SDL_zero(guid); SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name))); return guid; } - -SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) +SDL_JoystickGUID +SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) { SDL_JoystickGUID guid; /* the GUID is just the first 16 chars of the name for now */ diff --git a/src/joystick/emscripten/SDL_sysjoystick_c.h b/src/joystick/emscripten/SDL_sysjoystick_c.h index 375ea0ef8..4c907a66c 100644 --- a/src/joystick/emscripten/SDL_sysjoystick_c.h +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -19,7 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include "SDL_config.h" +#include "../../SDL_internal.h" #ifdef SDL_JOYSTICK_EMSCRIPTEN #include "../SDL_sysjoystick.h" diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc index 22c046aad..c9b7e114a 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -106,7 +106,7 @@ extern "C" } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -228,7 +228,6 @@ extern "C" SDL_free(joystick->hwdata->new_hats); SDL_free(joystick->hwdata->new_axes); SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } } diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index a4e18840c..25bdfbbf3 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -77,7 +77,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -167,7 +167,6 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) @autoreleasepool { [motionManager stopAccelerometerUpdates]; } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 05bf086f2..7dd33efd0 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -142,13 +142,15 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui #if SDL_USE_LIBUDEV void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) { - if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { + if (devpath == NULL) { return; } - - switch( udev_type ) - { + + switch (udev_type) { case SDL_UDEV_DEVICEADDED: + if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { + return; + } MaybeAddDevice(devpath); break; @@ -335,13 +337,12 @@ JoystickInitWithoutUdev(void) static int JoystickInitWithUdev(void) { - if (SDL_UDEV_Init() < 0) { return SDL_SetError("Could not initialize UDEV"); } /* Set up the udev callback */ - if ( SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { + if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { SDL_UDEV_Quit(); return SDL_SetError("Could not set up joystick <-> udev callback"); } @@ -565,7 +566,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -623,7 +624,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) /* Function to determine is this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return !joystick->closed && (joystick->hwdata->item != NULL); + return joystick->hwdata->item != NULL; } static SDL_INLINE void @@ -840,9 +841,7 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) SDL_free(joystick->hwdata->balls); SDL_free(joystick->hwdata->fname); SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/psp/SDL_sysjoystick.c b/src/joystick/psp/SDL_sysjoystick.c index f848d1cee..41f9358fc 100644 --- a/src/joystick/psp/SDL_sysjoystick.c +++ b/src/joystick/psp/SDL_sysjoystick.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_JOYSTICK_PSP /* This is the PSP implementation of the SDL joystick API */ #include @@ -161,7 +164,7 @@ const char *SDL_SYS_JoystickName(int index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -179,12 +182,12 @@ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; } + /* Function to update the state of a joystick - called as a device poll. * This function shouldn't update the joystick structure directly, * but instead should call SDL_PrivateJoystick*() to deliver events * and update joystick device state. */ - void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) { int i; @@ -230,7 +233,6 @@ void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick *joystick) { - /* Do nothing. */ } /* Function to perform any system-specific joystick related cleanup */ @@ -262,5 +264,7 @@ SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) return guid; } +#endif /* SDL_JOYSTICK_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/joystick/windows/SDL_mmjoystick.c b/src/joystick/windows/SDL_mmjoystick.c index 0ae344246..6c02597a9 100644 --- a/src/joystick/windows/SDL_mmjoystick.c +++ b/src/joystick/windows/SDL_mmjoystick.c @@ -210,7 +210,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -383,9 +383,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - /* free system specific hardware data */ SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index 0b2f370b5..5682a223f 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -446,7 +446,7 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -460,7 +460,6 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) /* allocate memory for system specific hardware data */ joystick->instance_id = joystickdevice->nInstanceID; - joystick->closed = SDL_FALSE; joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata)); if (joystick->hwdata == NULL) { @@ -480,13 +479,13 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick) { - return !joystick->closed && !joystick->hwdata->removed; + return joystick->hwdata && !joystick->hwdata->removed; } void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { - if (joystick->closed || !joystick->hwdata) { + if (!joystick->hwdata || joystick->hwdata->removed) { return; } @@ -497,8 +496,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) } if (joystick->hwdata->removed) { - joystick->closed = SDL_TRUE; - joystick->uncentered = SDL_TRUE; + joystick->force_recentering = SDL_TRUE; } } @@ -512,10 +510,7 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) SDL_DINPUT_JoystickClose(joystick); } - /* free system specific hardware data */ SDL_free(joystick->hwdata); - - joystick->closed = SDL_TRUE; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/main/psp/SDL_psp_main.c b/src/main/psp/SDL_psp_main.c index d79135dbc..2ca8e446b 100644 --- a/src/main/psp/SDL_psp_main.c +++ b/src/main/psp/SDL_psp_main.c @@ -1,6 +1,9 @@ /* SDL_psp_main.c, placed in the public domain by Sam Lantinga 3/13/14 */ +#include "SDL_config.h" + +#ifdef __PSP__ #include "SDL_main.h" #include @@ -61,3 +64,7 @@ int main(int argc, char *argv[]) (void)SDL_main(argc, argv); return 0; } + +#endif /* __PSP__ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/main/windows/SDL_windows_main.c b/src/main/windows/SDL_windows_main.c index 7886fe3a8..e6378081f 100644 --- a/src/main/windows/SDL_windows_main.c +++ b/src/main/windows/SDL_windows_main.c @@ -109,13 +109,16 @@ OutOfMemory(void) } #if defined(_MSC_VER) -/* The VC++ compiler needs main defined */ -#define console_main main +/* The VC++ compiler needs main/wmain defined */ +# define console_ansi_main main +# if UNICODE +# define console_wmain wmain +# endif #endif -/* This is where execution begins [console apps] */ -int -console_main(int argc, char *argv[]) +/* WinMain, main, and wmain eventually call into here. */ +static int +main_utf8(int argc, char *argv[]) { SDL_SetMainReady(); @@ -123,6 +126,37 @@ console_main(int argc, char *argv[]) return SDL_main(argc, argv); } +/* This is where execution begins [console apps, ansi] */ +int +console_ansi_main(int argc, char *argv[]) +{ + /* !!! FIXME: are these in the system codepage? We need to convert to UTF-8. */ + return main_utf8(argc, argv); +} + + +#if UNICODE +/* This is where execution begins [console apps, unicode] */ +int +console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) +{ + int retval = 0; + char **argv = SDL_stack_alloc(char*, argc); + int i; + + for (i = 0; i < argc; ++i) { + argv[i] = WIN_StringToUTF8(wargv[i]); + } + + retval = main_utf8(argc, argv); + + /* !!! FIXME: we are leaking all the elements of argv we allocated. */ + SDL_stack_free(argv); + + return retval; +} +#endif + /* This is where execution begins [windowed apps] */ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) @@ -136,6 +170,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) #if UNICODE cmdline = WIN_StringToUTF8(text); #else + /* !!! FIXME: are these in the system codepage? We need to convert to UTF-8. */ cmdline = SDL_strdup(text); #endif if (cmdline == NULL) { @@ -151,7 +186,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) ParseCommandLine(cmdline, argv); /* Run the main program */ - console_main(argc, argv); + main_utf8(argc, argv); SDL_stack_free(argv); diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index f99fdb1d5..c8a487a6b 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -829,9 +829,24 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); renderer->driverdata = data; +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1. + * Failure to use it seems to either result in: + * + * - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned + * off (framerate doesn't get capped), but nothing appears on-screen + * + * - with the D3D11 debug runtime turned ON, vsync gets automatically + * turned back on, and the following gets output to the debug console: + * + * DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ] + */ + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; +#else if ((flags & SDL_RENDERER_PRESENTVSYNC)) { renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; } +#endif /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in * order to give init functions access to the underlying window handle: diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index ecd0d531f..0c930f35d 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -342,9 +342,11 @@ GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GL if (type == GL_DEBUG_TYPE_ERROR_ARB) { /* Record this error */ - ++data->errors; - data->error_messages = SDL_realloc(data->error_messages, data->errors * sizeof(*data->error_messages)); - if (data->error_messages) { + int errors = data->errors + 1; + char **error_messages = SDL_realloc(data->error_messages, errors * sizeof(*data->error_messages)); + if (error_messages) { + data->errors = errors; + data->error_messages = error_messages; data->error_messages[data->errors-1] = SDL_strdup(message); } } diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 4022d20df..9b1d2914c 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1204,10 +1204,10 @@ SDLTest_PrintEvent(SDL_Event * event) event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure); break; case SDL_DOLLARGESTURE: - SDL_Log("SDL_EVENT: Dollar gesture detect: %"SDL_PRIs64, (long long) event->dgesture.gestureId); + SDL_Log("SDL_EVENT: Dollar gesture detect: %"SDL_PRIs64, (Sint64) event->dgesture.gestureId); break; case SDL_DOLLARRECORD: - SDL_Log("SDL_EVENT: Dollar gesture record: %"SDL_PRIs64, (long long) event->dgesture.gestureId); + SDL_Log("SDL_EVENT: Dollar gesture record: %"SDL_PRIs64, (Sint64) event->dgesture.gestureId); break; case SDL_MULTIGESTURE: SDL_Log("SDL_EVENT: Multi gesture fingers: %d", event->mgesture.numFingers); diff --git a/src/thread/psp/SDL_syscond.c b/src/thread/psp/SDL_syscond.c index 1abd9a3d9..3959a4c43 100644 --- a/src/thread/psp/SDL_syscond.c +++ b/src/thread/psp/SDL_syscond.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_THREAD_PSP + /* An implementation of condition variables using semaphores and mutexes */ /* This implementation borrows heavily from the BeOS condition variable @@ -217,4 +219,6 @@ SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); } +#endif /* SDL_THREAD_PSP */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/psp/SDL_sysmutex.c b/src/thread/psp/SDL_sysmutex.c index 478575b32..e1cf413c3 100644 --- a/src/thread/psp/SDL_sysmutex.c +++ b/src/thread/psp/SDL_sysmutex.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_THREAD_PSP + /* An implementation of mutexes using semaphores */ #include "SDL_thread.h" @@ -129,4 +131,6 @@ SDL_mutexV(SDL_mutex * mutex) #endif /* SDL_THREADS_DISABLED */ } +#endif /* SDL_THREAD_PSP */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/psp/SDL_syssem.c b/src/thread/psp/SDL_syssem.c index 27d3251a2..609ba7375 100644 --- a/src/thread/psp/SDL_syssem.c +++ b/src/thread/psp/SDL_syssem.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_THREAD_PSP /* Semaphore functions for the PSP. */ @@ -152,5 +155,7 @@ int SDL_SemPost(SDL_sem *sem) return 0; } +#endif /* SDL_THREAD_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/thread/psp/SDL_systhread.c b/src/thread/psp/SDL_systhread.c index d2fbeeb2f..8cbd2f132 100644 --- a/src/thread/psp/SDL_systhread.c +++ b/src/thread/psp/SDL_systhread.c @@ -18,7 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" +#if SDL_THREAD_PSP /* PSP thread management routines for SDL */ @@ -104,5 +106,7 @@ int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) } +#endif /* SDL_THREAD_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/timer/psp/SDL_systimer.c b/src/timer/psp/SDL_systimer.c index b706f4495..8488b284d 100644 --- a/src/timer/psp/SDL_systimer.c +++ b/src/timer/psp/SDL_systimer.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#ifdef SDL_TIMERS_PSP #include "SDL_thread.h" #include "SDL_timer.h" @@ -82,5 +85,7 @@ void SDL_Delay(Uint32 ms) sceKernelDelayThreadCB(ms * 1000); } +#endif /* SDL_TIMERS_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/video/SDL_bmp.c b/src/video/SDL_bmp.c index fcc48c6d5..f2b19fabd 100644 --- a/src/video/SDL_bmp.c +++ b/src/video/SDL_bmp.c @@ -306,16 +306,19 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) biClrUsed = 1 << biBitCount; } if ((int) biClrUsed > palette->ncolors) { - palette->ncolors = biClrUsed; - palette->colors = + SDL_Color *colors; + int ncolors = biClrUsed; + colors = (SDL_Color *) SDL_realloc(palette->colors, - palette->ncolors * + ncolors * sizeof(*palette->colors)); - if (!palette->colors) { + if (!colors) { SDL_OutOfMemory(); was_error = SDL_TRUE; goto done; } + palette->ncolors = ncolors; + palette->colors = colors; } else if ((int) biClrUsed < palette->ncolors) { palette->ncolors = biClrUsed; } diff --git a/src/video/SDL_clipboard.c b/src/video/SDL_clipboard.c index a3b38e045..f2b450152 100644 --- a/src/video/SDL_clipboard.c +++ b/src/video/SDL_clipboard.c @@ -29,6 +29,10 @@ SDL_SetClipboardText(const char *text) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + return SDL_SetError("Video subsystem must be initialized to set clipboard text"); + } + if (!text) { text = ""; } @@ -46,6 +50,11 @@ SDL_GetClipboardText(void) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + SDL_SetError("Video subsystem must be initialized to get clipboard text"); + return SDL_strdup(""); + } + if (_this->GetClipboardText) { return _this->GetClipboardText(_this); } else { @@ -62,6 +71,11 @@ SDL_HasClipboardText(void) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + SDL_SetError("Video subsystem must be initialized to check clipboard text"); + return SDL_FALSE; + } + if (_this->HasClipboardText) { return _this->HasClipboardText(_this); } else { diff --git a/src/video/SDL_fillrect.c b/src/video/SDL_fillrect.c index 5f343eaf2..84707842e 100644 --- a/src/video/SDL_fillrect.c +++ b/src/video/SDL_fillrect.c @@ -251,6 +251,10 @@ SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color) rect = &clipped; } else { rect = &dst->clip_rect; + /* Don't attempt to fill if the surface's clip_rect is empty */ + if (SDL_RectEmpty(rect)) { + return 0; + } } /* Perform software fill */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 2f0725550..9b2f7d170 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -274,6 +274,7 @@ struct SDL_VideoDevice int num_displays; SDL_VideoDisplay *displays; SDL_Window *windows; + SDL_Window *grabbed_window; Uint8 window_magic; Uint32 next_object_id; char * clipboard_text; @@ -303,6 +304,7 @@ struct SDL_VideoDevice int flags; int profile_mask; int share_with_current_context; + int release_behavior; int framebuffer_srgb_capable; int retained_backing; int driver_loaded; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 7b4a4c1b3..81d6254b3 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -46,6 +46,10 @@ #include "SDL_opengles2.h" #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ +#ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR +#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB +#endif + /* On Windows, windows.h defines CreateWindow */ #ifdef CreateWindow #undef CreateWindow @@ -1612,13 +1616,14 @@ SDL_SetWindowPosition(SDL_Window * window, int x, int y) CHECK_WINDOW_MAGIC(window,); if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - int displayIndex; + int displayIndex = (x & 0xFFFF); SDL_Rect bounds; + if (displayIndex > _this->num_displays) { + displayIndex = 0; + } SDL_zero(bounds); - displayIndex = SDL_GetIndexOfDisplay(display); SDL_GetDisplayBounds(displayIndex, &bounds); if (SDL_WINDOWPOS_ISCENTERED(x)) { x = bounds.x + (bounds.w - window->w) / 2; @@ -2114,6 +2119,7 @@ void SDL_UpdateWindowGrab(SDL_Window * window) { if (_this->SetWindowGrab) { + SDL_Window *grabbed_window; SDL_bool grabbed; if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { @@ -2121,6 +2127,19 @@ SDL_UpdateWindowGrab(SDL_Window * window) } else { grabbed = SDL_FALSE; } + + grabbed_window = _this->grabbed_window; + if (grabbed) { + if (grabbed_window && (grabbed_window != window)) { + /* stealing a grab from another window! */ + grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED; + _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE); + } + _this->grabbed_window = window; + } else if (grabbed_window == window) { + _this->grabbed_window = NULL; /* ungrabbing. */ + } + _this->SetWindowGrab(_this, window, grabbed); } } @@ -2145,8 +2164,15 @@ SDL_bool SDL_GetWindowGrab(SDL_Window * window) { CHECK_WINDOW_MAGIC(window, SDL_FALSE); + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return window == _this->grabbed_window; +} - return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0); +SDL_Window * +SDL_GetGrabbedWindow(void) +{ + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return _this->grabbed_window; } void @@ -2639,6 +2665,7 @@ SDL_GL_ResetAttributes() #endif _this->gl_config.flags = 0; _this->gl_config.framebuffer_srgb_capable = 0; + _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH; _this->gl_config.share_with_current_context = 0; } @@ -2745,6 +2772,9 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value) case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: _this->gl_config.framebuffer_srgb_capable = value; break; + case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: + _this->gl_config.release_behavior = value; + break; default: retval = SDL_SetError("Unknown OpenGL attribute"); break; @@ -2845,6 +2875,13 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) attrib = GL_SAMPLES_ARB; #else attrib = GL_SAMPLES; +#endif + break; + case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: +#if SDL_VIDEO_OPENGL + attrib = GL_CONTEXT_RELEASE_BEHAVIOR; +#else + attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR; #endif break; case SDL_GL_BUFFER_SIZE: diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 2662d1b3d..ef7d55648 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -32,8 +32,14 @@ void android_egl_context_backup(); void android_egl_context_restore(); + +#if SDL_AUDIO_DRIVER_ANDROID void AndroidAUD_ResumeDevices(void); void AndroidAUD_PauseDevices(void); +#else +static void AndroidAUD_ResumeDevices(void) {} +static void AndroidAUD_PauseDevices(void) {} +#endif void android_egl_context_restore() diff --git a/src/video/android/SDL_androidmessagebox.c b/src/video/android/SDL_androidmessagebox.c index a55afb376..11f856999 100644 --- a/src/video/android/SDL_androidmessagebox.c +++ b/src/video/android/SDL_androidmessagebox.c @@ -18,7 +18,7 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "SDL_config.h" +#include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_ANDROID diff --git a/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c new file mode 100644 index 000000000..af828af1f --- /dev/null +++ b/src/video/android/SDL_androidmouse.c @@ -0,0 +1,84 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidmouse.h" + +#include "SDL_events.h" +#include "../../events/SDL_mouse_c.h" + +#include "../../core/android/SDL_android.h" + +#define ACTION_DOWN 0 +#define ACTION_UP 1 +#define ACTION_HOVER_MOVE 7 +#define ACTION_SCROLL 8 +#define BUTTON_PRIMARY 1 +#define BUTTON_SECONDARY 2 +#define BUTTON_TERTIARY 4 + +void Android_OnMouse( int androidButton, int action, float x, float y) { + static Uint8 SDLButton; + + if (!Android_Window) { + return; + } + + switch(action) { + case ACTION_DOWN: + // Determine which button originated the event, and store it for ACTION_UP + SDLButton = SDL_BUTTON_LEFT; + if (androidButton == BUTTON_SECONDARY) { + SDLButton = SDL_BUTTON_RIGHT; + } else if (androidButton == BUTTON_TERTIARY) { + SDLButton = SDL_BUTTON_MIDDLE; + } + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_PRESSED, SDLButton); + break; + + case ACTION_UP: + // Android won't give us the button that originated the ACTION_DOWN event, so we'll + // assume it's the one we stored + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_RELEASED, SDLButton); + break; + + case ACTION_HOVER_MOVE: + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + break; + + case ACTION_SCROLL: + SDL_SendMouseWheel(Android_Window, 0, x, y, SDL_MOUSEWHEEL_NORMAL); + break; + + default: + break; + } +} + +#endif /* SDL_VIDEO_DRIVER_ANDROID */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/android/SDL_androidmouse.h b/src/video/android/SDL_androidmouse.h new file mode 100644 index 000000000..ebc6a7a1c --- /dev/null +++ b/src/video/android/SDL_androidmouse.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef _SDL_androidmouse_h +#define _SDL_androidmouse_h + +#include "SDL_androidvideo.h" + +extern void Android_OnMouse( int button, int action, float x, float y); + +#endif /* _SDL_androidmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidtouch.c b/src/video/android/SDL_androidtouch.c index 5f33429b5..3b406c96e 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -24,13 +24,12 @@ #include +#include "SDL_hints.h" #include "SDL_events.h" +#include "SDL_log.h" +#include "SDL_androidtouch.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" -#include "SDL_log.h" - -#include "SDL_androidtouch.h" - #include "../../core/android/SDL_android.h" #define ACTION_DOWN 0 @@ -51,11 +50,29 @@ static void Android_GetWindowCoordinates(float x, float y, *window_y = (int)(y * window_h); } +static volatile SDL_bool separate_mouse_and_touch = SDL_FALSE; + +static void +SeparateEventsHintWatcher(void *userdata, const char *name, + const char *oldValue, const char *newValue) +{ + jclass mActivityClass = Android_JNI_GetActivityClass(); + JNIEnv *env = Android_JNI_GetEnv(); + jfieldID fid = (*env)->GetStaticFieldID(env, mActivityClass, "mSeparateMouseAndTouch", "Z"); + + separate_mouse_and_touch = (newValue && (SDL_strcmp(newValue, "1") == 0)); + (*env)->SetStaticBooleanField(env, mActivityClass, fid, separate_mouse_and_touch ? JNI_TRUE : JNI_FALSE); +} + void Android_InitTouch(void) { int i; int* ids; - int number = Android_JNI_GetTouchDeviceIds(&ids); + const int number = Android_JNI_GetTouchDeviceIds(&ids); + + SDL_AddHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, + SeparateEventsHintWatcher, NULL); + if (0 < number) { for (i = 0; i < number; ++i) { SDL_AddTouch((SDL_TouchID) ids[i], ""); /* no error handling */ @@ -64,6 +81,13 @@ void Android_InitTouch(void) } } +void Android_QuitTouch(void) +{ + SDL_DelHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, + SeparateEventsHintWatcher, NULL); + separate_mouse_and_touch = SDL_FALSE; +} + void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p) { SDL_TouchID touchDeviceId = 0; @@ -85,36 +109,41 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio case ACTION_DOWN: /* Primary pointer down */ Android_GetWindowCoordinates(x, y, &window_x, &window_y); - /* send moved event */ - SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); - /* send mouse down event */ - SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + if (!separate_mouse_and_touch) { + /* send moved event */ + SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + /* send mouse down event */ + SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + } pointerFingerID = fingerId; case ACTION_POINTER_DOWN: /* Non primary pointer down */ SDL_SendTouch(touchDeviceId, fingerId, SDL_TRUE, x, y, p); break; - + case ACTION_MOVE: if (!pointerFingerID) { Android_GetWindowCoordinates(x, y, &window_x, &window_y); - - /* send moved event */ - SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + if (!separate_mouse_and_touch) { + /* send moved event */ + SDL_SendMouseMotion(Android_Window, SDL_TOUCH_MOUSEID, 0, window_x, window_y); + } } SDL_SendTouchMotion(touchDeviceId, fingerId, x, y, p); break; - + case ACTION_UP: /* Primary pointer up */ - /* send mouse up */ - pointerFingerID = (SDL_FingerID) 0; - SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + if (!separate_mouse_and_touch) { + /* send mouse up */ + pointerFingerID = (SDL_FingerID) 0; + SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + } case ACTION_POINTER_UP: /* Non primary pointer up */ SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p); break; - + default: break; } diff --git a/src/video/android/SDL_androidtouch.h b/src/video/android/SDL_androidtouch.h index 81a0cb50e..904e0d2a6 100644 --- a/src/video/android/SDL_androidtouch.h +++ b/src/video/android/SDL_androidtouch.h @@ -23,6 +23,7 @@ #include "SDL_androidvideo.h" extern void Android_InitTouch(void); +extern void Android_QuitTouch(void); extern void Android_OnTouch( int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index ed3d3b323..66384b261 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -86,6 +86,7 @@ Android_SuspendScreenSaver(_THIS) static void Android_DeleteDevice(SDL_VideoDevice * device) { + SDL_free(device->driverdata); SDL_free(device); } @@ -187,6 +188,7 @@ Android_VideoInit(_THIS) void Android_VideoQuit(_THIS) { + Android_QuitTouch(); } /* This function gets called before VideoInit() */ diff --git a/src/video/cocoa/SDL_cocoaevents.h b/src/video/cocoa/SDL_cocoaevents.h index 687cf647e..1d27bbf99 100644 --- a/src/video/cocoa/SDL_cocoaevents.h +++ b/src/video/cocoa/SDL_cocoaevents.h @@ -25,6 +25,7 @@ extern void Cocoa_RegisterApp(void); extern void Cocoa_PumpEvents(_THIS); +extern void Cocoa_SuspendScreenSaver(_THIS); #endif /* _SDL_cocoaevents_h */ diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 13aeb4502..925f05b8e 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -27,6 +27,11 @@ #include "../../events/SDL_events_c.h" #include "SDL_assert.h" +/* This define was added in the 10.9 SDK. */ +#ifndef kIOPMAssertPreventUserIdleDisplaySleep +#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep +#endif + @interface SDLApplication : NSApplication - (void)terminate:(id)sender; @@ -61,11 +66,19 @@ { self = [super init]; if (self) { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + seenFirstActivate = NO; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(focusSomeWindow:) - name:NSApplicationDidBecomeActiveNotification - object:nil]; + + [center addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:nil]; + + [center addObserver:self + selector:@selector(focusSomeWindow:) + name:NSApplicationDidBecomeActiveNotification + object:nil]; } return self; @@ -73,16 +86,65 @@ - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + [center removeObserver:self name:NSWindowWillCloseNotification object:nil]; + [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil]; + [super dealloc]; } +- (void)windowWillClose:(NSNotification *)notification; +{ + NSWindow *win = (NSWindow*)[notification object]; + + if (![win isKeyWindow]) { + return; + } + + /* HACK: Make the next window in the z-order key when the key window is + * closed. The custom event loop and/or windowing code we have seems to + * prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825 + */ + + /* +[NSApp orderedWindows] never includes the 'About' window, but we still + * want to try its list first since the behavior in other apps is to only + * make the 'About' window key if no other windows are on-screen. + */ + for (NSWindow *window in [NSApp orderedWindows]) { + if (window != win && [window canBecomeKeyWindow]) { + if ([window respondsToSelector:@selector(isOnActiveSpace)]) { + if (![window isOnActiveSpace]) { + continue; + } + } + [window makeKeyAndOrderFront:self]; + return; + } + } + + /* If a window wasn't found above, iterate through all visible windows + * (including the 'About' window, if it's shown) and make the first one key. + * Note that +[NSWindow windowNumbersWithOptions:] was added in 10.6. + */ + if ([NSWindow respondsToSelector:@selector(windowNumbersWithOptions:)]) { + /* Get all visible windows in the active Space, in z-order. */ + for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) { + NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]]; + if (window && window != win && [window canBecomeKeyWindow]) { + [window makeKeyAndOrderFront:self]; + return; + } + } + } +} + - (void)focusSomeWindow:(NSNotification *)aNotification { /* HACK: Ignore the first call. The application gets a * applicationDidBecomeActive: a little bit after the first window is * created, and if we don't ignore it, a window that has been created with - * SDL_WINDOW_MINIZED will ~immediately be restored. + * SDL_WINDOW_MINIMIZED will ~immediately be restored. */ if (!seenFirstActivate) { seenFirstActivate = YES; @@ -251,17 +313,24 @@ Cocoa_RegisterApp(void) { @autoreleasepool { /* This can get called more than once! Be careful what you initialize! */ - ProcessSerialNumber psn; - - if (!GetCurrentProcess(&psn)) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - } if (NSApp == nil) { [SDLApplication sharedApplication]; SDL_assert(NSApp != nil); +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 + if ([NSApp respondsToSelector:@selector(setActivationPolicy:)]) { +#endif + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 + } else { + ProcessSerialNumber psn = {0, kCurrentProcess}; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + } +#endif + + [NSApp activateIgnoringOtherApps:YES]; + if ([NSApp mainMenu] == nil) { CreateApplicationMenus(); } @@ -293,8 +362,8 @@ Cocoa_PumpEvents(_THIS) { @autoreleasepool { /* Update activity every 30 seconds to prevent screensaver */ - if (_this->suspend_screensaver) { - SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + if (_this->suspend_screensaver && !data->screensaver_use_iopm) { Uint32 now = SDL_GetTicks(); if (!data->screensaver_activity || SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { @@ -336,6 +405,35 @@ Cocoa_PumpEvents(_THIS) } }} +void +Cocoa_SuspendScreenSaver(_THIS) +{ @autoreleasepool +{ + SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + + if (!data->screensaver_use_iopm) { + return; + } + + if (data->screensaver_assertion) { + IOPMAssertionRelease(data->screensaver_assertion); + data->screensaver_assertion = 0; + } + + if (_this->suspend_screensaver) { + /* FIXME: this should ideally describe the real reason why the game + * called SDL_DisableScreenSaver. Note that the name is only meant to be + * seen by OS X power users. there's an additional optional human-readable + * (localized) reason parameter which we don't set. + */ + NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"]; + IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, + (CFStringRef) name, + NULL, NULL, NULL, 0, NULL, + &data->screensaver_assertion); + } +}} + #endif /* SDL_VIDEO_DRIVER_COCOA */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h index 288c41fca..cf254db1b 100644 --- a/src/video/cocoa/SDL_cocoavideo.h +++ b/src/video/cocoa/SDL_cocoavideo.h @@ -26,6 +26,7 @@ #include "SDL_opengl.h" #include +#include #include #include "SDL_keycode.h" @@ -51,6 +52,9 @@ typedef struct SDL_VideoData SDLTranslatorResponder *fieldEdit; NSInteger clipboard_count; Uint32 screensaver_activity; + BOOL screensaver_use_iopm; + IOPMAssertionID screensaver_assertion; + } SDL_VideoData; /* Utility functions */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index ad4f14c21..f31218b3a 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -76,6 +76,7 @@ Cocoa_CreateDevice(int devindex) device->GetDisplayModes = Cocoa_GetDisplayModes; device->SetDisplayMode = Cocoa_SetDisplayMode; device->PumpEvents = Cocoa_PumpEvents; + device->SuspendScreenSaver = Cocoa_SuspendScreenSaver; device->CreateWindow = Cocoa_CreateWindow; device->CreateWindowFrom = Cocoa_CreateWindowFrom; @@ -148,6 +149,9 @@ Cocoa_VideoInit(_THIS) const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES); data->allow_spaces = ( (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && (!hint || (*hint != '0')) ); + /* The IOPM assertion API can disable the screensaver as of 10.7. */ + data->screensaver_use_iopm = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; + return 0; } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index d5455290a..068c59e02 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -374,7 +374,6 @@ SetWindowStyle(SDL_Window * window, unsigned int style) NSNotificationCenter *center; NSWindow *window = _data->nswindow; NSView *view = [window contentView]; - NSArray *windows = nil; center = [NSNotificationCenter defaultCenter]; @@ -402,25 +401,6 @@ SetWindowStyle(SDL_Window * window, unsigned int style) if ([view nextResponder] == self) { [view setNextResponder:nil]; } - - /* Make the next window in the z-order Key. If we weren't the foreground - when closed, this is a no-op. - !!! FIXME: Note that this is a hack, and there are corner cases where - !!! FIXME: this fails (such as the About box). The typical nib+RunLoop - !!! FIXME: handles this for Cocoa apps, but we bypass all that in SDL. - !!! FIXME: We should remove this code when we find a better way to - !!! FIXME: have the system do this for us. See discussion in - !!! FIXME: http://bugzilla.libsdl.org/show_bug.cgi?id=1825 - */ - windows = [NSApp orderedWindows]; - for (NSWindow *win in windows) { - if (win == window) { - continue; - } - - [win makeKeyAndOrderFront:self]; - break; - } } - (BOOL)isMoving diff --git a/src/video/dummy/SDL_nullvideo.c b/src/video/dummy/SDL_nullvideo.c index 28147bd18..79f831eee 100644 --- a/src/video/dummy/SDL_nullvideo.c +++ b/src/video/dummy/SDL_nullvideo.c @@ -82,7 +82,6 @@ DUMMY_CreateDevice(int devindex) device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); if (!device) { SDL_OutOfMemory(); - SDL_free(device); return (0); } diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c index a2887bf56..6a04d4cc8 100644 --- a/src/video/emscripten/SDL_emscriptenevents.c +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -296,7 +296,7 @@ Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text) return SDL_TRUE; } -int +EM_BOOL Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -322,7 +322,7 @@ Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent return 0; } -int +EM_BOOL Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -344,7 +344,7 @@ Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEve return 1; } -int +EM_BOOL Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -352,7 +352,7 @@ Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEven return 1; } -int +EM_BOOL Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -360,7 +360,7 @@ Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, vo return 1; } -int +EM_BOOL Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -368,7 +368,7 @@ Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, vo return 1; } -int +EM_BOOL Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) { /*SDL_WindowData *window_data = userData;*/ @@ -404,7 +404,7 @@ Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, vo return 1; } -int +EM_BOOL Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { Uint32 scancode; @@ -443,16 +443,17 @@ Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, voi || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */; } -int +EM_BOOL Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { char text[5]; - Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text); - SDL_SendKeyboardText(text); + if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) { + SDL_SendKeyboardText(text); + } return 1; } -int +EM_BOOL Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData) { /*make sure this is actually our element going fullscreen*/ @@ -514,7 +515,7 @@ Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChang return 0; } -int +EM_BOOL Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -554,7 +555,7 @@ Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *u return 0; } -int +EM_BOOL Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData) { SDL_WindowData *window_data = userData; @@ -621,10 +622,15 @@ Emscripten_UnregisterEventHandlers(SDL_WindowData *data) emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL); emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL); - emscripten_set_keydown_callback("#window", NULL, 0, NULL); - emscripten_set_keyup_callback("#window", NULL, 0, NULL); + const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); + if (!target) { + target = "#window"; + } - emscripten_set_keypress_callback("#window", NULL, 0, NULL); + emscripten_set_keydown_callback(target, NULL, 0, NULL); + emscripten_set_keyup_callback(target, NULL, 0, NULL); + + emscripten_set_keypress_callback(target, NULL, 0, NULL); emscripten_set_fullscreenchange_callback("#document", NULL, 0, NULL); diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c index 1c76923dd..453865abb 100644 --- a/src/video/emscripten/SDL_emscriptenframebuffer.c +++ b/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -63,7 +63,7 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec SDL_WindowData *data = (SDL_WindowData *) window->driverdata; surface = data->surface; if (!surface) { - return SDL_SetError("Couldn't find dummy surface for window"); + return SDL_SetError("Couldn't find framebuffer surface for window"); } /* Send the data to the display */ diff --git a/src/video/nacl/SDL_naclevents.c b/src/video/nacl/SDL_naclevents.c index 3204a6b1d..ebdbbfa22 100644 --- a/src/video/nacl/SDL_naclevents.c +++ b/src/video/nacl/SDL_naclevents.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_VIDEO_DRIVER_NACL + #include "SDL.h" #include "../../events/SDL_sysevents.h" #include "../../events/SDL_events_c.h" @@ -430,3 +432,7 @@ void NACL_PumpEvents(_THIS) { } } } + +#endif /* SDL_VIDEO_DRIVER_NACL */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspevents.c b/src/video/psp/SDL_pspevents.c index d096c0616..399566bf6 100644 --- a/src/video/psp/SDL_pspevents.c +++ b/src/video/psp/SDL_pspevents.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_PSP /* Being a null driver, there's no event stream. We just define stubs for most of the API. */ @@ -282,3 +285,6 @@ void PSP_EventQuit(_THIS) /* end of SDL_pspevents.c ... */ +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspgl.c b/src/video/psp/SDL_pspgl.c index d24e72292..61620de38 100644 --- a/src/video/psp/SDL_pspgl.c +++ b/src/video/psp/SDL_pspgl.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_PSP #include #include @@ -203,3 +206,6 @@ PSP_GL_DeleteContext(_THIS, SDL_GLContext context) return; } +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspmouse.c b/src/video/psp/SDL_pspmouse.c index 8df3d614e..0c8f5a428 100644 --- a/src/video/psp/SDL_pspmouse.c +++ b/src/video/psp/SDL_pspmouse.c @@ -18,7 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" +#if SDL_VIDEO_DRIVER_PSP #include @@ -33,3 +35,7 @@ struct WMcursor { int unused; }; + +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspvideo.c b/src/video/psp/SDL_pspvideo.c index b3787239c..61244093c 100644 --- a/src/video/psp/SDL_pspvideo.c +++ b/src/video/psp/SDL_pspvideo.c @@ -66,7 +66,7 @@ PSP_Create() SDL_GLDriverData *gldata; int status; - /* Check if pandora could be initialized */ + /* Check if PSP could be initialized */ status = PSP_Available(); if (status == 0) { /* PSP could not be used */ @@ -80,7 +80,7 @@ PSP_Create() return NULL; } - /* Initialize internal Pandora specific data */ + /* Initialize internal PSP specific data */ phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); if (phdata == NULL) { SDL_OutOfMemory(); diff --git a/src/video/psp/SDL_pspvideo.h b/src/video/psp/SDL_pspvideo.h index 2e1bb241b..cb25b57d0 100644 --- a/src/video/psp/SDL_pspvideo.h +++ b/src/video/psp/SDL_pspvideo.h @@ -19,8 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef __SDL_PANDORA_H__ -#define __SDL_PANDORA_H__ +#ifndef _SDL_pspvideo_h +#define _SDL_pspvideo_h #include @@ -97,6 +97,6 @@ void PSP_ShowScreenKeyboard(_THIS, SDL_Window *window); void PSP_HideScreenKeyboard(_THIS, SDL_Window *window); SDL_bool PSP_IsScreenKeyboardShown(_THIS, SDL_Window *window); -#endif /* __SDL_PANDORA_H__ */ +#endif /* _SDL_pspvideo_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 3760c0d3b..81bdc81b1 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -29,6 +29,7 @@ #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" +#include "SDL_waylanddyn.h" static void handle_ping(void *data, struct wl_shell_surface *shell_surface, diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 9f2eff3f7..524e67adf 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -559,10 +559,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) GetKeyboardState(keyboardState); if (ToUnicode(wParam, (lParam >> 16) & 0xff, keyboardState, (LPWSTR)&utf32, 1, 0) > 0) { - WORD repetition; - for (repetition = lParam & 0xffff; repetition > 0; repetition--) { - WIN_ConvertUTF32toUTF8(utf32, text); - SDL_SendKeyboardText(text); + if (WIN_ConvertUTF32toUTF8(utf32, text)) { + WORD repetition; + for (repetition = lParam & 0xffff; repetition > 0; repetition--) { + SDL_SendKeyboardText(text); + } } } } diff --git a/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c index 71855c874..bab97fae0 100644 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -74,6 +74,13 @@ #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 #endif +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif + typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, @@ -405,6 +412,11 @@ WIN_GL_InitExtensions(_THIS) _this->gl_data->HAS_WGL_EXT_create_context_es2_profile = SDL_TRUE; } + /* Check for GLX_ARB_context_flush_control */ + if (HasExtension("WGL_ARB_context_flush_control", extensions)) { + _this->gl_data->HAS_WGL_ARB_context_flush_control = SDL_TRUE; + } + _this->gl_data->wglMakeCurrent(hdc, NULL); _this->gl_data->wglDeleteContext(hglrc); ReleaseDC(hwnd, hdc); @@ -648,8 +660,8 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) SDL_SetError("GL 3.x is not supported"); context = temp_context; } else { - /* max 8 attributes plus terminator */ - int attribs[9] = { + /* max 10 attributes plus terminator */ + int attribs[11] = { WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version, WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version, 0 @@ -668,6 +680,14 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) attribs[iattr++] = _this->gl_config.flags; } + /* only set if wgl extension is available */ + if( _this->gl_data->HAS_WGL_ARB_context_flush_control ) { + attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB; + attribs[iattr++] = _this->gl_config.release_behavior ? + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; + } + attribs[iattr++] = 0; /* Create the GL 3.x context */ diff --git a/src/video/windows/SDL_windowsopengl.h b/src/video/windows/SDL_windowsopengl.h index b96e0ac1e..b95b90f74 100644 --- a/src/video/windows/SDL_windowsopengl.h +++ b/src/video/windows/SDL_windowsopengl.h @@ -30,6 +30,7 @@ struct SDL_GLDriverData SDL_bool HAS_WGL_ARB_pixel_format; SDL_bool HAS_WGL_EXT_swap_control_tear; SDL_bool HAS_WGL_EXT_create_context_es2_profile; + SDL_bool HAS_WGL_ARB_context_flush_control; void *(WINAPI * wglGetProcAddress) (const char *proc); HGLRC(WINAPI * wglCreateContext) (HDC hdc); diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 94328339f..463db1e06 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -643,10 +643,11 @@ WIN_DestroyWindow(_THIS, SDL_Window * window) SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { - HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata; if (info->version.major <= SDL_MAJOR_VERSION) { info->subsystem = SDL_SYSWM_WINDOWS; - info->info.win.window = hwnd; + info->info.win.window = data->hwnd; + info->info.win.hdc = data->hdc; return SDL_TRUE; } else { SDL_SetError("Application not compiled with SDL %d.%d\n", diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp index e3a955be1..4c7199824 100644 --- a/src/video/winrt/SDL_winrtopengles.cpp +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -36,10 +36,17 @@ using namespace Windows::UI::Core; /* ANGLE/WinRT constants */ static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0; -#define EGL_PLATFORM_ANGLE_ANGLE 0x3201 -#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3203 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B +#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F + +#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER 0x320B + /* * SDL/EGL top-level implementation @@ -80,11 +87,40 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) Microsoft::WRL::ComPtr cpp_display = video_data->winrtEglWindow; _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display); if (!_this->egl_data->egl_display) { - return SDL_SetError("Could not get EGL display"); + return SDL_SetError("Could not get Windows 8.0 EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + return SDL_SetError("Could not initialize Windows 8.0 EGL"); } } else { - const EGLint displayAttributes[] = { + /* Declare some ANGLE/EGL initialization property-sets, as suggested by + * MSOpenTech's ANGLE-for-WinRT template apps: + */ + const EGLint defaultDisplayAttributes[] = + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint fl9_3DisplayAttributes[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint warpDisplayAttributes[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; @@ -99,14 +135,41 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) return SDL_SetError("Could not retrieve ANGLE/WinRT display function(s)"); } - _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes); +#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + /* Try initializing EGL at D3D11 Feature Level 10_0+ (which is not + * supported on WinPhone 8.x. + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (!_this->egl_data->egl_display) { - return SDL_SetError("Could not get EGL display"); + return SDL_SetError("Could not get 10_0+ EGL display"); } - } - if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { - return SDL_SetError("Could not initialize EGL"); + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) +#endif + { + /* Try initializing EGL at D3D11 Feature Level 9_3, in case the + * 10_0 init fails, or we're on Windows Phone (which only supports + * 9_3). + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get 9_3 EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + /* Try initializing EGL at D3D11 Feature Level 11_0 on WARP + * (a Windows-provided, software rasterizer) if all else fails. + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get WARP EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + return SDL_SetError("Could not initialize WinRT 8.x+ EGL"); + } + } + } } return 0; diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 645c7741d..02dc8a900 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -677,8 +677,17 @@ X11_DispatchEvent(_THIS) data->window == SDL_GetKeyboardFocus()) { ReconcileKeyboardState(_this, data); } - data->pending_focus = PENDING_FOCUS_IN; - data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusIn(data); + } + else + { + data->pending_focus = PENDING_FOCUS_IN; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; + } } break; @@ -701,8 +710,17 @@ X11_DispatchEvent(_THIS) #ifdef DEBUG_XEVENTS printf("window %p: FocusOut!\n", data); #endif - data->pending_focus = PENDING_FOCUS_OUT; - data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME; + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusOut(data); + } + else + { + data->pending_focus = PENDING_FOCUS_OUT; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; + } } break; @@ -1090,15 +1108,25 @@ X11_DispatchEvent(_THIS) without ever mapping / unmapping them, so we handle that here, because they use the NETWM protocol to notify us of changes. */ - Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); - if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN || - (flags^data->window->flags) & SDL_WINDOW_FULLSCREEN ) { - if (flags & SDL_WINDOW_HIDDEN) { - X11_DispatchUnmapNotify(data); - } else { - X11_DispatchMapNotify(data); + const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); + const Uint32 changed = flags ^ data->window->flags; + + if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) { + if (flags & SDL_WINDOW_HIDDEN) { + X11_DispatchUnmapNotify(data); + } else { + X11_DispatchMapNotify(data); } } + + if (changed & SDL_WINDOW_MAXIMIZED) { + if (flags & SDL_WINDOW_MAXIMIZED) { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); + } else { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); + } + } + } } break; @@ -1283,9 +1311,15 @@ X11_PumpEvents(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + if (data->last_mode_change_deadline) { + if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) { + data->last_mode_change_deadline = 0; /* assume we're done. */ + } + } + /* Update activity every 30 seconds to prevent screensaver */ if (_this->suspend_screensaver) { - Uint32 now = SDL_GetTicks(); + const Uint32 now = SDL_GetTicks(); if (!data->screensaver_activity || SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { X11_XResetScreenSaver(data->display); diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 2a98e3c3e..ea99cdc25 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -31,8 +31,8 @@ #include -#define SDL_FORK_MESSAGEBOX 0 -#define SDL_SET_LOCALE 0 +#define SDL_FORK_MESSAGEBOX 1 +#define SDL_SET_LOCALE 1 #if SDL_FORK_MESSAGEBOX #include @@ -366,6 +366,7 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) int x, y; XSizeHints *sizehints; XSetWindowAttributes wnd_attr; + Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG; Display *display = data->display; SDL_WindowData *windowdata = NULL; const SDL_MessageBoxData *messageboxdata = data->messageboxdata; @@ -401,6 +402,13 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) X11_XStoreName( display, data->window, messageboxdata->title ); + /* Let the window manager know this is a dialog box */ + _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); + _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, + (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1); + /* Allow the window to be deleted by the window manager */ data->wm_protocols = X11_XInternAtom( display, "WM_PROTOCOLS", False ); data->wm_delete_message = X11_XInternAtom( display, "WM_DELETE_WINDOW", False ); @@ -710,9 +718,6 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int fds[2]; int status = 0; - /* Need to flush here in case someone has turned grab off and it hasn't gone through yet, etc. */ - X11_XFlush(data->display); - if (pipe(fds) == -1) { return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */ } diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 0fc6d2386..5248f7655 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -24,6 +24,7 @@ #include "SDL_hints.h" #include "SDL_x11video.h" +#include "SDL_timer.h" #include "edid.h" /* #define X11MODES_DEBUG */ @@ -813,10 +814,13 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) int X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode) { - Display *display = ((SDL_VideoData *) _this->driverdata)->display; + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + Display *display = viddata->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; + viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2); + #if SDL_VIDEO_DRIVER_X11_XRANDR if (data->use_xrandr) { XRRScreenResources *res; diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 1e94b041c..7bc3256bd 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -122,6 +122,13 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy, #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 #endif +#ifndef GLX_ARB_context_flush_control +#define GLX_ARB_context_flush_control +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif + #define OPENGL_REQUIRES_DLOPEN #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) #include @@ -279,14 +286,14 @@ HasExtension(const char *extension, const char *extensions) const char *start; const char *where, *terminator; + if (!extensions) + return SDL_FALSE; + /* Extension names should not have spaces. */ where = SDL_strchr(extension, ' '); if (where || *extension == '\0') return SDL_FALSE; - if (!extensions) - return SDL_FALSE; - /* It takes a bit of care to be fool-proof about parsing the * OpenGL extensions string. Don't be fooled by sub-strings, * etc. */ @@ -312,32 +319,10 @@ static void X11_GL_InitExtensions(_THIS) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; - int screen = DefaultScreen(display); - XVisualInfo *vinfo; - XSetWindowAttributes xattr; - Window w; - GLXContext context; + const int screen = DefaultScreen(display); const char *(*glXQueryExtensionsStringFunc) (Display *, int); const char *extensions; - vinfo = X11_GL_GetVisual(_this, display, screen); - if (!vinfo) { - return; - } - xattr.background_pixel = 0; - xattr.border_pixel = 0; - xattr.colormap = - X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual, - AllocNone); - w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0, - vinfo->depth, InputOutput, vinfo->visual, - (CWBackPixel | CWBorderPixel | CWColormap), &xattr); - context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True); - if (context) { - _this->gl_data->glXMakeCurrent(display, w, context); - } - X11_XFree(vinfo); - glXQueryExtensionsStringFunc = (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this, "glXQueryExtensionsString"); @@ -373,6 +358,16 @@ X11_GL_InitExtensions(_THIS) (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); } + /* Check for GLX_ARB_create_context */ + if (HasExtension("GLX_ARB_create_context", extensions)) { + _this->gl_data->glXCreateContextAttribsARB = + (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *)) + X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB"); + _this->gl_data->glXChooseFBConfig = + (GLXFBConfig *(*)(Display *, int, const int *, int *)) + X11_GL_GetProcAddress(_this, "glXChooseFBConfig"); + } + /* Check for GLX_EXT_visual_rating */ if (HasExtension("GLX_EXT_visual_rating", extensions)) { _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE; @@ -388,18 +383,16 @@ X11_GL_InitExtensions(_THIS) _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE; } - if (context) { - _this->gl_data->glXMakeCurrent(display, None, NULL); - _this->gl_data->glXDestroyContext(display, context); + /* Check for GLX_ARB_context_flush_control */ + if (HasExtension("GLX_ARB_context_flush_control", extensions)) { + _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE; } - X11_XDestroyWindow(display, w); - X11_PumpEvents(_this); } /* glXChooseVisual and glXChooseFBConfig have some small differences in * the attribute encoding, it can be chosen with the for_FBConfig parameter. */ -int +static int X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig) { int i = 0; @@ -481,9 +474,7 @@ X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int si if (_this->gl_config.framebuffer_srgb_capable) { attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; - if( for_FBConfig ) { - attribs[i++] = True; - } + attribs[i++] = True; /* always needed, for_FBConfig or not! */ } if (_this->gl_config.accelerated >= 0 && @@ -576,7 +567,6 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) XVisualInfo v, *vinfo; int n; GLXContext context = NULL, share_context; - PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL; if (_this->gl_config.share_with_current_context) { share_context = (GLXContext)SDL_GL_GetCurrentContext(); @@ -601,78 +591,61 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) context = _this->gl_data->glXCreateContext(display, vinfo, share_context, True); } else { - /* If we want a GL 3.0 context or later we need to get a temporary - context to grab the new context creation function */ - GLXContext temp_context = - _this->gl_data->glXCreateContext(display, vinfo, NULL, True); - if (temp_context) { - /* max 8 attributes plus terminator */ - int attribs[9] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, - _this->gl_config.major_version, - GLX_CONTEXT_MINOR_VERSION_ARB, - _this->gl_config.minor_version, - 0 - }; - int iattr = 4; + /* max 10 attributes plus terminator */ + int attribs[11] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + _this->gl_config.major_version, + GLX_CONTEXT_MINOR_VERSION_ARB, + _this->gl_config.minor_version, + 0 + }; + int iattr = 4; - /* SDL profile bits match GLX profile bits */ - if( _this->gl_config.profile_mask != 0 ) { - attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; - attribs[iattr++] = _this->gl_config.profile_mask; - } + /* SDL profile bits match GLX profile bits */ + if( _this->gl_config.profile_mask != 0 ) { + attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; + attribs[iattr++] = _this->gl_config.profile_mask; + } - /* SDL flags match GLX flags */ - if( _this->gl_config.flags != 0 ) { - attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; - attribs[iattr++] = _this->gl_config.flags; - } + /* SDL flags match GLX flags */ + if( _this->gl_config.flags != 0 ) { + attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; + attribs[iattr++] = _this->gl_config.flags; + } - attribs[iattr++] = 0; + /* only set if glx extension is available */ + if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) { + attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB; + attribs[iattr++] = + _this->gl_config.release_behavior ? + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; + } - /* Get a pointer to the context creation function for GL 3.0 */ - glXCreateContextAttribs = - (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data-> - glXGetProcAddress((GLubyte *) - "glXCreateContextAttribsARB"); - if (!glXCreateContextAttribs) { - SDL_SetError("GL 3.x is not supported"); - context = temp_context; + attribs[iattr++] = 0; + + /* Get a pointer to the context creation function for GL 3.0 */ + if (!_this->gl_data->glXCreateContextAttribsARB) { + SDL_SetError("OpenGL 3.0 and later are not supported by this system"); + } else { + int glxAttribs[64]; + + /* Create a GL 3.x context */ + GLXFBConfig *framebuffer_config = NULL; + int fbcount = 0; + + X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); + + if (!_this->gl_data->glXChooseFBConfig + || !(framebuffer_config = + _this->gl_data->glXChooseFBConfig(display, + DefaultScreen(display), glxAttribs, + &fbcount))) { + SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable"); } else { - int glxAttribs[64]; - - /* Create a GL 3.x context */ - GLXFBConfig *framebuffer_config = NULL; - int fbcount = 0; - GLXFBConfig *(*glXChooseFBConfig) (Display * disp, - int screen, - const int *attrib_list, - int *nelements); - - glXChooseFBConfig = - (GLXFBConfig * - (*)(Display *, int, const int *, - int *)) _this->gl_data-> - glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); - - X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); - - if (!glXChooseFBConfig - || !(framebuffer_config = - glXChooseFBConfig(display, - DefaultScreen(display), glxAttribs, - &fbcount))) { - SDL_SetError - ("No good framebuffers found. GL 3.x disabled"); - context = temp_context; - } else { - context = - glXCreateContextAttribs(display, + context = _this->gl_data->glXCreateContextAttribsARB(display, framebuffer_config[0], share_context, True, attribs); - _this->gl_data->glXDestroyContext(display, - temp_context); - } } } } diff --git a/src/video/x11/SDL_x11opengl.h b/src/video/x11/SDL_x11opengl.h index ed7f292d4..5856c9b79 100644 --- a/src/video/x11/SDL_x11opengl.h +++ b/src/video/x11/SDL_x11opengl.h @@ -35,11 +35,14 @@ struct SDL_GLDriverData SDL_bool HAS_GLX_EXT_visual_info; SDL_bool HAS_GLX_EXT_swap_control_tear; SDL_bool HAS_GLX_EXT_create_context_es2_profile; + SDL_bool HAS_GLX_ARB_context_flush_control; Bool (*glXQueryExtension) (Display*,int*,int*); void *(*glXGetProcAddress) (const GLubyte*); XVisualInfo *(*glXChooseVisual) (Display*,int,int*); GLXContext (*glXCreateContext) (Display*,XVisualInfo*,GLXContext,Bool); + GLXContext (*glXCreateContextAttribsARB) (Display*,GLXFBConfig,GLXContext,Bool,const int *); + GLXFBConfig *(*glXChooseFBConfig) (Display*,int,const int *,int *); void (*glXDestroyContext) (Display*, GLXContext); Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext); void (*glXSwapBuffers) (Display*, GLXDrawable); diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index f076ccec1..ed6b14fa4 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -112,6 +112,7 @@ typedef struct SDL_VideoData SDL_Scancode key_layout[256]; SDL_bool selection_waiting; + Uint32 last_mode_change_deadline; } SDL_VideoData; extern SDL_bool X11_UseDirectColorVisuals(void); diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 789d2f7cc..ce3f58439 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -27,8 +27,7 @@ video mode changes and we can respond to them by triggering more mode changes. */ -#define PENDING_FOCUS_IN_TIME 200 -#define PENDING_FOCUS_OUT_TIME 200 +#define PENDING_FOCUS_TIME 200 #if SDL_VIDEO_OPENGL_EGL #include diff --git a/test/Makefile.in b/test/Makefile.in index 078e4eb99..1a8cec614 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -38,6 +38,7 @@ TARGETS = \ testloadso$(EXE) \ testlock$(EXE) \ testmultiaudio$(EXE) \ + testaudiohotplug$(EXE) \ testnative$(EXE) \ testoverlay2$(EXE) \ testplatform$(EXE) \ @@ -105,6 +106,9 @@ testautomation$(EXE): $(srcdir)/testautomation.c \ testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + testatomic$(EXE): $(srcdir)/testatomic.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/test/loopwave.c b/test/loopwave.c index 9d50aaea5..e09fe0f72 100644 --- a/test/loopwave.c +++ b/test/loopwave.c @@ -29,7 +29,6 @@ #endif #include "SDL.h" -#include "SDL_audio.h" struct { diff --git a/test/loopwavequeue.c b/test/loopwavequeue.c index 8ca31dd03..babff3b3f 100644 --- a/test/loopwavequeue.c +++ b/test/loopwavequeue.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" #if HAVE_SIGNAL_H @@ -45,10 +49,32 @@ poked(int sig) done = 1; } +void +loop() +{ +#ifdef __EMSCRIPTEN__ + if (done || (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)) { + emscripten_cancel_main_loop(); + } + else +#endif + { + /* The device from SDL_OpenAudio() is always device #1. */ + const Uint32 queued = SDL_GetQueuedAudioSize(1); + SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); + if (queued <= 8192) { /* time to requeue the whole thing? */ + if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { + SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); + } else { + SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); + } + } + } +} + int main(int argc, char *argv[]) { - int i; char filename[4096]; /* Enable standard application logging */ @@ -97,25 +123,22 @@ main(int argc, char *argv[]) /* Let the audio run */ SDL_PauseAudio(0); + done = 0; + /* Note that we stuff the entire audio buffer into the queue in one shot. Most apps would want to feed it a little at a time, as it plays, but we're going for simplicity here. */ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) { - /* The device from SDL_OpenAudio() is always device #1. */ - const Uint32 queued = SDL_GetQueuedAudioSize(1); - SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); - if (queued <= 8192) { /* time to requeue the whole thing? */ - if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { - SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); - } else { - SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); - } - } + loop(); SDL_Delay(100); /* let it play for awhile. */ } +#endif /* Clean up on signal */ SDL_CloseAudio(); diff --git a/test/relative_mode.markdown b/test/relative_mode.markdown index 9ae88aa1c..5b2ed6185 100644 --- a/test/relative_mode.markdown +++ b/test/relative_mode.markdown @@ -37,9 +37,11 @@ Code int main(int argc, char *argv[]) { + SDL_Window *win; + SDL_Init(SDL_INIT_VIDEO); - SDL_Window *win = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0); + win = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0); SDL_SetRelativeMouseMode(SDL_TRUE); while (1) diff --git a/test/testatomic.c b/test/testatomic.c index 662a017ca..178de7ac1 100644 --- a/test/testatomic.c +++ b/test/testatomic.c @@ -12,9 +12,6 @@ #include #include "SDL.h" -#include "SDL_atomic.h" -#include "SDL_assert.h" -#include "SDL_cpuinfo.h" /* Absolutely basic tests just to see if we get the expected value diff --git a/test/testaudiohotplug.c b/test/testaudiohotplug.c new file mode 100644 index 000000000..6c3d88cd1 --- /dev/null +++ b/test/testaudiohotplug.c @@ -0,0 +1,183 @@ +/* + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Program to test hotplugging of audio devices */ + +#include "SDL_config.h" + +#include +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#ifdef __EMSCRIPTEN__ +#include +#endif + +#include "SDL.h" + +static SDL_AudioSpec spec; +static Uint8 *sound = NULL; /* Pointer to wave data */ +static Uint32 soundlen = 0; /* Length of wave data */ + +static int posindex = 0; +static Uint32 positions[64]; + +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void +quit(int rc) +{ + SDL_Quit(); + exit(rc); +} + +void SDLCALL +fillerup(void *_pos, Uint8 * stream, int len) +{ + Uint32 pos = *((Uint32 *) _pos); + Uint8 *waveptr; + int waveleft; + + /* Set up the pointers */ + waveptr = sound + pos; + waveleft = soundlen - pos; + + /* Go! */ + while (waveleft <= len) { + SDL_memcpy(stream, waveptr, waveleft); + stream += waveleft; + len -= waveleft; + waveptr = sound; + waveleft = soundlen; + pos = 0; + } + SDL_memcpy(stream, waveptr, len); + pos += len; + *((Uint32 *) _pos) = pos; +} + +static int done = 0; +void +poked(int sig) +{ + done = 1; +} + +static void +iteration() +{ + SDL_Event e; + SDL_AudioDeviceID dev; + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + done = 1; + } else if (e.type == SDL_AUDIODEVICEADDED) { + const char *name = SDL_GetAudioDeviceName(e.adevice.which, 0); + SDL_Log("New %s audio device: %s\n", e.adevice.iscapture ? "capture" : "output", name); + if (!e.adevice.iscapture) { + positions[posindex] = 0; + spec.userdata = &positions[posindex++]; + spec.callback = fillerup; + dev = SDL_OpenAudioDevice(name, 0, &spec, NULL, 0); + if (!dev) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open '%s': %s\n", name, SDL_GetError()); + } else { + SDL_Log("Opened '%s' as %u\n", name, (unsigned int) dev); + SDL_PauseAudioDevice(dev, 0); + } + } + } else if (e.type == SDL_AUDIODEVICEREMOVED) { + dev = (SDL_AudioDeviceID) e.adevice.which; + SDL_Log("%s device %u removed.\n", e.adevice.iscapture ? "capture" : "output", (unsigned int) dev); + SDL_CloseAudioDevice(dev); + } + } +} + +#ifdef __EMSCRIPTEN__ +void +loop() +{ + if(done) + emscripten_cancel_main_loop(); + else + iteration(); +} +#endif + +int +main(int argc, char *argv[]) +{ + int i; + char filename[4096]; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return (1); + } + + /* Some targets (Mac CoreAudio) need an event queue for audio hotplug, so make and immediately hide a window. */ + SDL_MinimizeWindow(SDL_CreateWindow("testaudiohotplug", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0)); + + if (argc > 1) { + SDL_strlcpy(filename, argv[1], sizeof(filename)); + } else { + SDL_strlcpy(filename, "sample.wav", sizeof(filename)); + } + /* Load the wave file into memory */ + if (SDL_LoadWAV(filename, &spec, &sound, &soundlen) == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); + quit(1); + } + +#if HAVE_SIGNAL_H + /* Set the signals */ +#ifdef SIGHUP + signal(SIGHUP, poked); +#endif + signal(SIGINT, poked); +#ifdef SIGQUIT + signal(SIGQUIT, poked); +#endif + signal(SIGTERM, poked); +#endif /* HAVE_SIGNAL_H */ + + /* Show the list of available drivers */ + SDL_Log("Available audio drivers:"); + for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); + } + + SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + SDL_Delay(100); + iteration(); + } +#endif + + /* Clean up on signal */ + SDL_Quit(); + SDL_FreeWAV(sound); + return (0); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/testerror.c b/test/testerror.c index 1fa60885b..8290680e0 100644 --- a/test/testerror.c +++ b/test/testerror.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" static int alive = 0; diff --git a/test/testfile.c b/test/testfile.c index 172da865c..38a6bb799 100644 --- a/test/testfile.c +++ b/test/testfile.c @@ -22,7 +22,6 @@ #endif #include "SDL.h" -#include "SDL_endian.h" #include diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c index 29e0308a4..414872cf2 100644 --- a/test/testgamecontroller.c +++ b/test/testgamecontroller.c @@ -163,6 +163,10 @@ WatchGameController(SDL_GameController * gamecontroller) const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + 1; char *title = (char *)SDL_malloc(titlelen); SDL_Window *window = NULL; + + retval = SDL_FALSE; + done = SDL_FALSE; + if (title) { SDL_snprintf(title, titlelen, "%s%s", basetitle, name); } @@ -219,6 +223,10 @@ WatchGameController(SDL_GameController * gamecontroller) #endif SDL_DestroyRenderer(screen); + screen = NULL; + background = NULL; + button = NULL; + axis = NULL; SDL_DestroyWindow(window); return retval; } diff --git a/test/testhaptic.c b/test/testhaptic.c index ac8ab4158..bffe4467d 100644 --- a/test/testhaptic.c +++ b/test/testhaptic.c @@ -22,8 +22,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ifndef SDL_HAPTIC_DISABLED -#include "SDL_haptic.h" - static SDL_Haptic *haptic; diff --git a/test/testhotplug.c b/test/testhotplug.c index ba06dea0f..1b68db1e4 100644 --- a/test/testhotplug.c +++ b/test/testhotplug.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_haptic.h" #if !defined SDL_JOYSTICK_DISABLED && !defined SDL_HAPTIC_DISABLED diff --git a/test/testjoystick.c b/test/testjoystick.c index 232213a69..adb376e02 100644 --- a/test/testjoystick.c +++ b/test/testjoystick.c @@ -56,6 +56,12 @@ loop(void *arg) while (SDL_PollEvent(&event)) { switch (event.type) { + + case SDL_JOYDEVICEREMOVED: + SDL_Log("Joystick device %d removed.\n", (int) event.jdevice.which); + SDL_Log("Our instance ID is %d\n", (int) SDL_JoystickInstanceID(joystick)); + break; + case SDL_JOYAXISMOTION: SDL_Log("Joystick %d axis %d value: %d\n", event.jaxis.which, @@ -177,6 +183,8 @@ WatchJoystick(SDL_Joystick * joystick) SDL_Window *window = NULL; const char *name = NULL; + retval = SDL_FALSE; + done = SDL_FALSE; /* Create a window to display joystick axis position */ window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED, @@ -217,6 +225,7 @@ WatchJoystick(SDL_Joystick * joystick) #endif SDL_DestroyRenderer(screen); + screen = NULL; SDL_DestroyWindow(window); return retval; } diff --git a/test/testlock.c b/test/testlock.c index 9ca3ca199..92a5e9b3f 100644 --- a/test/testlock.c +++ b/test/testlock.c @@ -19,8 +19,6 @@ #include /* for atexit() */ #include "SDL.h" -#include "SDL_mutex.h" -#include "SDL_thread.h" static SDL_mutex *mutex = NULL; static SDL_threadID mainthread; diff --git a/test/testmessage.c b/test/testmessage.c index f44880c3f..b0bf39c89 100644 --- a/test/testmessage.c +++ b/test/testmessage.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void diff --git a/test/testplatform.c b/test/testplatform.c index e0dc29e7c..068be8efc 100644 --- a/test/testplatform.c +++ b/test/testplatform.c @@ -13,9 +13,6 @@ #include #include "SDL.h" -#include "SDL_endian.h" -#include "SDL_cpuinfo.h" -#include "SDL_assert.h" /* * Watcom C flags these as Warning 201: "Unreachable code" if you just @@ -170,7 +167,7 @@ TestAssertions(SDL_bool verbose) #endif { - const SDL_assert_data *item = SDL_GetAssertionReport(); + const SDL_AssertData *item = SDL_GetAssertionReport(); while (item) { SDL_Log("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", item->condition, item->function, item->filename, diff --git a/test/testrelative.c b/test/testrelative.c index 4425cb8d3..3b6ef810e 100644 --- a/test/testrelative.c +++ b/test/testrelative.c @@ -49,12 +49,20 @@ loop(){ } } for (i = 0; i < state->num_windows; ++i) { + SDL_Rect viewport; SDL_Renderer *renderer = state->renderers[i]; if (state->windows[i] == NULL) continue; SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); SDL_RenderClear(renderer); + /* Wrap the cursor rectangle at the screen edges to keep it visible */ + SDL_RenderGetViewport(renderer, &viewport); + if (rect.x < viewport.x) rect.x += viewport.w; + if (rect.y < viewport.y) rect.y += viewport.h; + if (rect.x > viewport.x + viewport.w) rect.x -= viewport.w; + if (rect.y > viewport.y + viewport.h) rect.y -= viewport.h; + DrawRects(renderer, &rect); SDL_RenderPresent(renderer); diff --git a/test/testrumble.c b/test/testrumble.c index 74a7e98fc..d72e5d94a 100644 --- a/test/testrumble.c +++ b/test/testrumble.c @@ -33,8 +33,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ifndef SDL_HAPTIC_DISABLED -#include "SDL_haptic.h" - static SDL_Haptic *haptic; diff --git a/test/testsem.c b/test/testsem.c index ca71ec2e6..8d41e083f 100644 --- a/test/testsem.c +++ b/test/testsem.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" #define NUM_THREADS 10 diff --git a/test/testthread.c b/test/testthread.c index d732320a5..75aed83fc 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" static SDL_TLSID tls; static int alive = 0; diff --git a/test/torturethread.c b/test/torturethread.c index bc4e1132f..2e572b64c 100644 --- a/test/torturethread.c +++ b/test/torturethread.c @@ -18,7 +18,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" #define NUMTHREADS 10