Merged default into iOS-improvements iOS-improvements
authorAlex Szpakowski <slime73@gmail.com>
Mon, 06 Apr 2015 15:26:37 -0300
branchiOS-improvements
changeset 9536 3c87b8f9dc58
parent 9535 a66a7f7e8cd8 (current diff)
parent 9459 f5b468964b0b (diff)
child 9537 ff30c198864e
Merged default into iOS-improvements
include/SDL_hints.h
include/SDL_syswm.h
src/joystick/iphoneos/SDL_sysjoystick.m
src/video/SDL_video.c
--- a/CMakeLists.txt	Sat Jan 24 23:58:07 2015 -0400
+++ b/CMakeLists.txt	Mon Apr 06 15:26:37 2015 -0300
@@ -118,9 +118,9 @@
 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 @@
 
 # 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 @@
   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 @@
 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(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 @@
       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 @@
     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 @@
       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()
--- a/SDL2.spec.in	Sat Jan 24 23:58:07 2015 -0400
+++ b/SDL2.spec.in	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 
 %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 @@
 %{_datadir}/aclocal/*
 
 %changelog
+* Sun Dec 07 2014 Simone Contini <s.contini@oltrelinux.com>
+- Fixed changelog date issue and docs filenames
+
 * Sun Jan 22 2012 Sam Lantinga <slouken@libsdl.org>
 - Updated for SDL 2.0
 
 * Tue May 16 2006 Sam Lantinga <slouken@libsdl.org>
 - Removed support for Darwin, due to build problems on ps2linux
 
-* Mon Jan 03 2004 Anders Bjorklund <afb@algonet.se>
+* Sat Jan 03 2004 Anders Bjorklund <afb@algonet.se>
 - Added support for Darwin, updated spec file
 
 * Wed Jan 19 2000 Sam Lantinga <slouken@libsdl.org>
--- a/android-project/src/org/libsdl/app/SDLActivity.java	Sat Jan 24 23:58:07 2015 -0400
+++ b/android-project/src/org/libsdl/app/SDLActivity.java	Mon Apr 06 15:26:37 2015 -0300
@@ -41,6 +41,10 @@
     /** 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 @@
     }
     
     /**
-     * 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 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 @@
         // 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 @@
         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 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;
     }
 }
--- a/cmake/sdlchecks.cmake	Sat Jan 24 23:58:07 2015 -0400
+++ b/cmake/sdlchecks.cmake	Mon Apr 06 15:26:37 2015 -0300
@@ -505,8 +505,13 @@
   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 @@
             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 @@
       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 @@
   endif()
 endmacro()
 
-# Rquires:
+# Requires:
 # - nada
 # Optional:
 # - THREADS opt
@@ -733,13 +776,17 @@
 
     # 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 <pthread.h>
         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 @@
           #include <pthread.h>
           #include <pthread_np.h>
           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}
--- a/configure	Sat Jan 24 23:58:07 2015 -0400
+++ b/configure	Mon Apr 06 15:26:37 2015 -0300
@@ -21916,6 +21916,7 @@
                 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
+                  #define _GNU_SOURCE 1
                   #include <pthread.h>
 
 int
@@ -21929,7 +21930,7 @@
   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 @@
 
 
 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 <pthread.h>
 
 int
@@ -21956,7 +21959,7 @@
   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 @@
 
 
 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 @@
         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
--- a/configure.in	Sat Jan 24 23:58:07 2015 -0400
+++ b/configure.in	Mon Apr 06 15:26:37 2015 -0300
@@ -2424,7 +2424,8 @@
             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.h>
                 ],[
                   pthread_mutexattr_t attr;
@@ -2435,7 +2436,8 @@
                 ])
             fi
             if test x$has_recursive_mutexes = xno; then
-                AC_TRY_COMPILE([
+                AC_TRY_LINK([
+                  #define _GNU_SOURCE 1
                   #include <pthread.h>
                 ],[
                   pthread_mutexattr_t attr;
@@ -2971,9 +2973,18 @@
         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
--- a/docs/README-platforms.md	Sat Jan 24 23:58:07 2015 -0400
+++ b/docs/README-platforms.md	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <axeld@pinc-software.de>
-* PSP - maintained by 527721088@qq.com
-* Pandora - maintained by Scott Smith <pickle136@sbcglobal.net>
-* NaCl - maintained by Gabriel Jacobo <gabomdq@gmail.com>
-
-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
+
--- a/docs/README-porting.md	Sat Jan 24 23:58:07 2015 -0400
+++ b/docs/README-porting.md	Mon Apr 06 15:26:37 2015 -0300
@@ -15,7 +15,7 @@
 
    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:
--- a/docs/README-winrt.md	Sat Jan 24 23:58:07 2015 -0400
+++ b/docs/README-winrt.md	Mon Apr 06 15:26:37 2015 -0300
@@ -90,10 +90,12 @@
   * 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 @@
     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
 
 
--- a/include/SDL_assert.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_assert.h	Mon Apr 06 15:26:37 2015 -0300
@@ -102,9 +102,9 @@
     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 @@
     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 @@
 #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 @@
 #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 @@
  *
  *  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 @@
  *  The proper way to examine this data looks something like this:
  *
  *  <code>
- *  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 @@
  *  \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 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
 }
--- a/include/SDL_config.h.cmake	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_config.h.cmake	Mon Apr 06 15:26:37 2015 -0300
@@ -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@
--- a/include/SDL_config.h.in	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_config.h.in	Mon Apr 06 15:26:37 2015 -0300
@@ -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 */
--- a/include/SDL_events.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_events.h	Mon Apr 06 15:26:37 2015 -0300
@@ -134,6 +134,10 @@
     /* 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 @@
     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_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 @@
     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 */
--- a/include/SDL_gamecontroller.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_gamecontroller.h	Mon Apr 06 15:26:37 2015 -0300
@@ -241,7 +241,8 @@
 /**
  *  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.
  */
--- a/include/SDL_hints.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_hints.h	Mon Apr 06 15:26:37 2015 -0300
@@ -533,6 +533,18 @@
  */
 #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
  *
@@ -548,6 +560,18 @@
 #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
  */
 typedef enum
--- a/include/SDL_opengl_glext.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_opengl_glext.h	Mon Apr 06 15:26:37 2015 -0300
@@ -2988,6 +2988,11 @@
 #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
--- a/include/SDL_render.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_render.h	Mon Apr 06 15:26:37 2015 -0300
@@ -81,8 +81,8 @@
     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 @@
  *  \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
--- a/include/SDL_stdinc.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_stdinc.h	Mon Apr 06 15:26:37 2015 -0300
@@ -173,6 +173,8 @@
 #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 @@
 #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 @@
 #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 @@
 #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
--- a/include/SDL_syswm.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_syswm.h	Mon Apr 06 15:26:37 2015 -0300
@@ -186,6 +186,7 @@
         struct
         {
             HWND window;                /**< The window handle */
+            HDC hdc;                    /**< The window device context */
         } win;
 #endif
 #if defined(SDL_VIDEO_DRIVER_WINRT)
--- a/include/SDL_video.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/include/SDL_video.h	Mon Apr 06 15:26:37 2015 -0300
@@ -189,7 +189,8 @@
     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 @@
     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 @@
  *  \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,
@@ -730,6 +740,15 @@
 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.
  *
  *  \return 0 on success, or -1 if setting the brightness isn't supported.
--- a/src/SDL.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/SDL.c	Mon Apr 06 15:26:37 2015 -0300
@@ -405,6 +405,8 @@
     return "BSDI";
 #elif __DREAMCAST__
     return "Dreamcast";
+#elif __EMSCRIPTEN__
+    return "Emscripten";
 #elif __FREEBSD__
     return "FreeBSD";
 #elif __HAIKU__
--- a/src/SDL_error.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/SDL_error.c	Mon Apr 06 15:26:37 2015 -0300
@@ -120,7 +120,7 @@
    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 @@
                     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);
--- a/src/audio/SDL_audio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/SDL_audio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -51,9 +51,7 @@
 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 @@
 
 /* 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 @@
 {                               /* 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 @@
     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)
+
+/* device hotplug support... */
+
+static int
+add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount)
 {
-    int i;
+    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;
+    }
+
+    SDL_assert(handle != NULL);  /* we reserve NULL, audio backends can't use it. */
+
+    item->handle = handle;
+    SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem));
 
-    for (i = 0; i < length; ++i) {
-        stream->buffer[stream->write_pos] = buf[i];
-        ++stream->write_pos;
-    }
+    SDL_LockMutex(current_audio.detectionLock);
+    item->next = *devices;
+    *devices = item;
+    retval = (*devCount)++;
+    SDL_UnlockMutex(current_audio.detectionLock);
+
+    return retval;
+}
+
+static SDL_INLINE int
+add_capture_device(const char *name, void *handle)
+{
+    /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
+    return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
 }
 
-/* Read [length] bytes out of the streamer into buf */
+static SDL_INLINE int
+add_output_device(const char *name, void *handle)
+{
+    return add_audio_device(name, handle, &current_audio.outputDevices, &current_audio.outputDeviceCount);
+}
+
 static void
-SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length)
+free_device_list(SDL_AudioDeviceItem **devices, int *devCount)
 {
-    int i;
+    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;
+}
+
 
-    for (i = 0; i < length; ++i) {
-        buf[i] = stream->buffer[stream->read_pos];
-        ++stream->read_pos;
+/* 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);
+        }
     }
 }
 
-static int
-SDL_StreamLength(SDL_AudioStreamer * stream)
+/* The audio backends call this when a currently-opened device is lost. */
+void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
 {
-    return (stream->write_pos - stream->read_pos) % stream->max_len;
-}
+    SDL_assert(get_audio_device(device->id) == device);
 
-/* 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) {
-        return -1;
+    if (!device->enabled) {
+        return;
     }
 
-    stream->max_len = max_len;
-    stream->read_pos = 0;
-    stream->write_pos = 0;
+    /* 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);
 
-    /* Zero out the buffer */
-    SDL_memset(stream->buffer, silence, max_len);
-
-    return 0;
+    /* 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);
+    }
 }
-#endif
 
-/* Deinitialize the stream simply by freeing the buffer */
 static void
-SDL_StreamDeinit(SDL_AudioStreamer * stream)
+mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag)
 {
-    SDL_free(stream->buffer);
+    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;
+        }
+    }
 }
-#endif
+
+/* 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, &current_audio.captureDevicesRemoved);
+    } else {
+        mark_device_removed(handle, current_audio.outputDevices, &current_audio.outputDevicesRemoved);
+    }
+    SDL_UnlockMutex(current_audio.detectionLock);
+    current_audio.impl.FreeDeviceHandle(handle);
+}
+
 
 
 /* buffer queueing support... */
@@ -510,26 +590,17 @@
 }
 
 
-#if defined(__ANDROID__)
-#include <android/log.h>
-#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 @@
     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);
+        if (stream == NULL) {
+            stream = device->fake_stream;
+        }
 
-                /* 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);
-                }
-            }
-
+        /* !!! 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);
         }
-    } 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) {
+        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 @@
 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_AudioQuit();        /* shutdown driver if already running. */
     }
 
-    SDL_memset(&current_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 @@
         }
 
         tried_to_init = 1;
-        SDL_memset(&current_audio, 0, sizeof(current_audio));
+        SDL_zero(current_audio);
         current_audio.name = backend->name;
         current_audio.desc = backend->desc;
         initialized = backend->init(&current_audio.impl);
@@ -817,13 +751,18 @@
             }
         }
 
-        SDL_memset(&current_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 @@
     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,30 +812,19 @@
         return -1;
     }
 
-    if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
-        return 0;
-    }
-
-    if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
-        return 1;
-    }
-
-    if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
-        return 1;
+    SDL_LockMutex(current_audio.detectionLock);
+    if (iscapture && current_audio.captureDevicesRemoved) {
+        clean_out_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount, &current_audio.captureDevicesRemoved);
     }
 
-    if (iscapture) {
-        free_device_list(&current_audio.inputDevices,
-                         &current_audio.inputDeviceCount);
-        current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
-        retval = current_audio.inputDeviceCount;
-    } else {
-        free_device_list(&current_audio.outputDevices,
-                         &current_audio.outputDeviceCount);
-        current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
-        retval = current_audio.outputDeviceCount;
+    if (!iscapture && current_audio.outputDevicesRemoved) {
+        clean_out_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount, &current_audio.outputDevicesRemoved);
+        current_audio.outputDevicesRemoved = SDL_FALSE;
     }
 
+    retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount;
+    SDL_UnlockMutex(current_audio.detectionLock);
+
     return retval;
 }
 
@@ -922,6 +832,8 @@
 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 @@
         return NULL;
     }
 
-    if (index < 0) {
-        goto no_such_device;
-    }
+    if (index >= 0) {
+        SDL_AudioDeviceItem *item;
+        int i;
 
-    if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
-        if (index > 0) {
-            goto no_such_device;
+        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;
         }
-        return DEFAULT_INPUT_DEVNAME;
+        SDL_UnlockMutex(current_audio.detectionLock);
     }
 
-    if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
-        if (index > 0) {
-            goto no_such_device;
-        }
-        return DEFAULT_OUTPUT_DEVNAME;
+    if (retval == NULL) {
+        SDL_SetError("No such device");
     }
 
-    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 @@
 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 @@
     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 @@
         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 @@
                 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 @@
                 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 @@
         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 @@
         }
     }
 
-    /* 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 @@
         }
     }
 
+    /* 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 @@
         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 @@
         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 @@
     /* 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_assert((id == 0) || (id == 1));
-    return ((id == 0) ? -1 : 0);
+    return (id == 0) ? -1 : 0;
 }
 
 SDL_AudioDeviceID
@@ -1338,7 +1265,7 @@
             status = SDL_AUDIO_PLAYING;
         }
     }
-    return (status);
+    return status;
 }
 
 
@@ -1429,14 +1356,16 @@
         }
     }
 
+    free_device_list(&current_audio.outputDevices, &current_audio.outputDeviceCount);
+    free_device_list(&current_audio.inputDevices, &current_audio.inputDeviceCount);
+
     /* Free the driver data */
     current_audio.impl.Deinitialize();
-    free_device_list(&current_audio.outputDevices,
-                     &current_audio.outputDeviceCount);
-    free_device_list(&current_audio.inputDevices,
-                     &current_audio.inputDeviceCount);
-    SDL_memset(&current_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 @@
         }
     }
     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
--- a/src/audio/SDL_audiodev.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/SDL_audiodev.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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);
             }
-            close(audio_fd);
         }
     }
 }
@@ -68,11 +71,10 @@
     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 @@
             }
         }
     }
-    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: */
--- a/src/audio/SDL_audiodev_c.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/SDL_audiodev_c.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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: */
--- a/src/audio/SDL_sysaudio.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/SDL_sysaudio.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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_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 @@
     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 @@
 
     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 @@
 {
     /* * * */
     /* Data common to all devices */
+    SDL_AudioDeviceID id;
 
     /* The current audio specification (shared with audio thread) */
     SDL_AudioSpec spec;
@@ -125,15 +157,17 @@
     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 */
--- a/src/audio/alsa/SDL_alsa_audio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/alsa/SDL_alsa_audio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -320,7 +320,7 @@
                 /* 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 @@
 }
 
 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;
--- a/src/audio/android/SDL_androidaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/android/SDL_androidaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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;
 
--- a/src/audio/arts/SDL_artsaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/arts/SDL_artsaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -151,7 +151,7 @@
         /* 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 @@
 
     /* 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 @@
 }
 
 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;
--- a/src/audio/bsd/SDL_bsdaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/bsd/SDL_bsdaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
                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 @@
 
     /* 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 @@
 }
 
 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 @@
     impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf;
     impl->CloseDevice = BSDAUDIO_CloseDevice;
 
+    impl->AllowsArbitraryDeviceNames = 1;
+
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/coreaudio/SDL_coreaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/coreaudio/SDL_coreaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     }
 
 #if MACOSX_COREAUDIO
-typedef void (*addDevFn)(const char *name, AudioDeviceID devId, void *data);
+static const AudioObjectPropertyAddress devlist_address = {
+    kAudioHardwarePropertyDevices,
+    kAudioObjectPropertyScopeGlobal,
+    kAudioObjectPropertyElementMaster
+};
+
+typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data);
+
+typedef struct AudioDeviceList
+{
+    AudioDeviceID devid;
+    SDL_bool alive;
+    struct AudioDeviceList *next;
+} AudioDeviceList;
+
+static AudioDeviceList *output_devs = NULL;
+static AudioDeviceList *capture_devs = NULL;
 
-static void
-addToDevList(const char *name, AudioDeviceID devId, void *data)
+static SDL_bool
+add_to_internal_dev_list(const int iscapture, AudioDeviceID devId)
 {
-    SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
-    addfn(name);
+    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
+static void
+addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data)
 {
-    const char *findname;
-    AudioDeviceID devId;
-    int found;
-} FindDevIdData;
-
-static void
-findDevId(const char *name, 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 @@
     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 @@
     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 @@
         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 @@
         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 @@
                    ((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)
+{
+    AudioDeviceList *item = *list;
+    while (item) {
+        AudioDeviceList *next = item->next;
+        SDL_free(item);
+        item = next;
+    }
+    *list = NULL;
+}
+
+static void
+COREAUDIO_DetectDevices(void)
 {
-    build_device_list(iscapture, addToDevList, addfn);
+    build_device_list(SDL_TRUE, addToDevList, NULL);
+    build_device_list(SDL_FALSE, addToDevList, NULL);
+}
+
+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;
+        }
+    }
+
+    add_to_internal_dev_list(iscapture, devId);  /* new device, add it. */
+    SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId));
 }
 
-static int
-find_device_by_name(_THIS, const char *devname, int iscapture)
+static void
+reprocess_device_list(const int iscapture, AudioDeviceList **list)
 {
-    AudioDeviceID devid = 0;
-    OSStatus result = noErr;
-    UInt32 size = 0;
-    UInt32 alive = 0;
-    pid_t pid = 0;
-
-    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;
-        }
-        devid = data.devId;
+    AudioDeviceList *item;
+    AudioDeviceList *prev = NULL;
+    for (item = *list; item != NULL; item = item->next) {
+        item->alive = SDL_FALSE;
     }
 
-    addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
-    addr.mScope = iscapture ? kAudioDevicePropertyScopeInput :
-                    kAudioDevicePropertyScopeOutput;
+    build_device_list(iscapture, build_device_change_list, list);
 
-    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;
+    /* 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;
     }
-
-    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;
+/* 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 @@
 }
 
 
+#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 @@
     }
 }
 
+#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 @@
                                   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 @@
     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 @@
     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 @@
     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 @@
     "coreaudio", "CoreAudio", COREAUDIO_Init, 0
 };
 
+#endif /* SDL_AUDIO_DRIVER_COREAUDIO */
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/directsound/SDL_directsound.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/directsound/SDL_directsound.c	Mon Apr 06 15:26:37 2015 -0300
@@ -144,15 +144,22 @@
     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 @@
 }
 
 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 @@
     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 @@
     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. */
--- a/src/audio/disk/SDL_diskaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/disk/SDL_diskaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -71,7 +71,7 @@
 
     /* 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 @@
 }
 
 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 @@
     impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
     impl->CloseDevice = DISKAUD_CloseDevice;
 
+    impl->AllowsArbitraryDeviceNames = 1;
+
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/dsp/SDL_dspaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/dsp/SDL_dspaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 
 
 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 @@
     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 @@
     impl->GetDeviceBuf = DSP_GetDeviceBuf;
     impl->CloseDevice = DSP_CloseDevice;
 
+    impl->AllowsArbitraryDeviceNames = 1;
+
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/dummy/SDL_dummyaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/dummy/SDL_dummyaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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. */
 }
--- a/src/audio/emscripten/SDL_emscriptenaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/emscripten/SDL_emscriptenaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -151,12 +151,13 @@
 }
 
 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 @@
     /* 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 @@
             } 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({
--- a/src/audio/esd/SDL_esdaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/esd/SDL_esdaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -129,7 +129,7 @@
         /* 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 @@
 
     /* If we couldn't write, assume fatal error for now */
     if (written < 0) {
-        this->enabled = 0;
+        SDL_OpenedAudioDeviceDisconnected(this);
     }
 }
 
@@ -215,7 +215,7 @@
 
 
 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;
--- a/src/audio/fusionsound/SDL_fsaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/fusionsound/SDL_fsaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -143,7 +143,7 @@
                                       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 @@
 
 
 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;
--- a/src/audio/haiku/SDL_haikuaudio.cc	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/haiku/SDL_haikuaudio.cc	Mon Apr 06 15:26:37 2015 -0300
@@ -111,7 +111,7 @@
 
 
 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;
--- a/src/audio/nacl/SDL_naclaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/nacl/SDL_naclaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 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 @@
     /* 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 @@
     NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver",
     NACLAUD_Init, 0
 };
+
+#endif /* SDL_AUDIO_DRIVER_NACL */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/nas/SDL_nasaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/nas/SDL_nasaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -276,7 +276,7 @@
 }
 
 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;
--- a/src/audio/paudio/SDL_paudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/paudio/SDL_paudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -176,7 +176,7 @@
              * 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 @@
 
     /* 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 @@
 }
 
 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];
--- a/src/audio/psp/SDL_pspaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/psp/SDL_pspaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <stdio.h>
 #include <string.h>
@@ -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 @@
 
  /* SDL_AUDI */
 
+#endif /* SDL_AUDIO_DRIVER_PSP */
 
-
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/psp/SDL_pspaudio.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/psp/SDL_pspaudio.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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
--- a/src/audio/pulseaudio/SDL_pulseaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/pulseaudio/SDL_pulseaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <sys/types.h>
 #include <errno.h>
 #include <pulse/pulseaudio.h>
-#include <pulse/simple.h>
 
 #include "SDL_timer.h"
 #include "SDL_audio.h"
@@ -66,16 +66,14 @@
 
 
 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 @@
     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 @@
 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 @@
     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 @@
     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 @@
     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 @@
         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 @@
         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 @@
     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 @@
         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 @@
     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
 };
--- a/src/audio/pulseaudio/SDL_pulseaudio.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/pulseaudio/SDL_pulseaudio.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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;
 
--- a/src/audio/qsa/SDL_qsa_audio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/qsa/SDL_qsa_audio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 
     /* If we couldn't write, assume fatal error for now */
     if (towrite != 0) {
-        this->enabled = 0;
+        SDL_OpenedAudioDeviceDisconnected(this);
     }
 }
 
@@ -337,8 +346,9 @@
 }
 
 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 @@
     /* 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) {
+    if (device != NULL) {
+        /* Open requested audio device */
+        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 */
-        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 {
-        /* 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);
-        }
+        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 @@
 }
 
 static void
-QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
+QSA_DetectDevices(void)
 {
     uint32_t it;
     uint32_t cards;
@@ -656,8 +605,9 @@
         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 @@
                             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 @@
                 break;
             }
         }
-    } else {
+    }
+
+    {  /* capture devices */
         /* Capture devices enumeration requested */
         for (it = 0; it < cards; it++) {
             devices = 0;
@@ -744,7 +696,7 @@
                             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 {
--- a/src/audio/sndio/SDL_sndioaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/sndio/SDL_sndioaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -158,7 +158,7 @@
 
     /* 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 @@
 }
 
 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;
--- a/src/audio/sun/SDL_sunaudio.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/sun/SDL_sunaudio.c	Mon Apr 06 15:26:37 2015 -0300
@@ -56,9 +56,9 @@
 
 /* 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 @@
         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 @@
         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 @@
 }
 
 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 @@
     impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf;
     impl->CloseDevice = SUNAUDIO_CloseDevice;
 
+    impl->AllowsArbitraryDeviceNames = 1;
+
     return 1; /* this audio target is available. */
 }
 
--- a/src/audio/winmm/SDL_winmm.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/winmm/SDL_winmm.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
         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 @@
 }
 
 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 @@
     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:
--- a/src/audio/xaudio2/SDL_xaudio2.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/audio/xaudio2/SDL_xaudio2.c	Mon Apr 06 15:26:37 2015 -0300
@@ -126,16 +126,13 @@
 
 
 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 @@
         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 @@
 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 @@
 
     if (result != S_OK) {  /* uhoh, panic! */
         IXAudio2SourceVoice_FlushSourceBuffers(source);
-        this->enabled = 0;
+        SDL_OpenedAudioDeviceDisconnected(this);
     }
 }
 
@@ -289,7 +286,7 @@
 }
 
 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 @@
 
     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 @@
     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 @@
     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
 }
--- a/src/core/android/SDL_android.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/core/android/SDL_android.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     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 @@
  * 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 @@
     return s_AndroidExternalFilesPath;
 }
 
+jclass Android_JNI_GetActivityClass(void)
+{
+    return mActivityClass;
+}
+
 #endif /* __ANDROID__ */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/core/android/SDL_android.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/core/android/SDL_android.h	Mon Apr 06 15:26:37 2015 -0300
@@ -78,6 +78,7 @@
 #include <jni.h>
 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);
--- a/src/core/linux/SDL_ibus.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/core/linux/SDL_ibus.c	Mon Apr 06 15:26:37 2015 -0300
@@ -462,6 +462,9 @@
         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();
--- a/src/core/linux/SDL_udev.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/core/linux/SDL_udev.c	Mon Apr 06 15:26:37 2015 -0300
@@ -350,17 +350,19 @@
             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 */
         }
     }
--- a/src/dynapi/SDL_dynapi.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/dynapi/SDL_dynapi.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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
 
--- a/src/dynapi/SDL_dynapi_overrides.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/dynapi/SDL_dynapi_overrides.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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
--- a/src/dynapi/SDL_dynapi_procs.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/dynapi/SDL_dynapi_procs.h	Mon Apr 06 15:26:37 2015 -0300
@@ -623,3 +623,4 @@
 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)
--- a/src/events/SDL_events.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/events/SDL_events.c	Mon Apr 06 15:26:37 2015 -0300
@@ -75,12 +75,13 @@
     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 @@
 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_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_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_EventQ.count;
 
+    if (SDL_EventQ.count > SDL_EventQ.max_events_seen) {
+        SDL_EventQ.max_events_seen = SDL_EventQ.count;
+    }
+
     return 1;
 }
 
--- a/src/events/SDL_gesture.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/events/SDL_gesture.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 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 @@
     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 @@
     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"); */
--- a/src/events/SDL_mouse.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/events/SDL_mouse.c	Mon Apr 06 15:26:37 2015 -0300
@@ -293,9 +293,14 @@
         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 @@
 {
     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]);
--- a/src/events/SDL_quit.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/events/SDL_quit.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 #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 @@
 #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 @@
 #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)
--- a/src/filesystem/nacl/SDL_sysfilesystem.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/filesystem/nacl/SDL_sysfilesystem.c	Mon Apr 06 15:26:37 2015 -0300
@@ -38,4 +38,5 @@
     return NULL;
 }
 
-#endif /* __NACL__ */
\ No newline at end of file
+#endif /* SDL_FILESYSTEM_NACL */
+
--- a/src/haptic/linux/SDL_syshaptic.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/haptic/linux/SDL_syshaptic.c	Mon Apr 06 15:26:37 2015 -0300
@@ -288,8 +288,7 @@
     }
 
     item->fname = SDL_strdup(path);
-    if ( (item->fname == NULL) ) {
-        SDL_free(item->fname);
+    if (item->fname == NULL) {
         SDL_free(item);
         return -1;
     }
--- a/src/joystick/SDL_gamecontrollerdb.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/SDL_gamecontrollerdb.h	Mon Apr 06 15:26:37 2015 -0300
@@ -63,6 +63,8 @@
     "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 @@
     "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
 };
--- a/src/joystick/SDL_joystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/SDL_joystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -206,10 +206,6 @@
         valid = 1;
     }
 
-    if (joystick && joystick->closed) {
-        valid = 0;
-    }
-
     return valid;
 }
 
@@ -412,6 +408,7 @@
     }
 
     SDL_SYS_JoystickClose(joystick);
+    joystick->hwdata = NULL;
 
     joysticklist = SDL_joysticks;
     joysticklistprev = NULL;
@@ -668,7 +665,7 @@
 
         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 @@
             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;
--- a/src/joystick/SDL_sysjoystick.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/SDL_sysjoystick.h	Mon Apr 06 15:26:37 2015 -0300
@@ -53,8 +53,7 @@
 
     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 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);
 
--- a/src/joystick/android/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/android/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -467,7 +467,7 @@
 }
 
 /* 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 @@
 /* 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 @@
 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 */
--- a/src/joystick/android/SDL_sysjoystick_c.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/android/SDL_sysjoystick_c.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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"
--- a/src/joystick/bsd/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/bsd/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -558,8 +558,6 @@
     close(joy->hwdata->fd);
     SDL_free(joy->hwdata->path);
     SDL_free(joy->hwdata);
-
-    return;
 }
 
 void
--- a/src/joystick/darwin/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/darwin/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -138,7 +138,7 @@
 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 @@
     /* 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
-        }
     }
 
     device->send_open_event = 1;
@@ -446,9 +446,9 @@
         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 @@
 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 @@
             }
         }
     }
+
+	// 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 @@
 }
 
 /* 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 @@
 }
 
 /* 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 @@
     }
 
     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 @@
 void
 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
 {
-    joystick->closed = 1;
 }
 
 /* Function to perform any system-specific joystick related cleanup */
--- a/src/joystick/darwin/SDL_sysjoystick_c.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/darwin/SDL_sysjoystick_c.h	Mon Apr 06 15:26:37 2015 -0300
@@ -58,8 +58,7 @@
     recElement *firstButton;
     recElement *firstHat;
 
-    int removed;
-    int uncentered;
+    SDL_bool removed;
 
     int instance_id;
     SDL_JoystickGUID guid;
--- a/src/joystick/dummy/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/dummy/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -34,7 +34,7 @@
 int
 SDL_SYS_JoystickInit(void)
 {
-    return (0);
+    return 0;
 }
 
 int SDL_SYS_NumJoysticks()
@@ -61,7 +61,7 @@
 }
 
 /* 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 @@
 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 )
--- a/src/joystick/emscripten/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/emscripten/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -46,7 +46,7 @@
 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 @@
     }
 
     ++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 @@
     }
 #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 @@
         return 1;
     }
 
-    const int retval = item->device_instance;
     if (item->joystick) {
         item->joystick->hwdata = NULL;
     }
@@ -174,7 +177,9 @@
     }
 #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 @@
                                                       Emscripten_JoyStickConnected);
 
     if(retval != EMSCRIPTEN_RESULT_SUCCESS) {
+        SDL_SYS_JoystickQuit();
         return -1;
     }
 
@@ -222,12 +228,28 @@
                                                          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 @@
 {
 }
 
-// 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 @@
 /* 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 @@
 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 @@
                 }
             }
         }
-        item = item->next;
     }
 }
 
@@ -375,11 +378,6 @@
 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 @@
 
     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 */
--- a/src/joystick/emscripten/SDL_sysjoystick_c.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/emscripten/SDL_sysjoystick_c.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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"
--- a/src/joystick/haiku/SDL_haikujoystick.cc	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/haiku/SDL_haikujoystick.cc	Mon Apr 06 15:26:37 2015 -0300
@@ -106,7 +106,7 @@
     }
 
 /* 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 @@
             SDL_free(joystick->hwdata->new_hats);
             SDL_free(joystick->hwdata->new_axes);
             SDL_free(joystick->hwdata);
-            joystick->hwdata = NULL;
         }
     }
 
--- a/src/joystick/iphoneos/SDL_sysjoystick.m	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m	Mon Apr 06 15:26:37 2015 -0300
@@ -77,7 +77,7 @@
 }
 
 /* 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 @@
     @autoreleasepool {
         [motionManager stopAccelerometerUpdates];
     }
-    joystick->closed = 1;
 }
 
 /* Function to perform any system-specific joystick related cleanup */
--- a/src/joystick/linux/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/linux/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -142,13 +142,15 @@
 #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 @@
 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 @@
 
 
 /* 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 @@
 /* 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_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 */
--- a/src/joystick/psp/SDL_sysjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/psp/SDL_sysjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <pspctrl.h>
@@ -161,7 +164,7 @@
 }
 
 /* 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 @@
 {
     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 @@
 /* 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 @@
     return guid;
 }
 
+#endif /* SDL_JOYSTICK_PSP */
+
 /* vim: ts=4 sw=4
  */
--- a/src/joystick/windows/SDL_mmjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/windows/SDL_mmjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -210,7 +210,7 @@
 }
 
 /* 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 @@
 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 */
--- a/src/joystick/windows/SDL_windowsjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/joystick/windows/SDL_windowsjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -446,7 +446,7 @@
 }
 
 /* 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 @@
 
     /* 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_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 @@
     }
 
     if (joystick->hwdata->removed) {
-        joystick->closed = SDL_TRUE;
-        joystick->uncentered = SDL_TRUE;
+        joystick->force_recentering = SDL_TRUE;
     }
 }
 
@@ -512,10 +510,7 @@
         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 */
--- a/src/main/psp/SDL_psp_main.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/main/psp/SDL_psp_main.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <pspkernel.h>
@@ -61,3 +64,7 @@
     (void)SDL_main(argc, argv);
     return 0;
 }
+
+#endif /* __PSP__ */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/main/windows/SDL_windows_main.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/main/windows/SDL_windows_main.c	Mon Apr 06 15:26:37 2015 -0300
@@ -109,13 +109,16 @@
 }
 
 #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 @@
     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 @@
 #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 @@
     ParseCommandLine(cmdline, argv);
 
     /* Run the main program */
-    console_main(argc, argv);
+    main_utf8(argc, argv);
 
     SDL_stack_free(argv);
 
--- a/src/render/direct3d11/SDL_render_d3d11.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/render/direct3d11/SDL_render_d3d11.c	Mon Apr 06 15:26:37 2015 -0300
@@ -829,9 +829,24 @@
     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:
--- a/src/render/opengl/SDL_render_gl.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/render/opengl/SDL_render_gl.c	Mon Apr 06 15:26:37 2015 -0300
@@ -342,9 +342,11 @@
 
     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);
         }
     }
--- a/src/test/SDL_test_common.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/test/SDL_test_common.c	Mon Apr 06 15:26:37 2015 -0300
@@ -1204,10 +1204,10 @@
                 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);
--- a/src/thread/psp/SDL_syscond.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/thread/psp/SDL_syscond.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
 }
 
+#endif /* SDL_THREAD_PSP */
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/thread/psp/SDL_sysmutex.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/thread/psp/SDL_sysmutex.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 #endif /* SDL_THREADS_DISABLED */
 }
 
+#endif /* SDL_THREAD_PSP */
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/thread/psp/SDL_syssem.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/thread/psp/SDL_syssem.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     return 0;
 }
 
+#endif /* SDL_THREAD_PSP */
+
 /* vim: ts=4 sw=4
  */
--- a/src/thread/psp/SDL_systhread.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/thread/psp/SDL_systhread.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 
 }
 
+#endif /* SDL_THREAD_PSP */
+
 /* vim: ts=4 sw=4
  */
--- a/src/timer/psp/SDL_systimer.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/timer/psp/SDL_systimer.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     sceKernelDelayThreadCB(ms * 1000);
 }
 
+#endif /* SDL_TIMERS_PSP */
+
 /* vim: ts=4 sw=4
  */
--- a/src/video/SDL_bmp.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/SDL_bmp.c	Mon Apr 06 15:26:37 2015 -0300
@@ -306,16 +306,19 @@
             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;
         }
--- a/src/video/SDL_clipboard.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/SDL_clipboard.c	Mon Apr 06 15:26:37 2015 -0300
@@ -29,6 +29,10 @@
 {
     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_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_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 {
--- a/src/video/SDL_fillrect.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/SDL_fillrect.c	Mon Apr 06 15:26:37 2015 -0300
@@ -251,6 +251,10 @@
         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 */
--- a/src/video/SDL_sysvideo.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/SDL_sysvideo.h	Mon Apr 06 15:26:37 2015 -0300
@@ -274,6 +274,7 @@
     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 @@
         int flags;
         int profile_mask;
         int share_with_current_context;
+        int release_behavior;
         int framebuffer_srgb_capable;
         int retained_backing;
         int driver_loaded;
--- a/src/video/SDL_video.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/SDL_video.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     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 @@
 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 @@
         } 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_GetWindowGrab(SDL_Window * window)
 {
     CHECK_WINDOW_MAGIC(window, SDL_FALSE);
-
-    return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
+    SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0));
+    return window == _this->grabbed_window;
+}
+
+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 @@
 #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 @@
     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;
@@ -2847,6 +2877,13 @@
         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:
         {
             GLint bits = 0;
--- a/src/video/android/SDL_androidevents.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/android/SDL_androidevents.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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() 
--- a/src/video/android/SDL_androidmessagebox.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/android/SDL_androidmessagebox.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/android/SDL_androidmouse.c	Mon Apr 06 15:26:37 2015 -0300
@@ -0,0 +1,84 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  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: */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/android/SDL_androidmouse.h	Mon Apr 06 15:26:37 2015 -0300
@@ -0,0 +1,31 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  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: */
--- a/src/video/android/SDL_androidtouch.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/android/SDL_androidtouch.c	Mon Apr 06 15:26:37 2015 -0300
@@ -24,13 +24,12 @@
 
 #include <android/log.h>
 
+#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 @@
     *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_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 @@
         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;
     }
--- a/src/video/android/SDL_androidtouch.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/android/SDL_androidtouch.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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: */
--- a/src/video/android/SDL_androidvideo.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/android/SDL_androidvideo.c	Mon Apr 06 15:26:37 2015 -0300
@@ -86,6 +86,7 @@
 static void
 Android_DeleteDevice(SDL_VideoDevice * device)
 {
+    SDL_free(device->driverdata);
     SDL_free(device);
 }
 
@@ -187,6 +188,7 @@
 void
 Android_VideoQuit(_THIS)
 {
+    Android_QuitTouch();
 }
 
 /* This function gets called before VideoInit() */
--- a/src/video/cocoa/SDL_cocoaevents.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/cocoa/SDL_cocoaevents.h	Mon Apr 06 15:26:37 2015 -0300
@@ -25,6 +25,7 @@
 
 extern void Cocoa_RegisterApp(void);
 extern void Cocoa_PumpEvents(_THIS);
+extern void Cocoa_SuspendScreenSaver(_THIS);
 
 #endif /* _SDL_cocoaevents_h */
 
--- a/src/video/cocoa/SDL_cocoaevents.m	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/cocoa/SDL_cocoaevents.m	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 { @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 @@
 { @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 @@
     }
 }}
 
+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: */
--- a/src/video/cocoa/SDL_cocoavideo.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/cocoa/SDL_cocoavideo.h	Mon Apr 06 15:26:37 2015 -0300
@@ -26,6 +26,7 @@
 #include "SDL_opengl.h"
 
 #include <ApplicationServices/ApplicationServices.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
 #include <Cocoa/Cocoa.h>
 
 #include "SDL_keycode.h"
@@ -51,6 +52,9 @@
     SDLTranslatorResponder *fieldEdit;
     NSInteger clipboard_count;
     Uint32 screensaver_activity;
+    BOOL screensaver_use_iopm;
+    IOPMAssertionID screensaver_assertion;
+
 } SDL_VideoData;
 
 /* Utility functions */
--- a/src/video/cocoa/SDL_cocoavideo.m	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/cocoa/SDL_cocoavideo.m	Mon Apr 06 15:26:37 2015 -0300
@@ -76,6 +76,7 @@
     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 @@
     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;
 }
 
--- a/src/video/cocoa/SDL_cocoawindow.m	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/cocoa/SDL_cocoawindow.m	Mon Apr 06 15:26:37 2015 -0300
@@ -374,7 +374,6 @@
     NSNotificationCenter *center;
     NSWindow *window = _data->nswindow;
     NSView *view = [window contentView];
-    NSArray *windows = nil;
 
     center = [NSNotificationCenter defaultCenter];
 
@@ -402,25 +401,6 @@
     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
--- a/src/video/dummy/SDL_nullvideo.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/dummy/SDL_nullvideo.c	Mon Apr 06 15:26:37 2015 -0300
@@ -82,7 +82,6 @@
     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
     if (!device) {
         SDL_OutOfMemory();
-        SDL_free(device);
         return (0);
     }
 
--- a/src/video/emscripten/SDL_emscriptenevents.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/emscripten/SDL_emscriptenevents.c	Mon Apr 06 15:26:37 2015 -0300
@@ -296,7 +296,7 @@
     return SDL_TRUE;
 }
 
-int
+EM_BOOL
 Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -322,7 +322,7 @@
     return 0;
 }
 
-int
+EM_BOOL
 Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -344,7 +344,7 @@
     return 1;
 }
 
-int
+EM_BOOL
 Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -352,7 +352,7 @@
     return 1;
 }
 
-int
+EM_BOOL
 Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -360,7 +360,7 @@
     return 1;
 }
 
-int
+EM_BOOL
 Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -368,7 +368,7 @@
     return 1;
 }
 
-int
+EM_BOOL
 Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
 {
     /*SDL_WindowData *window_data = userData;*/
@@ -404,7 +404,7 @@
     return 1;
 }
 
-int
+EM_BOOL
 Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
 {
     Uint32 scancode;
@@ -443,16 +443,17 @@
             || 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 @@
     return 0;
 }
 
-int
+EM_BOOL
 Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -554,7 +555,7 @@
     return 0;
 }
 
-int
+EM_BOOL
 Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData)
 {
     SDL_WindowData *window_data = userData;
@@ -621,10 +622,15 @@
     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);
 
--- a/src/video/emscripten/SDL_emscriptenframebuffer.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/emscripten/SDL_emscriptenframebuffer.c	Mon Apr 06 15:26:37 2015 -0300
@@ -63,7 +63,7 @@
     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 */
--- a/src/video/nacl/SDL_naclevents.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/nacl/SDL_naclevents.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
     }
   }
 }
+
+#endif /* SDL_VIDEO_DRIVER_NACL */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/psp/SDL_pspevents.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/psp/SDL_pspevents.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 
 /* end of SDL_pspevents.c ... */
 
+#endif /* SDL_VIDEO_DRIVER_PSP */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/psp/SDL_pspgl.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/psp/SDL_pspgl.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <stdlib.h>
 #include <string.h>
@@ -203,3 +206,6 @@
     return;
 }
 
+#endif /* SDL_VIDEO_DRIVER_PSP */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/psp/SDL_pspmouse.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/psp/SDL_pspmouse.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <stdio.h>
 
@@ -33,3 +35,7 @@
 struct WMcursor {
     int unused;
 };
+
+#endif /* SDL_VIDEO_DRIVER_PSP */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/psp/SDL_pspvideo.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/psp/SDL_pspvideo.c	Mon Apr 06 15:26:37 2015 -0300
@@ -66,7 +66,7 @@
     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 @@
         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();
--- a/src/video/psp/SDL_pspvideo.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/psp/SDL_pspvideo.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <GLES/egl.h>
 
@@ -97,6 +97,6 @@
 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: */
--- a/src/video/wayland/SDL_waylandwindow.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/wayland/SDL_waylandwindow.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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,
--- a/src/video/windows/SDL_windowsevents.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/windows/SDL_windowsevents.c	Mon Apr 06 15:26:37 2015 -0300
@@ -559,10 +559,11 @@
 
             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);
+                    }
                 }
             }
         }
--- a/src/video/windows/SDL_windowsopengl.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/windows/SDL_windowsopengl.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
         _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 @@
             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 @@
         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 */
--- a/src/video/windows/SDL_windowsopengl.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/windows/SDL_windowsopengl.h	Mon Apr 06 15:26:37 2015 -0300
@@ -30,6 +30,7 @@
     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);
--- a/src/video/windows/SDL_windowswindow.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/windows/SDL_windowswindow.c	Mon Apr 06 15:26:37 2015 -0300
@@ -643,10 +643,11 @@
 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",
--- a/src/video/winrt/SDL_winrtopengles.cpp	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/winrt/SDL_winrtopengles.cpp	Mon Apr 06 15:26:37 2015 -0300
@@ -36,10 +36,17 @@
 
 /* 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 @@
         Microsoft::WRL::ComPtr<IUnknown> 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 @@
             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)
+#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) {
-        return SDL_SetError("Could not initialize EGL");
+            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;
--- a/src/video/x11/SDL_x11events.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11events.c	Mon Apr 06 15:26:37 2015 -0300
@@ -677,8 +677,17 @@
                 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 @@
 #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 @@
                    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 @@
 {
     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);
--- a/src/video/x11/SDL_x11messagebox.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11messagebox.c	Mon Apr 06 15:26:37 2015 -0300
@@ -31,8 +31,8 @@
 #include <locale.h>
 
 
-#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 <sys/types.h>
@@ -366,6 +366,7 @@
     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_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 @@
     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. */
     }
--- a/src/video/x11/SDL_x11modes.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11modes.c	Mon Apr 06 15:26:37 2015 -0300
@@ -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 @@
 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;
--- a/src/video/x11/SDL_x11opengl.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11opengl.c	Mon Apr 06 15:26:37 2015 -0300
@@ -122,6 +122,13 @@
 #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 <dlfcn.h>
@@ -279,14 +286,14 @@
     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 @@
 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 @@
             (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 @@
         _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 @@
 
     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 @@
     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 @@
             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;
-                }
-
-                attribs[iattr++] = 0;
+            /* SDL flags match GLX flags */
+            if( _this->gl_config.flags != 0 ) {
+                attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
+                attribs[iattr++] = _this->gl_config.flags;
+            }
 
-                /* 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;
-                } else {
-                    int glxAttribs[64];
+            /* 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;
+            }
 
-                    /* 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);
+            attribs[iattr++] = 0;
 
-                    glXChooseFBConfig =
-                        (GLXFBConfig *
-                         (*)(Display *, int, const int *,
-                             int *)) _this->gl_data->
-                        glXGetProcAddress((GLubyte *) "glXChooseFBConfig");
+            /* 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];
 
-                    X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE);
+                /* Create a GL 3.x context */
+                GLXFBConfig *framebuffer_config = NULL;
+                int fbcount = 0;
 
-                    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,
+                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 {
+                    context = _this->gl_data->glXCreateContextAttribsARB(display,
                                                     framebuffer_config[0],
                                                     share_context, True, attribs);
-                        _this->gl_data->glXDestroyContext(display,
-                                                          temp_context);
-                    }
                 }
             }
         }
--- a/src/video/x11/SDL_x11opengl.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11opengl.h	Mon Apr 06 15:26:37 2015 -0300
@@ -35,11 +35,14 @@
     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);
--- a/src/video/x11/SDL_x11video.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11video.h	Mon Apr 06 15:26:37 2015 -0300
@@ -112,6 +112,7 @@
     SDL_Scancode key_layout[256];
     SDL_bool selection_waiting;
 
+    Uint32 last_mode_change_deadline;
 } SDL_VideoData;
 
 extern SDL_bool X11_UseDirectColorVisuals(void);
--- a/src/video/x11/SDL_x11window.h	Sat Jan 24 23:58:07 2015 -0400
+++ b/src/video/x11/SDL_x11window.h	Mon Apr 06 15:26:37 2015 -0300
@@ -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 <EGL/egl.h>
--- a/test/Makefile.in	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/Makefile.in	Mon Apr 06 15:26:37 2015 -0300
@@ -38,6 +38,7 @@
 	testloadso$(EXE) \
 	testlock$(EXE) \
 	testmultiaudio$(EXE) \
+	testaudiohotplug$(EXE) \
 	testnative$(EXE) \
 	testoverlay2$(EXE) \
 	testplatform$(EXE) \
@@ -105,6 +106,9 @@
 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)
 
--- a/test/loopwave.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/loopwave.c	Mon Apr 06 15:26:37 2015 -0300
@@ -29,7 +29,6 @@
 #endif
 
 #include "SDL.h"
-#include "SDL_audio.h"
 
 struct
 {
--- a/test/loopwavequeue.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/loopwavequeue.c	Mon Apr 06 15:26:37 2015 -0300
@@ -15,6 +15,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten/emscripten.h>
+#endif
+
 #include "SDL.h"
 
 #if HAVE_SIGNAL_H
@@ -45,10 +49,32 @@
     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 @@
     /* 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();
--- a/test/relative_mode.markdown	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/relative_mode.markdown	Mon Apr 06 15:26:37 2015 -0300
@@ -37,9 +37,11 @@
 
     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)
--- a/test/testatomic.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testatomic.c	Mon Apr 06 15:26:37 2015 -0300
@@ -12,9 +12,6 @@
 #include <stdio.h>
 
 #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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testaudiohotplug.c	Mon Apr 06 15:26:37 2015 -0300
@@ -0,0 +1,183 @@
+/*
+  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
+
+  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 <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef __EMSCRIPTEN__
+#include <emscripten/emscripten.h>
+#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: */
--- a/test/testerror.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testerror.c	Mon Apr 06 15:26:37 2015 -0300
@@ -17,7 +17,6 @@
 #include <signal.h>
 
 #include "SDL.h"
-#include "SDL_thread.h"
 
 static int alive = 0;
 
--- a/test/testfile.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testfile.c	Mon Apr 06 15:26:37 2015 -0300
@@ -22,7 +22,6 @@
 #endif
 
 #include "SDL.h"
-#include "SDL_endian.h"
 
 
 #include <stdio.h>
--- a/test/testgamecontroller.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testgamecontroller.c	Mon Apr 06 15:26:37 2015 -0300
@@ -163,6 +163,10 @@
     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 @@
 #endif
 
     SDL_DestroyRenderer(screen);
+    screen = NULL;
+    background = NULL;
+    button = NULL;
+    axis = NULL;
     SDL_DestroyWindow(window);
     return retval;
 }
--- a/test/testhaptic.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testhaptic.c	Mon Apr 06 15:26:37 2015 -0300
@@ -22,8 +22,6 @@
 
 #ifndef SDL_HAPTIC_DISABLED
 
-#include "SDL_haptic.h"
-
 static SDL_Haptic *haptic;
 
 
--- a/test/testhotplug.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testhotplug.c	Mon Apr 06 15:26:37 2015 -0300
@@ -17,7 +17,6 @@
 #include <string.h>
 
 #include "SDL.h"
-#include "SDL_haptic.h"
 
 #if !defined SDL_JOYSTICK_DISABLED && !defined SDL_HAPTIC_DISABLED
 
--- a/test/testjoystick.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testjoystick.c	Mon Apr 06 15:26:37 2015 -0300
@@ -56,6 +56,12 @@
 
         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 @@
     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 @@
 #endif
 
     SDL_DestroyRenderer(screen);
+    screen = NULL;
     SDL_DestroyWindow(window);
     return retval;
 }
--- a/test/testlock.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testlock.c	Mon Apr 06 15:26:37 2015 -0300
@@ -19,8 +19,6 @@
 #include <stdlib.h> /* for atexit() */
 
 #include "SDL.h"
-#include "SDL_mutex.h"
-#include "SDL_thread.h"
 
 static SDL_mutex *mutex = NULL;
 static SDL_threadID mainthread;
--- a/test/testmessage.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testmessage.c	Mon Apr 06 15:26:37 2015 -0300
@@ -17,7 +17,6 @@
 #include <signal.h>
 
 #include "SDL.h"
-#include "SDL_thread.h"
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
 static void
--- a/test/testplatform.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testplatform.c	Mon Apr 06 15:26:37 2015 -0300
@@ -13,9 +13,6 @@
 #include <stdio.h>
 
 #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 @@
 #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,
--- a/test/testrelative.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testrelative.c	Mon Apr 06 15:26:37 2015 -0300
@@ -49,12 +49,20 @@
         }
     }
     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);
--- a/test/testrumble.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testrumble.c	Mon Apr 06 15:26:37 2015 -0300
@@ -33,8 +33,6 @@
 
 #ifndef SDL_HAPTIC_DISABLED
 
-#include "SDL_haptic.h"
-
 static SDL_Haptic *haptic;
 
 
--- a/test/testsem.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testsem.c	Mon Apr 06 15:26:37 2015 -0300
@@ -17,7 +17,6 @@
 #include <signal.h>
 
 #include "SDL.h"
-#include "SDL_thread.h"
 
 #define NUM_THREADS 10
 
--- a/test/testthread.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/testthread.c	Mon Apr 06 15:26:37 2015 -0300
@@ -17,7 +17,6 @@
 #include <signal.h>
 
 #include "SDL.h"
-#include "SDL_thread.h"
 
 static SDL_TLSID tls;
 static int alive = 0;
--- a/test/torturethread.c	Sat Jan 24 23:58:07 2015 -0400
+++ b/test/torturethread.c	Mon Apr 06 15:26:37 2015 -0300
@@ -18,7 +18,6 @@
 #include <string.h>
 
 #include "SDL.h"
-#include "SDL_thread.h"
 
 #define NUMTHREADS 10