diff --git a/.hgignore b/.hgignore index c16de7595..489f09a64 100644 --- a/.hgignore +++ b/.hgignore @@ -8,6 +8,9 @@ Makefile sdl-config SDL2.spec build +Build +*xcuserdata* +*xcworkspacedata* # for Xcode *.orig @@ -72,20 +75,26 @@ test/config.status test/Makefile test/SDL2.dll test/checkkeys +test/controllermap test/loopwave test/loopwavequeue test/testatomic +test/testaudiohotplug test/testaudioinfo test/testautomation test/testdraw2 +test/testdrawchessboard +test/testdropfile test/testerror test/testfile test/testgamecontroller test/testgesture test/testgl2 test/testgles +test/testgles2 test/testhaptic test/testhittesting +test/testhotplug test/testiconv test/testime test/testintersections @@ -115,6 +124,7 @@ test/teststreaming test/testthread test/testtimer test/testver +test/testviewport test/testwm2 test/torturethread test/*.exe diff --git a/CMakeLists.txt b/CMakeLists.txt index b5e560f03..edd649c7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the SDL source code and call cmake from there") endif() -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 2.8) project(SDL2 C) include(CheckFunctionExists) include(CheckLibraryExists) @@ -117,6 +117,12 @@ else() set(UNIX_OR_MAC_SYS OFF) endif() +if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN) # JavaScript does not yet have threading support, so disable pthreads when building for Emscripten. + set(SDL_PTHREADS_ENABLED_BY_DEFAULT ON) +else() + set(SDL_PTHREADS_ENABLED_BY_DEFAULT OFF) +endif() + # Default option knobs if(APPLE OR ARCH_64) set(OPT_DEF_SSEMATH ON) @@ -144,7 +150,7 @@ if("$ENV{CFLAGS}" STREQUAL "") if(USE_GCC OR USE_CLANG) set(CMAKE_C_FLAGS "-g -O3") endif() -else("$ENV{CFLAGS}" STREQUAL "") +else() set(CMAKE_C_FLAGS "$ENV{CFLAGS}") list(APPEND EXTRA_CFLAGS "$ENV{CFLAGS}") endif() @@ -161,7 +167,7 @@ if(MSVC) if(${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif() - endforeach(flag_var) + endforeach() endif() endif() @@ -170,13 +176,19 @@ endif() set(SDL_LIBS "-lSDL2") set(SDL_CFLAGS "") +# Emscripten toolchain has a nonempty default value for this, and the checks +# in this file need to change that, so remember the original value, and +# restore back to that afterwards. For check_function_exists() to work in +# Emscripten, this value must be at its default value. +set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + if(CYGWIN) # We build SDL on cygwin without the UNIX emulation layer include_directories("-I/usr/include/mingw") set(CMAKE_REQUIRED_FLAGS "-mno-cygwin") check_c_source_compiles("int main(int argc, char **argv) {}" HAVE_GCC_NO_CYGWIN) - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) if(HAVE_GCC_NO_CYGWIN) list(APPEND EXTRA_LDFLAGS "-mno-cygwin") list(APPEND SDL_LIBS "-mno-cygwin") @@ -188,12 +200,31 @@ add_definitions(-DUSING_GENERATED_CONFIG_H) # General includes include_directories(${SDL2_BINARY_DIR}/include ${SDL2_SOURCE_DIR}/include) +# All these ENABLED_BY_DEFAULT vars will default to ON if not specified, so +# you only need to have a platform override them if they are disabling. +set(OPT_DEF_ASM TRUE) +if(EMSCRIPTEN) + # Set up default values for the currently supported set of subsystems: + # Emscripten/Javascript does not have assembly support, a dynamic library + # loading architecture, low-level CPU inspection or multithreading. + set(OPT_DEF_ASM FALSE) + set(SDL_SHARED_ENABLED_BY_DEFAULT OFF) + set(SDL_ATOMIC_ENABLED_BY_DEFAULT OFF) + set(SDL_THREADS_ENABLED_BY_DEFAULT OFF) + set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF) + set(SDL_CPUINFO_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) - option(SDL_${_OPT} "Enable the ${_SUB} subsystem" ON) + if (NOT DEFINED SDL_${_OPT}_ENABLED_BY_DEFAULT) + set(SDL_${_OPT}_ENABLED_BY_DEFAULT ON) + endif() + option(SDL_${_OPT} "Enable the ${_SUB} subsystem" ${SDL_${_OPT}_ENABLED_BY_DEFAULT}) endforeach() option_string(ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto") @@ -212,13 +243,13 @@ set_option(DUMMYAUDIO "Support the dummy audio driver" ON) set_option(VIDEO_DIRECTFB "Use DirectFB video driver" OFF) dep_option(DIRECTFB_SHARED "Dynamically load directfb support" ON "VIDEO_DIRECTFB" OFF) set_option(FUSIONSOUND "Use FusionSound audio driver" OFF) -dep_option(FUSIONSOUND_SHARED "Dynamically load fusionsound audio support" ON "FUSIONSOUND_SHARED" OFF) +dep_option(FUSIONSOUND_SHARED "Dynamically load fusionsound audio support" ON "FUSIONSOUND" OFF) 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" ${UNIX_OR_MAC_SYS}) +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" ON) +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) @@ -236,7 +267,10 @@ set_option(CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" O set_option(INPUT_TSLIB "Use the Touchscreen library for input" ${UNIX_SYS}) set_option(VIDEO_X11 "Use X11 video driver" ${UNIX_SYS}) set_option(VIDEO_WAYLAND "Use Wayland video driver" ${UNIX_SYS}) +dep_option(WAYLAND_SHARED "Dynamically load Wayland support" ON "VIDEO_WAYLAND" OFF) +dep_option(VIDEO_WAYLAND_QT_TOUCH "QtWayland server support for Wayland video driver" ON "VIDEO_WAYLAND" OFF) set_option(VIDEO_MIR "Use Mir video driver" ${UNIX_SYS}) +dep_option(MIR_SHARED "Dynamically load Mir support" ON "VIDEO_MIR" OFF) set_option(VIDEO_RPI "Use Raspberry Pi video driver" ${UNIX_SYS}) dep_option(X11_SHARED "Dynamically load X11 support" ON "VIDEO_X11" OFF) set(SDL_X11_OPTIONS Xcursor Xinerama XInput Xrandr Xscrnsaver XShape Xvm) @@ -251,7 +285,7 @@ set_option(VIDEO_VIVANTE "Use Vivante EGL video driver" ${UNIX_SYS}) # TODO: We should (should we?) respect cmake's ${BUILD_SHARED_LIBS} flag here # The options below are for compatibility to configure's default behaviour. -set(SDL_SHARED ON CACHE BOOL "Build a shared version of the library") +set(SDL_SHARED ${SDL_SHARED_ENABLED_BY_DEFAULT} CACHE BOOL "Build a shared version of the library") set(SDL_STATIC ON CACHE BOOL "Build a static version of the library") # General source files @@ -317,7 +351,7 @@ if(USE_GCC OR USE_CLANG) set(CMAKE_REQUIRED_FLAGS "-mpreferred-stack-boundary=2") check_c_source_compiles("int x = 0; int main(int argc, char **argv) {}" HAVE_GCC_PREFERRED_STACK_BOUNDARY) - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden -Werror") check_c_source_compiles(" @@ -328,7 +362,7 @@ if(USE_GCC OR USE_CLANG) if(HAVE_GCC_FVISIBILITY) list(APPEND EXTRA_CFLAGS "-fvisibility=hidden") endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) check_c_compiler_flag(-Wall HAVE_GCC_WALL) if(HAVE_GCC_WALL) @@ -376,7 +410,7 @@ if(ASSEMBLY) if(HAVE_MMX) list(APPEND EXTRA_CFLAGS "-mmmx") endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) endif() if(3DNOW) @@ -393,7 +427,7 @@ if(ASSEMBLY) if(HAVE_3DNOW) list(APPEND EXTRA_CFLAGS "-m3dnow") endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) endif() if(SSE) @@ -416,7 +450,7 @@ if(ASSEMBLY) if(HAVE_SSE) list(APPEND EXTRA_CFLAGS "-msse") endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) endif() if(SSE2) @@ -439,7 +473,7 @@ if(ASSEMBLY) if(HAVE_SSE2) list(APPEND EXTRA_CFLAGS "-msse2") endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) endif() if(SSEMATH) @@ -464,7 +498,7 @@ if(ASSEMBLY) return vec_splat_u32(0); } int main(int argc, char **argv) { }" HAVE_ALTIVEC) - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) if(HAVE_ALTIVEC OR HAVE_ALTIVEC_H_HDR) set(HAVE_ALTIVEC TRUE) # if only HAVE_ALTIVEC_H_HDR is set list(APPEND EXTRA_CFLAGS "-maltivec") @@ -486,7 +520,7 @@ if(ASSEMBLY) set(SDL_ASSEMBLY_ROUTINES 1) endif() # TODO: -#else(ASSEMBLY) +#else() # if(USE_GCC OR USE_CLANG) # list(APPEND EXTRA_CFLAGS "-mno-sse" "-mno-sse2" "-mno-mmx") # endif() @@ -518,7 +552,7 @@ if(LIBC) set(HAVE_M_PI 1) add_definitions(-D_USE_MATH_DEFINES) # needed for M_PI set(STDC_HEADERS 1) - else(WINDOWS AND NOT MINGW) + else() set(HAVE_LIBC TRUE) check_include_file(sys/types.h HAVE_SYS_TYPES_H) foreach(_HEADER @@ -555,7 +589,7 @@ if(LIBC) set(CMAKE_REQUIRED_LIBRARIES m) foreach(_FN atan atan2 ceil copysign cos cosf fabs floor log pow scalbn sin - sinf sqrt sqrtf tan tanf) + sinf sqrt sqrtf tan tanf acos asin) string(TOUPPER ${_FN} _UPPER) set(_HAVEVAR "HAVE_${_UPPER}") check_function_exists("${_FN}" ${_HAVEVAR}) @@ -567,11 +601,20 @@ if(LIBC) check_library_exists(iconv iconv_open "" HAVE_LIBICONV) if(HAVE_LIBICONV) list(APPEND EXTRA_LIBS iconv) + set(HAVE_ICONV 1) + endif() + + if(NOT APPLE) + check_include_file(alloca.h HAVE_ALLOCA_H) + check_function_exists(alloca HAVE_ALLOCA) + else() + set(HAVE_ALLOCA_H 1) + set(HAVE_ALLOCA 1) endif() check_struct_has_member("struct sigaction" "sa_sigaction" "signal.h" HAVE_SA_SIGACTION) endif() -else(LIBC) +else() if(WINDOWS) set(HAVE_STDARG_H 1) set(HAVE_STDDEF_H 1) @@ -642,7 +685,49 @@ if(SDL_VIDEO) endif() # Platform-specific options and settings -if(UNIX AND NOT APPLE) +if(EMSCRIPTEN) + # Hide noisy warnings that intend to aid mostly during initial stages of porting a new + # project. Uncomment at will for verbose cross-compiling -I/../ path info. + add_definitions(-Wno-warn-absolute-paths) + if(SDL_AUDIO) + set(SDL_AUDIO_DRIVER_EMSCRIPTEN 1) + file(GLOB EM_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EM_AUDIO_SOURCES}) + set(HAVE_SDL_AUDIO TRUE) + endif() + if(SDL_FILESYSTEM) + set(SDL_FILESYSTEM_EMSCRIPTEN 1) + file(GLOB EM_FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EM_FILESYSTEM_SOURCES}) + set(HAVE_SDL_FILESYSTEM TRUE) + endif() + if(SDL_JOYSTICK) + set(SDL_JOYSTICK_EMSCRIPTEN 1) + file(GLOB EM_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EM_JOYSTICK_SOURCES}) + set(HAVE_SDL_JOYSTICK TRUE) + endif() + if(SDL_POWER) + set(SDL_POWER_EMSCRIPTEN 1) + file(GLOB EM_POWER_SOURCES ${SDL2_SOURCE_DIR}/src/power/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EM_POWER_SOURCES}) + set(HAVE_SDL_POWER TRUE) + endif() + if(SDL_VIDEO) + set(SDL_VIDEO_DRIVER_EMSCRIPTEN 1) + file(GLOB EM_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EM_VIDEO_SOURCES}) + set(HAVE_SDL_VIDEO TRUE) + + #enable gles + if(VIDEO_OPENGLES) + set(SDL_VIDEO_OPENGL_EGL 1) + set(HAVE_VIDEO_OPENGLES TRUE) + set(SDL_VIDEO_OPENGL_ES2 1) + set(SDL_VIDEO_RENDER_OGL_ES2 1) + endif() + endif() +elseif(UNIX AND NOT APPLE) if(SDL_AUDIO) if(SYSV5 OR SOLARIS OR HPUX) set(SDL_AUDIO_DRIVER_SUNAUDIO 1) @@ -752,7 +837,7 @@ if(UNIX AND NOT APPLE) if(FOUND_CLOCK_GETTIME) list(APPEND EXTRA_LIBS rt) set(HAVE_CLOCK_GETTIME 1) - else(FOUND_CLOCK_GETTIME) + else() check_library_exists(c clock_gettime "" FOUND_CLOCK_GETTIME) if(FOUND_CLOCK_GETTIME) set(HAVE_CLOCK_GETTIME 1) @@ -829,7 +914,7 @@ elseif(WINDOWS) link_directories($ENV{DXSDK_DIR}\\lib\\${PROCESSOR_ARCH}) include_directories($ENV{DXSDK_DIR}\\Include) endif() - set(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) endif() if(SDL_AUDIO) @@ -978,7 +1063,7 @@ elseif(APPLE) endif() if(SDL_AUDIO) - set(MACOSX_COREAUDIO 1) + set(SDL_AUDIO_DRIVER_COREAUDIO 1) file(GLOB AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/coreaudio/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${AUDIO_SOURCES}) set(HAVE_SDL_AUDIO TRUE) @@ -1068,10 +1153,6 @@ elseif(APPLE) set(SDL_VIDEO_OPENGL 1) set(SDL_VIDEO_OPENGL_CGL 1) set(SDL_VIDEO_RENDER_OGL 1) - if(DARWIN) - find_library(OpenGL_LIBRARY OpenGL) - list(APPEND EXTRA_LIBRARIES ${OpenGL_LIBRARY}) - endif() set(HAVE_VIDEO_OPENGL TRUE) endif() endif() @@ -1193,14 +1274,14 @@ if(NOT WINDOWS OR CYGWIN) if(SDL_STATIC) set(ENABLE_STATIC_TRUE "") set(ENABLE_STATIC_FALSE "#") - else(SDL_STATIC) + else() set(ENABLE_STATIC_TRUE "#") set(ENABLE_STATIC_FALSE "") endif() if(SDL_SHARED) set(ENABLE_SHARED_TRUE "") set(ENABLE_SHARED_FALSE "#") - else(SDL_SHARED) + else() set(ENABLE_SHARED_TRUE "#") set(ENABLE_SHARED_FALSE "") endif() @@ -1281,7 +1362,7 @@ if(SDL_SHARED) VERSION ${LT_VERSION} SOVERSION ${LT_REVISION} OUTPUT_NAME "SDL2-${LT_RELEASE}") - else(UNIX) + else() set_target_properties(SDL2 PROPERTIES VERSION ${SDL_VERSION} SOVERSION ${LT_REVISION} @@ -1330,7 +1411,7 @@ if(NOT WINDOWS OR CYGWIN) if(FREEBSD) # FreeBSD uses ${PREFIX}/libdata/pkgconfig install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "libdata/pkgconfig") - else(FREEBSD) + else() install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "lib${LIB_SUFFIX}/pkgconfig") endif() diff --git a/SDL2.spec.in b/SDL2.spec.in index 2a5c47924..628a9a0c6 100644 --- a/SDL2.spec.in +++ b/SDL2.spec.in @@ -1,7 +1,7 @@ Summary: Simple DirectMedia Layer Name: SDL2 Version: @SDL_VERSION@ -Release: 1 +Release: 2 Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz URL: http://www.libsdl.org/ License: zlib @@ -63,12 +63,12 @@ rm -rf $RPM_BUILD_ROOT %files %{__defattr} -%doc README-SDL.txt COPYING.txt CREDITS.txt BUGS.txt +%doc README*.txt COPYING.txt CREDITS.txt BUGS.txt %{_libdir}/lib*.%{__soext}.* %files devel %{__defattr} -%doc README README-SDL.txt COPYING CREDITS BUGS WhatsNew +%doc README*.txt COPYING.txt CREDITS.txt BUGS.txt WhatsNew.txt %{_bindir}/*-config %{_libdir}/lib*.a %{_libdir}/lib*.la @@ -78,13 +78,16 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/aclocal/* %changelog +* Sun Dec 07 2014 Simone Contini +- Fixed changelog date issue and docs filenames + * Sun Jan 22 2012 Sam Lantinga - Updated for SDL 2.0 * Tue May 16 2006 Sam Lantinga - Removed support for Darwin, due to build problems on ps2linux -* Mon Jan 03 2004 Anders Bjorklund +* Sat Jan 03 2004 Anders Bjorklund - Added support for Darwin, updated spec file * Wed Jan 19 2000 Sam Lantinga diff --git a/Xcode-iOS/Demos/src/fireworks.c b/Xcode-iOS/Demos/src/fireworks.c index 6c60dd125..a5beada91 100644 --- a/Xcode-iOS/Demos/src/fireworks.c +++ b/Xcode-iOS/Demos/src/fireworks.c @@ -387,6 +387,9 @@ main(int argc, char *argv[]) SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); + /* create main window and renderer */ window = SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj index 44055cae4..747f150bf 100755 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -1274,8 +1274,14 @@ FD6526640DE8FCCB002AD96B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; COPY_PHASE_STRIP = NO; IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; @@ -1284,8 +1290,14 @@ FD6526650DE8FCCB002AD96B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; COPY_PHASE_STRIP = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.1.1; + GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; + GCC_WARN_STRICT_SELECTOR_MATCH = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; PRODUCT_NAME = SDL2; SKIP_INSTALL = YES; }; diff --git a/android-project/AndroidManifest.xml b/android-project/AndroidManifest.xml index dc8450a61..960bde334 100644 --- a/android-project/AndroidManifest.xml +++ b/android-project/AndroidManifest.xml @@ -8,6 +8,15 @@ android:versionName="1.0" android:installLocation="auto"> + + + + + + + + + - - - - - - - diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java index f65a01050..3c154da95 100644 --- a/android-project/src/org/libsdl/app/SDLActivity.java +++ b/android-project/src/org/libsdl/app/SDLActivity.java @@ -41,6 +41,10 @@ public class SDLActivity extends Activity { /** If shared libraries (e.g. SDL or the native application) could not be loaded. */ public static boolean mBrokenLibraries; + // If we want to separate mouse and touch events. + // This is only toggled in native code when a hint is set! + public static boolean mSeparateMouseAndTouch; + // Main components protected static SDLActivity mSingleton; protected static SDLSurface mSurface; @@ -81,7 +85,6 @@ public class SDLActivity extends Activity { } /** - * This method is called by SDL using JNI. * This method is called by SDL before starting the native application thread. * It can be overridden to provide the arguments after the application name. * The default implementation returns an empty array. It never returns null. @@ -111,6 +114,8 @@ public class SDLActivity extends Activity { // Setup @Override protected void onCreate(Bundle savedInstanceState) { + Log.v("SDL", "Device: " + android.os.Build.DEVICE); + Log.v("SDL", "Model: " + android.os.Build.MODEL); Log.v("SDL", "onCreate():" + mSingleton); super.onCreate(savedInstanceState); @@ -392,7 +397,7 @@ public class SDLActivity extends Activity { public static native void nativeQuit(); public static native void nativePause(); public static native void nativeResume(); - public static native void onNativeResize(int x, int y, int format); + public static native void onNativeResize(int x, int y, int format, float rate); public static native int onNativePadDown(int device_id, int keycode); public static native int onNativePadUp(int device_id, int keycode); public static native void onNativeJoy(int device_id, int axis, @@ -402,6 +407,7 @@ public class SDLActivity extends Activity { public static native void onNativeKeyDown(int keycode); public static native void onNativeKeyUp(int keycode); public static native void onNativeKeyboardFocusLost(); + public static native void onNativeMouse(int button, int action, float x, float y); public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y, float p); @@ -1041,7 +1047,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, mWidth = width; mHeight = height; - SDLActivity.onNativeResize(width, height, sdlFormat); + SDLActivity.onNativeResize(width, height, sdlFormat, mDisplay.getRefreshRate()); Log.v("SDL", "Window size:" + width + "x"+height); // Set mIsSurfaceReady to 'true' *before* making a call to handleResume @@ -1088,8 +1094,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, // Dispatch the different events depending on where they come from // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD - - if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */ + + if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) { @@ -1126,50 +1132,65 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, final int pointerCount = event.getPointerCount(); int action = event.getActionMasked(); int pointerFingerId; + int mouseButton; int i = -1; float x,y,p; - - switch(action) { - case MotionEvent.ACTION_MOVE: - for (i = 0; i < pointerCount; i++) { + + // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14. + if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) { + if (Build.VERSION.SDK_INT < 14) { + mouseButton = 1; // For Android==12 all mouse buttons are the left button + } else { + try { + mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event); + } catch(Exception e) { + mouseButton = 1; // oh well. + } + } + SDLActivity.onNativeMouse(mouseButton, action, event.getX(0), event.getY(0)); + } else { + switch(action) { + case MotionEvent.ACTION_MOVE: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); + } + break; + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_DOWN: + // Primary pointer up/down, the index is always zero + i = 0; + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_POINTER_DOWN: + // Non primary pointer up/down + if (i == -1) { + i = event.getActionIndex(); + } + pointerFingerId = event.getPointerId(i); x = event.getX(i) / mWidth; y = event.getY(i) / mHeight; p = event.getPressure(i); SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - } - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_DOWN: - // Primary pointer up/down, the index is always zero - i = 0; - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: - // Non primary pointer up/down - if (i == -1) { - i = event.getActionIndex(); - } + break; - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p); - break; - - case MotionEvent.ACTION_CANCEL: - for (i = 0; i < pointerCount; i++) { - pointerFingerId = event.getPointerId(i); - x = event.getX(i) / mWidth; - y = event.getY(i) / mHeight; - p = event.getPressure(i); - SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); - } - break; + case MotionEvent.ACTION_CANCEL: + for (i = 0; i < pointerCount; i++) { + pointerFingerId = event.getPointerId(i); + x = event.getX(i) / mWidth; + y = event.getY(i) / mHeight; + p = event.getPressure(i); + SDLActivity.onNativeTouch(touchDevId, pointerFingerId, MotionEvent.ACTION_UP, x, y, p); + } + break; - default: - break; + default: + break; + } } return true; @@ -1500,9 +1521,44 @@ class SDLJoystickHandler_API12 extends SDLJoystickHandler { class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener { // Generic Motion (mouse hover, joystick...) events go here - // We only have joysticks yet @Override public boolean onGenericMotion(View v, MotionEvent event) { - return SDLActivity.handleJoystickMotionEvent(event); + float x, y; + int mouseButton; + int action; + + switch ( event.getSource() ) { + case InputDevice.SOURCE_JOYSTICK: + case InputDevice.SOURCE_GAMEPAD: + case InputDevice.SOURCE_DPAD: + SDLActivity.handleJoystickMotionEvent(event); + return true; + + case InputDevice.SOURCE_MOUSE: + action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_SCROLL: + x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0); + y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0); + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + case MotionEvent.ACTION_HOVER_MOVE: + x = event.getX(0); + y = event.getY(0); + + SDLActivity.onNativeMouse(0, action, x, y); + return true; + + default: + break; + } + + default: + break; + } + + // Event was not managed + return false; } } diff --git a/build-scripts/config.guess b/build-scripts/config.guess index ddb36220a..68c1be32a 100644 --- a/build-scripts/config.guess +++ b/build-scripts/config.guess @@ -898,6 +898,7 @@ EOF else case `sed -n '/^Hardware/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in BCM2708) MANUFACTURER=raspberry;; + BCM2709) MANUFACTURER=raspberry;; *) MANUFACTURER=unknown;; esac if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ diff --git a/build-scripts/config.sub b/build-scripts/config.sub index ce5e0e68d..53273f2bb 100644 --- a/build-scripts/config.sub +++ b/build-scripts/config.sub @@ -1534,6 +1534,8 @@ case $os in -pnacl*) os=-pnacl ;; + -emscripten*) + ;; -none) ;; *) diff --git a/build-scripts/emscripten-buildbot.sh b/build-scripts/emscripten-buildbot.sh new file mode 100755 index 000000000..db5fb8184 --- /dev/null +++ b/build-scripts/emscripten-buildbot.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +SDKDIR="/emsdk_portable" +ENVSCRIPT="$SDKDIR/emsdk_env.sh" +if [ ! -f "$ENVSCRIPT" ]; then + echo "ERROR: This script expects the Emscripten SDK to be in '$SDKDIR'." 1>&2 + exit 1 +fi + +TARBALL="$1" +if [ -z $1 ]; then + TARBALL=sdl-emscripten.tar.xz +fi + +cd `dirname "$0"` +cd .. +SDLBASE=`pwd` + +if [ -z "$MAKE" ]; then + OSTYPE=`uname -s` + if [ "$OSTYPE" == "Linux" ]; then + NCPU=`cat /proc/cpuinfo |grep vendor_id |wc -l` + let NCPU=$NCPU+1 + elif [ "$OSTYPE" = "Darwin" ]; then + NCPU=`sysctl -n hw.ncpu` + elif [ "$OSTYPE" = "SunOS" ]; then + NCPU=`/usr/sbin/psrinfo |wc -l |sed -e 's/^ *//g;s/ *$//g'` + else + NCPU=1 + fi + + if [ -z "$NCPU" ]; then + NCPU=1 + elif [ "$NCPU" = "0" ]; then + NCPU=1 + fi + + MAKE="make -j$NCPU" +fi + +echo "\$MAKE is '$MAKE'" + +echo "Setting up Emscripten SDK environment..." +source "$ENVSCRIPT" + +echo "Setting up..." +set -x +cd "$SDLBASE" +rm -rf buildbot +mkdir buildbot +pushd buildbot + +echo "Configuring..." +emconfigure ../configure --host=asmjs-unknown-emscripten --disable-assembly --disable-threads --enable-cpuinfo=false CFLAGS="-O2 -Wno-warn-absolute-paths -Wdeclaration-after-statement -Werror=declaration-after-statement" --prefix="$PWD/emscripten-sdl2-installed" + +echo "Building..." +emmake $MAKE + +echo "Moving things around..." +emmake $MAKE install +# Fix up a few things to a real install path +perl -w -pi -e "s#$PWD/emscripten-sdl2-installed#/usr/local#g;" ./emscripten-sdl2-installed/lib/libSDL2.la ./emscripten-sdl2-installed/lib/pkgconfig/sdl2.pc ./emscripten-sdl2-installed/bin/sdl2-config +mkdir -p ./usr +mv ./emscripten-sdl2-installed ./usr/local +popd +tar -cJvvf $TARBALL -C buildbot usr +rm -rf buildbot + +exit 0 + +# end of emscripten-buildbot.sh ... + diff --git a/build-scripts/windows-buildbot-zipper.bat b/build-scripts/windows-buildbot-zipper.bat new file mode 100644 index 000000000..5a1e40a2e --- /dev/null +++ b/build-scripts/windows-buildbot-zipper.bat @@ -0,0 +1,31 @@ +@echo off +rem just a helper batch file for collecting up files and zipping them. +rem usage: windows-buildbot-zipper.bat +rem must be run from root of SDL source tree. + +IF EXIST VisualC\Win32\Release GOTO okaydir +echo Please run from root of source tree after doing a Release build. +GOTO done + +:okaydir +erase /q /f /s zipper +IF EXIST zipper GOTO zippermade +mkdir zipper +:zippermade +cd zipper +mkdir SDL +cd SDL +mkdir include +mkdir lib +mkdir lib\win32 +copy ..\..\include\*.h include\ +copy ..\..\VisualC\Win32\Release\SDL2.dll lib\win32\ +copy ..\..\VisualC\Win32\Release\SDL2.lib lib\win32\ +copy ..\..\VisualC\Win32\Release\SDL2main.lib lib\win32\ +cd .. +zip -9r ..\%1 SDL +cd .. +erase /q /f /s zipper + +:done + diff --git a/cmake/macros.cmake b/cmake/macros.cmake index c234a566c..96a7ce8b1 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -66,7 +66,7 @@ endmacro() macro(CHECK_OBJC_SOURCE_COMPILES SOURCE VAR) set(PREV_REQUIRED_DEFS "${CMAKE_REQUIRED_DEFINITIONS}") - set(CMAKE_REQUIRED_DEFINITIONS "-ObjC ${PREV_REQUIRED_DEFS}") + set(CMAKE_REQUIRED_DEFINITIONS "-x objective-c ${PREV_REQUIRED_DEFS}") CHECK_C_SOURCE_COMPILES(${SOURCE} ${VAR}) set(CMAKE_REQUIRED_DEFINITIONS "${PREV_REQUIRED_DEFS}") endmacro() diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index 63aceda3d..f390fcbd0 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -39,7 +39,7 @@ macro(CheckDLOPEN) set(_DLLIB ${_LIBNAME}) set(HAVE_DLOPEN TRUE) break() - endif(DLOPEN_LIB) + endif() endforeach() endif() @@ -63,7 +63,7 @@ macro(CheckDLOPEN) set(SOURCE_FILES ${SOURCE_FILES} ${DLOPEN_SOURCES}) set(HAVE_SDL_LOADSO TRUE) endif() -endmacro(CheckDLOPEN) +endmacro() # Requires: # - n/a @@ -78,23 +78,23 @@ macro(CheckOSS) check_c_source_compiles(" #include int main() { int arg = SNDCTL_DSP_SETFRAGMENT; }" OSS_FOUND) - endif(NOT OSS_FOUND) + endif() if(OSS_FOUND) set(HAVE_OSS TRUE) file(GLOB OSS_SOURCES ${SDL2_SOURCE_DIR}/src/audio/dsp/*.c) if(OSS_HEADER_FILE STREQUAL "soundcard.h") set(SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H 1) - endif(OSS_HEADER_FILE STREQUAL "soundcard.h") + endif() set(SDL_AUDIO_DRIVER_OSS 1) set(SOURCE_FILES ${SOURCE_FILES} ${OSS_SOURCES}) if(NETBSD OR OPENBSD) list(APPEND EXTRA_LIBS ossaudio) - endif(NETBSD OR OPENBSD) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(OSS_FOUND) - endif(OSS) -endmacro(CheckOSS) + endif() + endif() +endmacro() # Requires: # - n/a @@ -117,14 +117,14 @@ macro(CheckALSA) FindLibraryAndSONAME("asound") set(SDL_AUDIO_DRIVER_ALSA_DYNAMIC "\"${ASOUND_LIB_SONAME}\"") set(HAVE_ALSA_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(ALSA_SHARED) + endif() + else() list(APPEND EXTRA_LIBS asound) - endif(ALSA_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(HAVE_ASOUNDLIB_H) - endif(ALSA) -endmacro(CheckALSA) + endif() + endif() +endmacro() # Requires: # - PkgCheckModules @@ -147,14 +147,14 @@ macro(CheckPulseAudio) FindLibraryAndSONAME("pulse-simple") set(SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC "\"${PULSE_SIMPLE_LIB_SONAME}\"") set(HAVE_PULSEAUDIO_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(PULSEAUDIO_SHARED) + endif() + else() list(APPEND EXTRA_LDFLAGS ${PKG_PULSEAUDIO_LDFLAGS}) - endif(PULSEAUDIO_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(PKG_PULSEAUDIO_FOUND) - endif(PULSEAUDIO) -endmacro(CheckPulseAudio) + endif() + endif() +endmacro() # Requires: # - PkgCheckModules @@ -177,14 +177,14 @@ macro(CheckESD) FindLibraryAndSONAME(esd) set(SDL_AUDIO_DRIVER_ESD_DYNAMIC "\"${ESD_LIB_SONAME}\"") set(HAVE_ESD_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(ESD_SHARED) + endif() + else() list(APPEND EXTRA_LDFLAGS ${PKG_ESD_LDFLAGS}) - endif(ESD_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(PKG_ESD_FOUND) - endif(ESD) -endmacro(CheckESD) + endif() + endif() +endmacro() # Requires: # - n/a @@ -212,14 +212,14 @@ macro(CheckARTS) FindLibraryAndSONAME(artsc) set(SDL_AUDIO_DRIVER_ARTS_DYNAMIC "\"${ARTSC_LIB_SONAME}\"") set(HAVE_ARTS_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(ARTS_SHARED) + endif() + else() list(APPEND EXTRA_LDFLAGS ${ARTS_LIBS}) - endif(ARTS_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(ARTS_CONFIG) - endif(ARTS) -endmacro(CheckARTS) + endif() + endif() +endmacro() # Requires: # - n/a @@ -243,14 +243,14 @@ macro(CheckNAS) FindLibraryAndSONAME("audio") set(SDL_AUDIO_DRIVER_NAS_DYNAMIC "\"${AUDIO_LIB_SONAME}\"") set(HAVE_NAS_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(NAS_SHARED) + endif() + else() list(APPEND EXTRA_LIBS ${D_NAS_LIB}) - endif(NAS_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(HAVE_NAS_H AND D_NAS_LIB) - endif(NAS) -endmacro(CheckNAS) + endif() + endif() +endmacro() # Requires: # - n/a @@ -274,14 +274,14 @@ macro(CheckSNDIO) FindLibraryAndSONAME("sndio") set(SDL_AUDIO_DRIVER_SNDIO_DYNAMIC "\"${SNDIO_LIB_SONAME}\"") set(HAVE_SNDIO_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(SNDIO_SHARED) + endif() + else() list(APPEND EXTRA_LIBS ${D_SNDIO_LIB}) - endif(SNDIO_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(HAVE_SNDIO_H AND D_SNDIO_LIB) - endif(SNDIO) -endmacro(CheckSNDIO) + endif() + endif() +endmacro() # Requires: # - PkgCheckModules @@ -304,14 +304,14 @@ macro(CheckFusionSound) FindLibraryAndSONAME("fusionsound") set(SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "\"${FUSIONSOUND_LIB_SONAME}\"") set(HAVE_FUSIONSOUND_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(FUSIONSOUND_SHARED) + endif() + else() list(APPEND EXTRA_LDFLAGS ${PKG_FUSIONSOUND_LDFLAGS}) - endif(FUSIONSOUND_SHARED) + endif() set(HAVE_SDL_AUDIO TRUE) - endif(PKG_FUSIONSOUND_FOUND) - endif(FUSIONSOUND) -endmacro(CheckFusionSound) + endif() + endif() +endmacro() # Requires: # - n/a @@ -353,34 +353,34 @@ macro(CheckX11) if(APPLE) set(X11_SHARED OFF) - endif(APPLE) + endif() check_function_exists("shmat" HAVE_SHMAT) if(NOT HAVE_SHMAT) check_library_exists(ipc shmat "" HAVE_SHMAT) if(HAVE_SHMAT) list(APPEND EXTRA_LIBS ipc) - endif(HAVE_SHMAT) + endif() if(NOT HAVE_SHMAT) add_definitions(-DNO_SHARED_MEMORY) set(X_CFLAGS "${X_CFLAGS} -DNO_SHARED_MEMORY") - endif(NOT HAVE_SHMAT) - endif(NOT HAVE_SHMAT) + endif() + endif() if(X11_SHARED) if(NOT HAVE_DLOPEN) message_warn("You must have SDL_LoadObject() support for dynamic X11 loading") set(HAVE_X11_SHARED FALSE) - else(NOT HAVE_DLOPEN) + else() set(HAVE_X11_SHARED TRUE) endif() if(HAVE_X11_SHARED) set(SDL_VIDEO_DRIVER_X11_DYNAMIC "\"${X11_LIB_SONAME}\"") set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "\"${XEXT_LIB_SONAME}\"") - else(HAVE_X11_SHARED) + else() list(APPEND EXTRA_LIBS ${X11_LIB} ${XEXT_LIB}) - endif(HAVE_X11_SHARED) - endif(X11_SHARED) + endif() + endif() set(SDL_CFLAGS "${SDL_CFLAGS} ${X_CFLAGS}") @@ -394,7 +394,7 @@ macro(CheckX11) int main(int argc, char **argv) {}" HAVE_CONST_XEXT_ADDDISPLAY) if(HAVE_CONST_XEXT_ADDDISPLAY) set(SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY 1) - endif(HAVE_CONST_XEXT_ADDDISPLAY) + endif() check_c_source_compiles(" #include @@ -407,7 +407,7 @@ macro(CheckX11) XFreeEventData(display, cookie); }" HAVE_XGENERICEVENT) if(HAVE_XGENERICEVENT) set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1) - endif(HAVE_XGENERICEVENT) + endif() check_c_source_compiles(" #include @@ -415,7 +415,7 @@ macro(CheckX11) int main(int argc, char **argv) {}" HAVE_CONST_XDATA32) if(HAVE_CONST_XDATA32) set(SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32 1) - endif(HAVE_CONST_XDATA32) + endif() check_function_exists(XkbKeycodeToKeysym SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM) @@ -423,29 +423,29 @@ macro(CheckX11) set(HAVE_VIDEO_X11_XCURSOR TRUE) if(HAVE_X11_SHARED AND XCURSOR_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR "\"${XCURSOR_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XCURSOR_LIB) + else() list(APPEND EXTRA_LIBS ${XCURSOR_LIB}) - endif(HAVE_X11_SHARED AND XCURSOR_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XCURSOR 1) - endif(VIDEO_X11_XCURSOR AND HAVE_XCURSOR_H) + endif() if(VIDEO_X11_XINERAMA AND HAVE_XINERAMA_H) set(HAVE_VIDEO_X11_XINERAMA TRUE) if(HAVE_X11_SHARED AND XINERAMA_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "\"${XINERAMA_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XINERAMA_LIB) + else() list(APPEND EXTRA_LIBS ${XINERAMA_LIB}) - endif(HAVE_X11_SHARED AND XINERAMA_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XINERAMA 1) - endif(VIDEO_X11_XINERAMA AND HAVE_XINERAMA_H) + endif() if(VIDEO_X11_XINPUT AND HAVE_XINPUT_H) set(HAVE_VIDEO_X11_XINPUT TRUE) if(HAVE_X11_SHARED AND XI_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "\"${XI_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XI_LIB) + else() list(APPEND EXTRA_LIBS ${XI_LIB}) - endif(HAVE_X11_SHARED AND XI_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XINPUT2 1) # Check for multitouch @@ -462,51 +462,56 @@ macro(CheckX11) int main(int argc, char **argv) {}" HAVE_XINPUT2_MULTITOUCH) if(HAVE_XINPUT2_MULTITOUCH) set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1) - endif(HAVE_XINPUT2_MULTITOUCH) - endif(VIDEO_X11_XINPUT AND HAVE_XINPUT_H) + endif() + endif() if(VIDEO_X11_XRANDR AND HAVE_XRANDR_H) if(HAVE_X11_SHARED AND XRANDR_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "\"${XRANDR_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XRANDR_LIB) + else() list(APPEND EXTRA_LIBS ${XRANDR_LIB}) - endif(HAVE_X11_SHARED AND XRANDR_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XRANDR 1) set(HAVE_VIDEO_X11_XRANDR TRUE) - endif(VIDEO_X11_XRANDR AND HAVE_XRANDR_H) + endif() if(VIDEO_X11_XSCRNSAVER AND HAVE_XSS_H) if(HAVE_X11_SHARED AND XSS_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "\"${XSS_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XSS_LIB) + else() list(APPEND EXTRA_LIBS ${XSS_LIB}) - endif(HAVE_X11_SHARED AND XSS_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1) set(HAVE_VIDEO_X11_XSCRNSAVER TRUE) - endif(VIDEO_X11_XSCRNSAVER AND HAVE_XSS_H) + endif() if(VIDEO_X11_XSHAPE AND HAVE_XSHAPE_H) set(SDL_VIDEO_DRIVER_X11_XSHAPE 1) set(HAVE_VIDEO_X11_XSHAPE TRUE) - endif(VIDEO_X11_XSHAPE AND HAVE_XSHAPE_H) + endif() if(VIDEO_X11_XVM AND HAVE_XF86VM_H) if(HAVE_X11_SHARED AND XXF86VM_LIB) set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "\"${XXF86VM_LIB_SONAME}\"") - else(HAVE_X11_SHARED AND XXF86VM_LIB) + else() list(APPEND EXTRA_LIBS ${XXF86VM_LIB}) - endif(HAVE_X11_SHARED AND XXF86VM_LIB) + endif() set(SDL_VIDEO_DRIVER_X11_XVIDMODE 1) set(HAVE_VIDEO_X11_XVM TRUE) - endif(VIDEO_X11_XVM AND HAVE_XF86VM_H) + endif() set(CMAKE_REQUIRED_LIBRARIES) - endif(X11_LIB) - endif(VIDEO_X11) -endmacro(CheckX11) + endif() + endif() +endmacro() +# Requires: +# - EGL +# - PkgCheckModules +# Optional: +# - MIR_SHARED opt +# - HAVE_DLOPEN opt macro(CheckMir) -# !!! FIXME: hook up dynamic loading here. if(VIDEO_MIR) find_library(MIR_LIB mirclient mircommon egl) pkg_check_modules(MIR_TOOLKIT mirclient mircommon) @@ -522,15 +527,31 @@ macro(CheckMir) set(SDL_VIDEO_DRIVER_MIR 1) list(APPEND EXTRA_CFLAGS ${MIR_TOOLKIT_CFLAGS} ${EGL_CLFAGS} ${XKB_CLFLAGS}) - list(APPEND EXTRA_LDFLAGS ${MIR_TOOLKIT_LDFLAGS} ${EGL_LDLAGS} ${XKB_LDLAGS}) - endif (MIR_LIB AND MIR_TOOLKIT_FOUND AND EGL_FOUND AND XKB_FOUND) - endif(VIDEO_MIR) -endmacro(CheckMir) + + 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,16 +561,38 @@ macro(CheckWayland) include_directories( ${WAYLAND_INCLUDE_DIRS} ) - set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS}) set(HAVE_VIDEO_WAYLAND TRUE) set(HAVE_SDL_VIDEO TRUE) file(GLOB WAYLAND_SOURCES ${SDL2_SOURCE_DIR}/src/video/wayland/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${WAYLAND_SOURCES}) + + if(VIDEO_WAYLAND_QT_TOUCH) + set(SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH 1) + endif() + + if(WAYLAND_SHARED) + if(NOT HAVE_DLOPEN) + message_warn("You must have SDL_LoadObject() support for dynamic Wayland loading") + else() + FindLibraryAndSONAME(wayland-client) + FindLibraryAndSONAME(wayland-egl) + FindLibraryAndSONAME(wayland-cursor) + FindLibraryAndSONAME(xkbcommon) + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC "\"${WAYLAND_CLIENT_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL "\"${WAYLAND_EGL_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR "\"${WAYLAND_CURSOR_LIB_SONAME}\"") + set(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON "\"${XKBCOMMON_LIB_SONAME}\"") + set(HAVE_WAYLAND_SHARED TRUE) + endif() + else() + set(EXTRA_LIBS ${WAYLAND_LIBRARIES} ${EXTRA_LIBS}) + endif() + set(SDL_VIDEO_DRIVER_WAYLAND 1) - endif(WAYLAND_FOUND) - endif(VIDEO_WAYLAND) -endmacro(CheckWayland) + endif() + endif() +endmacro() # Requires: # - n/a @@ -558,16 +601,16 @@ macro(CheckCOCOA) if(VIDEO_COCOA) if(APPLE) # Apple always has Cocoa. set(HAVE_VIDEO_COCOA TRUE) - endif(APPLE) + endif() if(HAVE_VIDEO_COCOA) file(GLOB COCOA_SOURCES ${SDL2_SOURCE_DIR}/src/video/cocoa/*.m) set_source_files_properties(${COCOA_SOURCES} PROPERTIES LANGUAGE C) set(SOURCE_FILES ${SOURCE_FILES} ${COCOA_SOURCES}) set(SDL_VIDEO_DRIVER_COCOA 1) set(HAVE_SDL_VIDEO TRUE) - endif(HAVE_VIDEO_COCOA) - endif(VIDEO_COCOA) -endmacro(CheckCOCOA) + endif() + endif() +endmacro() # Requires: # - PkgCheckModules @@ -591,14 +634,14 @@ macro(CheckDirectFB) FindLibraryAndSONAME("directfb") set(SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC "\"${DIRECTFB_LIB_SONAME}\"") set(HAVE_DIRECTFB_SHARED TRUE) - endif(NOT HAVE_DLOPEN) - else(DIRECTFB_SHARED) + endif() + else() list(APPEND EXTRA_LDFLAGS ${PKG_DIRECTFB_LDFLAGS}) - endif(DIRECTFB_SHARED) + endif() set(HAVE_SDL_VIDEO TRUE) - endif(PKG_DIRECTFB_FOUND) - endif(VIDEO_DIRECTFB) -endmacro(CheckDirectFB) + endif() + endif() +endmacro() # Requires: # - n/a @@ -645,9 +688,9 @@ macro(CheckOpenGLX11) set(SDL_VIDEO_OPENGL_GLX 1) set(SDL_VIDEO_RENDER_OGL 1) list(APPEND EXTRA_LIBS GL) - endif(HAVE_VIDEO_OPENGL) - endif(VIDEO_OPENGL) -endmacro(CheckOpenGLX11) + endif() + endif() +endmacro() # Requires: # - nada @@ -659,7 +702,7 @@ macro(CheckOpenGLESX11) int main (int argc, char** argv) {}" HAVE_VIDEO_OPENGL_EGL) if(HAVE_VIDEO_OPENGL_EGL) set(SDL_VIDEO_OPENGL_EGL 1) - endif(HAVE_VIDEO_OPENGL_EGL) + endif() check_c_source_compiles(" #include #include @@ -668,7 +711,7 @@ macro(CheckOpenGLESX11) set(HAVE_VIDEO_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES 1) set(SDL_VIDEO_RENDER_OGL_ES 1) - endif(HAVE_VIDEO_OPENGLES_V1) + endif() check_c_source_compiles(" #include #include @@ -677,12 +720,12 @@ macro(CheckOpenGLESX11) set(HAVE_VIDEO_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES2 1) set(SDL_VIDEO_RENDER_OGL_ES2 1) - endif(HAVE_VIDEO_OPENGLES_V2) + endif() - endif(VIDEO_OPENGLES) -endmacro(CheckOpenGLESX11) + endif() +endmacro() -# Rquires: +# Requires: # - nada # Optional: # - THREADS opt @@ -729,17 +772,21 @@ macro(CheckPTHREAD) else() set(PTHREAD_CFLAGS "-D_REENTRANT") set(PTHREAD_LDFLAGS "-lpthread") - endif(LINUX) + endif() # Run some tests set(CMAKE_REQUIRED_FLAGS "${PTHREAD_CFLAGS} ${PTHREAD_LDFLAGS}") - check_c_source_runs(" + if(CMAKE_CROSSCOMPILING) + set(HAVE_PTHREADS 1) + else() + check_c_source_runs(" #include int main(int argc, char** argv) { pthread_attr_t type; pthread_attr_init(&type); return 0; }" HAVE_PTHREADS) + endif() if(HAVE_PTHREADS) set(SDL_THREAD_PTHREAD 1) list(APPEND EXTRA_CFLAGS ${PTHREAD_CFLAGS}) @@ -756,7 +803,7 @@ macro(CheckPTHREAD) }" HAVE_RECURSIVE_MUTEXES) if(HAVE_RECURSIVE_MUTEXES) set(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1) - else(HAVE_RECURSIVE_MUTEXES) + else() check_c_source_compiles(" #include int main(int argc, char **argv) { @@ -766,8 +813,8 @@ macro(CheckPTHREAD) }" HAVE_RECURSIVE_MUTEXES_NP) if(HAVE_RECURSIVE_MUTEXES_NP) set(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1) - endif(HAVE_RECURSIVE_MUTEXES_NP) - endif(HAVE_RECURSIVE_MUTEXES) + endif() + endif() if(PTHREADS_SEM) check_c_source_compiles("#include @@ -781,15 +828,15 @@ macro(CheckPTHREAD) sem_timedwait(NULL, NULL); return 0; }" HAVE_SEM_TIMEDWAIT) - endif(HAVE_PTHREADS_SEM) - endif(PTHREADS_SEM) + endif() + endif() check_c_source_compiles(" #include #include int main(int argc, char** argv) { return 0; }" HAVE_PTHREAD_NP_H) - check_function_exists(pthread_setname_np HAVE_PTHREAD_setNAME_NP) - check_function_exists(pthread_set_name_np HAVE_PTHREAD_set_NAME_NP) + check_function_exists(pthread_setname_np HAVE_PTHREAD_SETNAME_NP) + check_function_exists(pthread_set_name_np HAVE_PTHREAD_SET_NAME_NP) set(CMAKE_REQUIRED_FLAGS) set(SOURCE_FILES ${SOURCE_FILES} @@ -801,14 +848,14 @@ macro(CheckPTHREAD) if(HAVE_PTHREADS_SEM) set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/thread/pthread/SDL_syssem.c) - else(HAVE_PTHREADS_SEM) + else() set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_syssem.c) - endif(HAVE_PTHREADS_SEM) + endif() set(HAVE_SDL_THREADS TRUE) - endif(HAVE_PTHREADS) - endif(PTHREADS) -endmacro(CheckPTHREAD) + endif() + endif() +endmacro() # Requires # - nada @@ -822,27 +869,27 @@ macro(CheckUSBHID) check_include_file(usbhid.h HAVE_USBHID_H) if(HAVE_USBHID_H) set(USB_CFLAGS "-DHAVE_USBHID_H") - endif(HAVE_USBHID_H) + endif() check_include_file(libusbhid.h HAVE_LIBUSBHID_H) if(HAVE_LIBUSBHID_H) set(USB_CFLAGS "${USB_CFLAGS} -DHAVE_LIBUSBHID_H") - endif(HAVE_LIBUSBHID_H) + endif() set(USB_LIBS ${USB_LIBS} usbhid) - else(LIBUSBHID) + else() check_include_file(usb.h HAVE_USB_H) if(HAVE_USB_H) set(USB_CFLAGS "-DHAVE_USB_H") - endif(HAVE_USB_H) + endif() check_include_file(libusb.h HAVE_LIBUSB_H) if(HAVE_LIBUSB_H) set(USB_CFLAGS "${USB_CFLAGS} -DHAVE_LIBUSB_H") - endif(HAVE_LIBUSB_H) + endif() check_library_exists(usb hid_init "" LIBUSB) if(LIBUSB) set(USB_LIBS ${USB_LIBS} usb) - endif(LIBUSB) - endif(LIBUSBHID) + endif() + endif() set(CMAKE_REQUIRED_FLAGS "${USB_CFLAGS}") set(CMAKE_REQUIRED_LIBRARIES "${USB_LIBS}") @@ -898,7 +945,7 @@ macro(CheckUSBHID) }" HAVE_USBHID_UCR_DATA) if(HAVE_USBHID_UCR_DATA) set(USB_CFLAGS "${USB_CFLAGS} -DUSBHID_UCR_DATA") - endif(HAVE_USBHID_UCR_DATA) + endif() check_c_source_compiles(" #include @@ -926,7 +973,7 @@ macro(CheckUSBHID) }" HAVE_USBHID_NEW) if(HAVE_USBHID_NEW) set(USB_CFLAGS "${USB_CFLAGS} -DUSBHID_NEW") - endif(HAVE_USBHID_NEW) + endif() check_c_source_compiles(" #include @@ -936,7 +983,7 @@ macro(CheckUSBHID) }" HAVE_MACHINE_JOYSTICK) if(HAVE_MACHINE_JOYSTICK) set(SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H 1) - endif(HAVE_MACHINE_JOYSTICK) + endif() set(SDL_JOYSTICK_USBHID 1) file(GLOB BSD_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/bsd/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${BSD_JOYSTICK_SOURCES}) @@ -946,8 +993,8 @@ macro(CheckUSBHID) set(CMAKE_REQUIRED_LIBRARIES) set(CMAKE_REQUIRED_FLAGS) - endif(HAVE_USBHID) -endmacro(CheckUSBHID) + endif() +endmacro() # Requires: # - n/a diff --git a/configure b/configure index d8360487e..42283e11f 100755 --- a/configure +++ b/configure @@ -21385,6 +21385,78 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL 1" >>confdefs.h fi } +CheckEmscriptenGLES() +{ + if test x$enable_video = xyes -a x$enable_video_opengles = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EGL support" >&5 +$as_echo_n "checking for EGL support... " >&6; } + video_opengl_egl=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + +int +main () +{ + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + video_opengl_egl=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $video_opengl_egl" >&5 +$as_echo "$video_opengl_egl" >&6; } + if test x$video_opengl_egl = xyes; then + +$as_echo "#define SDL_VIDEO_OPENGL_EGL 1" >>confdefs.h + + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenGL ES v2 headers" >&5 +$as_echo_n "checking for OpenGL ES v2 headers... " >&6; } + video_opengles_v2=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + video_opengles_v2=yes + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $video_opengles_v2" >&5 +$as_echo "$video_opengles_v2" >&6; } + if test x$video_opengles_v2 = xyes; then + +$as_echo "#define SDL_VIDEO_OPENGL_ES2 1" >>confdefs.h + + +$as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h + + SUMMARY_video="${SUMMARY_video} opengl_es2" + fi + fi +} + CheckInputEvents() { { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux 2.4 unified input interface" >&5 @@ -21844,6 +21916,7 @@ $as_echo_n "checking for recursive mutexes... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ + #define _GNU_SOURCE 1 #include int @@ -21857,7 +21930,7 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : has_recursive_mutexes=yes @@ -21865,12 +21938,14 @@ $as_echo "#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi if test x$has_recursive_mutexes = xno; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ + #define _GNU_SOURCE 1 #include int @@ -21884,7 +21959,7 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_link "$LINENO"; then : has_recursive_mutexes=yes @@ -21892,7 +21967,8 @@ $as_echo "#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1" >>confdefs.h fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_recursive_mutexes" >&5 $as_echo "$has_recursive_mutexes" >&6; } @@ -22865,7 +22941,9 @@ case "$host" in if test x$enable_video = xyes; then SOURCES="$SOURCES $srcdir/src/video/raspberry/*.c" + # FIXME: confdefs? Not AC_DEFINE? $as_echo "#define SDL_VIDEO_DRIVER_RPI 1" >>confdefs.h + SUMMARY_video="${SUMMARY_video} rpi" fi ;; *-*-androideabi*) @@ -22879,6 +22957,7 @@ case "$host" in if test x$enable_video = xyes; then SOURCES="$SOURCES $srcdir/src/core/android/*.c $srcdir/src/video/android/*.c" + # FIXME: confdefs? Not AC_DEFINE? $as_echo "#define SDL_VIDEO_DRIVER_ANDROID 1" >>confdefs.h SUMMARY_video="${SUMMARY_video} android" fi @@ -23019,11 +23098,22 @@ $as_echo "#define SDL_POWER_ANDROID 1" >>confdefs.h fi # Set up files for the filesystem library if test x$enable_filesystem = xyes; then + case $ARCH in + android) + +$as_echo "#define SDL_FILESYSTEM_ANDROID 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/filesystem/android/*.c" + have_filesystem=yes + ;; + *) $as_echo "#define SDL_FILESYSTEM_UNIX 1" >>confdefs.h - SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" - have_filesystem=yes + SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" + have_filesystem=yes + ;; + esac fi # Set up files for the timer library if test x$enable_timers = xyes; then @@ -23483,7 +23573,68 @@ $as_echo "#define SDL_FILESYSTEM_NACL 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/filesystem/nacl/*.c" have_filesystem=yes fi + ;; + *-*-emscripten* ) + if test x$enable_video = xyes; then +$as_echo "#define SDL_VIDEO_DRIVER_EMSCRIPTEN 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/video/emscripten/*.c" + have_video=yes + SUMMARY_video="${SUMMARY_video} emscripten" + fi + + if test x$enable_audio = xyes; then + +$as_echo "#define SDL_AUDIO_DRIVER_EMSCRIPTEN 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/audio/emscripten/*.c" + have_audio=yes + SUMMARY_audio="${SUMMARY_audio} emscripten" + fi + + CheckVisibilityHidden + CheckDummyVideo + CheckDiskAudio + CheckDummyAudio + CheckDLOPEN + CheckClockGettime + CheckEmscriptenGLES + + # Set up files for the power library + if test x$enable_power = xyes; then + +$as_echo "#define SDL_POWER_EMSCRIPTEN 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/power/emscripten/*.c" + have_power=yes + fi + + # Set up files for the power library + if test x$enable_joystick = xyes; then + +$as_echo "#define SDL_JOYSTICK_EMSCRIPTEN 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/joystick/emscripten/*.c" + have_joystick=yes + fi + + # Set up files for the filesystem library + if test x$enable_filesystem = xyes; then + +$as_echo "#define SDL_FILESYSTEM_EMSCRIPTEN 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/filesystem/emscripten/*.c" + have_filesystem=yes + fi + # Set up files for the timer library + if test x$enable_timers = xyes; then + +$as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/timer/unix/*.c" + have_timers=yes + fi ;; *) as_fn_error $? " diff --git a/configure.in b/configure.in index ea34dfbe5..38c682bf0 100644 --- a/configure.in +++ b/configure.in @@ -2130,6 +2130,40 @@ CheckMacGL() fi } +CheckEmscriptenGLES() +{ + if test x$enable_video = xyes -a x$enable_video_opengles = xyes; then + AC_MSG_CHECKING(for EGL support) + video_opengl_egl=no + AC_TRY_COMPILE([ + #include + ],[ + ],[ + video_opengl_egl=yes + ]) + AC_MSG_RESULT($video_opengl_egl) + if test x$video_opengl_egl = xyes; then + AC_DEFINE(SDL_VIDEO_OPENGL_EGL, 1, [ ]) + fi + + AC_MSG_CHECKING(for OpenGL ES v2 headers) + video_opengles_v2=no + AC_TRY_COMPILE([ + #include + #include + ],[ + ],[ + video_opengles_v2=yes + ]) + AC_MSG_RESULT($video_opengles_v2) + if test x$video_opengles_v2 = xyes; then + AC_DEFINE(SDL_VIDEO_OPENGL_ES2, 1, [ ]) + AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES2, 1, [ ]) + SUMMARY_video="${SUMMARY_video} opengl_es2" + fi + fi +} + dnl See if we can use the new unified event interface in Linux 2.4 CheckInputEvents() { @@ -2390,7 +2424,8 @@ AC_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [[default=yes]]]) AC_MSG_CHECKING(for recursive mutexes) has_recursive_mutexes=no if test x$has_recursive_mutexes = xno; then - AC_TRY_COMPILE([ + AC_TRY_LINK([ + #define _GNU_SOURCE 1 #include ],[ pthread_mutexattr_t attr; @@ -2401,7 +2436,8 @@ AC_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [[default=yes]]]) ]) fi if test x$has_recursive_mutexes = xno; then - AC_TRY_COMPILE([ + AC_TRY_LINK([ + #define _GNU_SOURCE 1 #include ],[ pthread_mutexattr_t attr; @@ -2801,7 +2837,9 @@ case "$host" in if test x$enable_video = xyes; then SOURCES="$SOURCES $srcdir/src/video/raspberry/*.c" + # FIXME: confdefs? Not AC_DEFINE? $as_echo "#define SDL_VIDEO_DRIVER_RPI 1" >>confdefs.h + SUMMARY_video="${SUMMARY_video} rpi" fi ;; *-*-androideabi*) @@ -2815,6 +2853,7 @@ case "$host" in if test x$enable_video = xyes; then SOURCES="$SOURCES $srcdir/src/core/android/*.c $srcdir/src/video/android/*.c" + # FIXME: confdefs? Not AC_DEFINE? $as_echo "#define SDL_VIDEO_DRIVER_ANDROID 1" >>confdefs.h SUMMARY_video="${SUMMARY_video} android" fi @@ -2937,9 +2976,18 @@ case "$host" in fi # Set up files for the filesystem library if test x$enable_filesystem = xyes; then - AC_DEFINE(SDL_FILESYSTEM_UNIX, 1, [ ]) - SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" - have_filesystem=yes + case $ARCH in + android) + AC_DEFINE(SDL_FILESYSTEM_ANDROID, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/filesystem/android/*.c" + have_filesystem=yes + ;; + *) + AC_DEFINE(SDL_FILESYSTEM_UNIX, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/filesystem/unix/*.c" + have_filesystem=yes + ;; + esac fi # Set up files for the timer library if test x$enable_timers = xyes; then @@ -3302,7 +3350,56 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau SOURCES="$SOURCES $srcdir/src/filesystem/nacl/*.c" have_filesystem=yes fi + ;; + *-*-emscripten* ) + if test x$enable_video = xyes; then + AC_DEFINE(SDL_VIDEO_DRIVER_EMSCRIPTEN, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/video/emscripten/*.c" + have_video=yes + SUMMARY_video="${SUMMARY_video} emscripten" + fi + + if test x$enable_audio = xyes; then + AC_DEFINE(SDL_AUDIO_DRIVER_EMSCRIPTEN, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/audio/emscripten/*.c" + have_audio=yes + SUMMARY_audio="${SUMMARY_audio} emscripten" + fi + + CheckVisibilityHidden + CheckDummyVideo + CheckDiskAudio + CheckDummyAudio + CheckDLOPEN + CheckClockGettime + CheckEmscriptenGLES + + # Set up files for the power library + if test x$enable_power = xyes; then + AC_DEFINE(SDL_POWER_EMSCRIPTEN, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/power/emscripten/*.c" + have_power=yes + fi + # Set up files for the power library + if test x$enable_joystick = xyes; then + AC_DEFINE(SDL_JOYSTICK_EMSCRIPTEN, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/joystick/emscripten/*.c" + have_joystick=yes + fi + + # Set up files for the filesystem library + if test x$enable_filesystem = xyes; then + AC_DEFINE(SDL_FILESYSTEM_EMSCRIPTEN, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/filesystem/emscripten/*.c" + have_filesystem=yes + fi + # Set up files for the timer library + if test x$enable_timers = xyes; then + AC_DEFINE(SDL_TIMER_UNIX, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/timer/unix/*.c" + have_timers=yes + fi ;; *) AC_MSG_ERROR([ diff --git a/docs/README-emscripten.md b/docs/README-emscripten.md new file mode 100644 index 000000000..ca9b35b10 --- /dev/null +++ b/docs/README-emscripten.md @@ -0,0 +1,33 @@ +Emscripten +================================================================================ + +Build: + + $ emconfigure ./configure --host=asmjs-unknown-emscripten --disable-assembly --disable-threads --enable-cpuinfo=false CFLAGS="-O2" + $ emmake make + +Or with cmake: + + $ emconfigure cmake .. + $ make + +To build one of the tests: + + $ cd test/ + $ emcc -O2 --js-opts 0 -g4 testdraw2.c -I../include ../build/.libs/libSDL2.a ../build/libSDL2_test.a -o a.html + +Uses GLES2 renderer or software + +tests: https://dl.dropboxusercontent.com/u/17360362/SDL2-em/index.html + +Some other SDL2 libraries can be easily built (assuming SDL2 is installed somewhere): + +SDL_mixer (http://www.libsdl.org/projects/SDL_mixer/) + + $ EMCONFIGURE_JS=1 emconfigure ../configure + build as usual... + +SDL_gfx (http://cms.ferzkopp.net/index.php/software/13-sdl-gfx): + + $ EMCONFIGURE_JS=1 emconfigure ../configure --disable-mmx + build as usual... diff --git a/docs/README-gesture.md b/docs/README-gesture.md index 7b90b54d9..7e9f95bc1 100644 --- a/docs/README-gesture.md +++ b/docs/README-gesture.md @@ -1,6 +1,6 @@ Dollar Gestures =========================================================================== -SDL Provides an implementation of the $1 gesture recognition system. This allows for recording, saving, loading, and performing single stroke gestures. +SDL provides an implementation of the $1 gesture recognition system. This allows for recording, saving, loading, and performing single stroke gestures. Gestures can be performed with any number of fingers (the centroid of the fingers must follow the path of the gesture), but the number of fingers must be constant (a finger cannot go down in the middle of a gesture). The path of a gesture is considered the path from the time when the final finger went down, to the first time any finger comes up. diff --git a/docs/README-platforms.md b/docs/README-platforms.md index 4bf77b206..14454ec5d 100644 --- a/docs/README-platforms.md +++ b/docs/README-platforms.md @@ -1,34 +1,8 @@ Platforms ========= - -This is a list of the platforms SDL supports, and who maintains them. - -Officially supported platforms -============================== -(code compiles, and thoroughly tested for release) -============================== -* Windows XP/Vista/7/8 -* Mac OS X 10.5+ -* Linux 2.6+ -* iOS 5.1.1+ -* Android 2.3.3+ - -Unofficially supported platforms -================================ -(code compiles, but not thoroughly tested) -================================ -* FreeBSD -* NetBSD -* OpenBSD -* Solaris - -Platforms supported by volunteers -================================= -* Haiku - maintained by Axel Dörfler -* PSP - maintained by 527721088@qq.com -* Pandora - maintained by Scott Smith -* NaCl - maintained by Gabriel Jacobo - -Platforms that need maintainers -=============================== +We maintain the list of supported platforms on our wiki now, and how to +build and install SDL for those platforms: + + https://wiki.libsdl.org/Installation + diff --git a/docs/README-porting.md b/docs/README-porting.md index d93c65bd3..cf2d3eaca 100644 --- a/docs/README-porting.md +++ b/docs/README-porting.md @@ -15,7 +15,7 @@ There are two basic ways of building SDL at the moment: If you have a GNUish system, then you might try this. Edit configure.in, take a look at the large section labelled: - "Set up the configuration based on the target platform!" + "Set up the configuration based on the host platform!" Add a section for your platform, and then re-run autogen.sh and build! 2. Using an IDE: diff --git a/docs/README-winrt.md b/docs/README-winrt.md index fdc669f10..75cd7cd2b 100644 --- a/docs/README-winrt.md +++ b/docs/README-winrt.md @@ -90,10 +90,12 @@ Here is a rough list of what works, and what doens't: * keyboard input. Most of WinRT's documented virtual keys are supported, as well as many keys with documented hardware scancodes. * OpenGL. Experimental support for OpenGL ES 2 is available via the ANGLE - project, using either MS Open Technologies' repository, at - https://github.com/msopentech/angle (both the "winrt" and "future-dev" - branches are supported), or the official ANGLE repository, at - https://chromium.googlesource.com/angle/angle + project, using either: + * MS Open Technologies' "ms-master" repository, at https://github.com/MSOpenTech/angle + (for use with Windows 8.1+ or Windows Phone 8.1+) + * MS Open Technologies' "angle-win8.0" repository, at https://github.com/MSOpenTech/angle-win8.0 + (for Windows 8.0 only!) + * Google's main ANGLE repository, at https://chromium.googlesource.com/angle/angle * SDLmain. WinRT uses a different signature for each app's main() function. SDL-based apps that use this port must compile in SDL_winrt_main_NonXAML.cpp (in `SDL\src\main\winrt\`) directly in order for their C-style main() @@ -112,6 +114,11 @@ Here is a rough list of what works, and what doens't: supported by WinRT itself. * joysticks and game controllers that aren't supported by Microsoft's XInput API. + * turning off VSync when rendering on Windows Phone. Attempts to turn VSync + off on Windows Phone result either in Direct3D not drawing anything, or it + forcing VSync back on. As such, SDL_RENDERER_PRESENTVSYNC will always get + turned-on on Windows Phone. This limitation is not present in non-Phone + WinRT (such as Windows 8.x), where turning off VSync appears to work. * probably anything else that's not listed as supported diff --git a/docs/README.md b/docs/README.md index de173bd28..4e3106920 100644 --- a/docs/README.md +++ b/docs/README.md @@ -33,6 +33,7 @@ More documentation and FAQs are available online at [the wiki](http://wiki.libsd - [CMake](README-cmake.md) - [DirectFB](README-directfb.md) - [DynAPI](README-dynapi.md) +- [Emscripten](README-emscripten.md) - [Gesture](README-gesture.md) - [Mercurial](README-hg.md) - [iOS](README-ios.md) diff --git a/include/SDL_assert.h b/include/SDL_assert.h index 94d998770..0d7229d02 100644 --- a/include/SDL_assert.h +++ b/include/SDL_assert.h @@ -86,8 +86,10 @@ This also solves the problem of... disable assertions. */ +/* "while (0,0)" fools Microsoft's compiler's /W4 warning level into thinking + this condition isn't constant. And looks like an owl's face! */ #ifdef _MSC_VER /* stupid /W4 warnings. */ -#define SDL_NULL_WHILE_LOOP_CONDITION (-1 == __LINE__) +#define SDL_NULL_WHILE_LOOP_CONDITION (0,0) #else #define SDL_NULL_WHILE_LOOP_CONDITION (0) #endif @@ -102,9 +104,9 @@ typedef enum SDL_ASSERTION_ABORT, /**< Terminate the program. */ SDL_ASSERTION_IGNORE, /**< Ignore the assert. */ SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */ -} SDL_assert_state; +} SDL_AssertState; -typedef struct SDL_assert_data +typedef struct SDL_AssertData { int always_ignore; unsigned int trigger_count; @@ -112,13 +114,13 @@ typedef struct SDL_assert_data const char *filename; int linenum; const char *function; - const struct SDL_assert_data *next; -} SDL_assert_data; + const struct SDL_AssertData *next; +} SDL_AssertData; #if (SDL_ASSERT_LEVEL > 0) /* Never call this directly. Use the SDL_assert* macros. */ -extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, +extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *, const char *, const char *, int) #if defined(__clang__) @@ -141,10 +143,10 @@ extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, #define SDL_enabled_assert(condition) \ do { \ while ( !(condition) ) { \ - static struct SDL_assert_data sdl_assert_data = { \ + static struct SDL_AssertData sdl_assert_data = { \ 0, 0, #condition, 0, 0, 0, 0 \ }; \ - const SDL_assert_state sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \ + const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \ if (sdl_assert_state == SDL_ASSERTION_RETRY) { \ continue; /* go again. */ \ } else if (sdl_assert_state == SDL_ASSERTION_BREAK) { \ @@ -181,8 +183,8 @@ extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *, #define SDL_assert_always(condition) SDL_enabled_assert(condition) -typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)( - const SDL_assert_data* data, void* userdata); +typedef SDL_AssertState (SDLCALL *SDL_AssertionHandler)( + const SDL_AssertData* data, void* userdata); /** * \brief Set an application-defined assertion handler. @@ -199,7 +201,7 @@ typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)( * * This callback is NOT reset to SDL's internal handler upon SDL_Quit()! * - * \return SDL_assert_state value of how to handle the assertion failure. + * \return SDL_AssertState value of how to handle the assertion failure. * * \param handler Callback function, called when an assertion fails. * \param userdata A pointer passed to the callback as-is. @@ -246,7 +248,7 @@ extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puse * The proper way to examine this data looks something like this: * * - * const SDL_assert_data *item = SDL_GetAssertionReport(); + * const SDL_AssertData *item = SDL_GetAssertionReport(); * while (item) { * printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", * item->condition, item->function, item->filename, @@ -259,7 +261,7 @@ extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puse * \return List of all assertions. * \sa SDL_ResetAssertionReport */ -extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void); +extern DECLSPEC const SDL_AssertData * SDLCALL SDL_GetAssertionReport(void); /** * \brief Reset the list of all assertion failures. @@ -270,6 +272,12 @@ extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void); */ extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void); + +/* these had wrong naming conventions until 2.0.4. Please update your app! */ +#define SDL_assert_state SDL_AssertState +#define SDL_assert_data SDL_AssertData + + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/include/SDL_atomic.h b/include/SDL_atomic.h index 6f308ce84..09e78de7f 100644 --- a/include/SDL_atomic.h +++ b/include/SDL_atomic.h @@ -122,7 +122,7 @@ extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock); void _ReadWriteBarrier(void); #pragma intrinsic(_ReadWriteBarrier) #define SDL_CompilerBarrier() _ReadWriteBarrier() -#elif defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120)) +#elif (defined(__GNUC__) && !defined(__EMSCRIPTEN__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120)) /* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */ #define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory") #else diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index a0e4cb0e7..db245aa49 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -217,6 +217,7 @@ #cmakedefine SDL_AUDIO_DRIVER_WINMM @SDL_AUDIO_DRIVER_WINMM@ #cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@ #cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@ +#cmakedefine SDL_AUDIO_DRIVER_EMSCRIPTEN @SDL_AUDIO_DRIVER_EMSCRIPTEN@ /* Enable various input drivers */ #cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@ @@ -230,6 +231,7 @@ #cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@ #cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@ #cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@ +#cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@ #cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@ #cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@ #cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@ @@ -267,18 +269,16 @@ #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@ #cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON@ +#cmakedefine SDL_VIDEO_DRIVER_EMSCRIPTEN @SDL_VIDEO_DRIVER_EMSCRIPTEN@ #cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@ #cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@ @@ -325,6 +325,7 @@ #cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@ #cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@ #cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@ +#cmakedefine SDL_POWER_EMSCRIPTEN @SDL_POWER_EMSCRIPTEN@ #cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@ /* Enable system filesystem support */ @@ -333,6 +334,7 @@ #cmakedefine SDL_FILESYSTEM_DUMMY @SDL_FILESYSTEM_DUMMY@ #cmakedefine SDL_FILESYSTEM_UNIX @SDL_FILESYSTEM_UNIX@ #cmakedefine SDL_FILESYSTEM_WINDOWS @SDL_FILESYSTEM_WINDOWS@ +#cmakedefine SDL_FILESYSTEM_EMSCRIPTEN @SDL_FILESYSTEM_EMSCRIPTEN@ /* Enable assembly routines */ #cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 300149ea3..925bfaa1a 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -228,6 +228,7 @@ #undef SDL_AUDIO_DRIVER_WINMM #undef SDL_AUDIO_DRIVER_FUSIONSOUND #undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC +#undef SDL_AUDIO_DRIVER_EMSCRIPTEN /* Enable various input drivers */ #undef SDL_INPUT_LINUXEV @@ -243,6 +244,7 @@ #undef SDL_JOYSTICK_WINMM #undef SDL_JOYSTICK_USBHID #undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H +#undef SDL_JOYSTICK_EMSCRIPTEN #undef SDL_HAPTIC_DUMMY #undef SDL_HAPTIC_LINUX #undef SDL_HAPTIC_IOKIT @@ -287,6 +289,7 @@ #undef SDL_VIDEO_DRIVER_X11 #undef SDL_VIDEO_DRIVER_RPI #undef SDL_VIDEO_DRIVER_ANDROID +#undef SDL_VIDEO_DRIVER_EMSCRIPTEN #undef SDL_VIDEO_DRIVER_X11_DYNAMIC #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT #undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR @@ -336,6 +339,7 @@ #undef SDL_POWER_MACOSX #undef SDL_POWER_HAIKU #undef SDL_POWER_ANDROID +#undef SDL_POWER_EMSCRIPTEN #undef SDL_POWER_HARDWIRED /* Enable system filesystem support */ @@ -345,6 +349,8 @@ #undef SDL_FILESYSTEM_UNIX #undef SDL_FILESYSTEM_WINDOWS #undef SDL_FILESYSTEM_NACL +#undef SDL_FILESYSTEM_ANDROID +#undef SDL_FILESYSTEM_EMSCRIPTEN /* Enable assembly routines */ #undef SDL_ASSEMBLY_ROUTINES diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 4e3eb2c92..79da3667b 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -145,6 +145,9 @@ /* enable iPhone keyboard support */ #define SDL_IPHONE_KEYBOARD 1 +/* enable iOS extended launch screen */ +#define SDL_IPHONE_LAUNCHSCREEN 1 + /* enable joystick subsystem */ #define SDL_JOYSTICK_DISABLED 0 diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index 96c53c2e9..ff84f0960 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2012 Sam Lantinga + Copyright (C) 1997-2014 Sam Lantinga This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/SDL_events.h b/include/SDL_events.h index f5136424e..ee61421f6 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -134,6 +134,10 @@ typedef enum /* Drag and drop events */ SDL_DROPFILE = 0x1000, /**< The system requests a file open */ + /* Audio hotplug events */ + SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */ + SDL_AUDIODEVICEREMOVED, /**< An audio device has been removed. */ + /* Render events */ SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset and their contents need to be updated */ SDL_RENDER_DEVICE_RESET, /**< The device has been reset and all textures need to be recreated */ @@ -260,6 +264,7 @@ typedef struct SDL_MouseWheelEvent Uint32 which; /**< The mouse instance id, or SDL_TOUCH_MOUSEID */ Sint32 x; /**< The amount scrolled horizontally, positive to the right and negative to the left */ Sint32 y; /**< The amount scrolled vertically, positive away from the user and negative toward the user */ + Uint32 direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */ } SDL_MouseWheelEvent; /** @@ -381,6 +386,20 @@ typedef struct SDL_ControllerDeviceEvent Sint32 which; /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */ } SDL_ControllerDeviceEvent; +/** + * \brief Audio device event structure (event.adevice.*) + */ +typedef struct SDL_AudioDeviceEvent +{ + Uint32 type; /**< ::SDL_AUDIODEVICEADDED, or ::SDL_AUDIODEVICEREMOVED */ + Uint32 timestamp; + Uint32 which; /**< The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event */ + Uint8 iscapture; /**< zero if an output device, non-zero if a capture device. */ + Uint8 padding1; + Uint8 padding2; + Uint8 padding3; +} SDL_AudioDeviceEvent; + /** * \brief Touch finger event structure (event.tfinger.*) @@ -421,7 +440,7 @@ typedef struct SDL_MultiGestureEvent */ typedef struct SDL_DollarGestureEvent { - Uint32 type; /**< ::SDL_DOLLARGESTURE */ + Uint32 type; /**< ::SDL_DOLLARGESTURE or ::SDL_DOLLARRECORD */ Uint32 timestamp; SDL_TouchID touchId; /**< The touch device id */ SDL_GestureID gestureId; @@ -515,6 +534,7 @@ typedef union SDL_Event SDL_ControllerAxisEvent caxis; /**< Game Controller axis event data */ SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */ SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */ + SDL_AudioDeviceEvent adevice; /**< Audio device event data */ SDL_QuitEvent quit; /**< Quit request event data */ SDL_UserEvent user; /**< Custom event data */ SDL_SysWMEvent syswm; /**< System dependent window event data */ diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index 9df526a76..5c9082ced 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -241,7 +241,8 @@ SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller, /** * Get the current state of an axis control on a game controller. * - * The state is a value ranging from -32768 to 32767. + * The state is a value ranging from -32768 to 32767 (except for the triggers, + * which range from 0 to 32767). * * The axis indices start at index 0. */ diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 2366ddd4d..04fa9d500 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -272,8 +272,9 @@ extern "C" { #define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS" /** - * \brief A variable controlling whether an Android built-in accelerometer should be - * listed as a joystick device, rather than listing actual joysticks only. + * \brief A variable controlling whether the Android / iOS built-in + * accelerometer should be listed as a joystick device, rather than listing + * actual joysticks only. * * This variable can be set to the following values: * "0" - List only real joysticks and accept input from them @@ -356,7 +357,7 @@ extern "C" { /** - * \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac) + * \brief If set to 1, then do not allow high-DPI windows. ("Retina" on Mac and iOS) */ #define SDL_HINT_VIDEO_HIGHDPI_DISABLED "SDL_VIDEO_HIGHDPI_DISABLED" @@ -543,6 +544,44 @@ extern "C" { */ #define SDL_HINT_IME_INTERNAL_EDITING "SDL_IME_INTERNAL_EDITING" + /** + * \brief A variable to control whether mouse and touch events are to be treated together or separately + * + * The variable can be set to the following values: + * "0" - Mouse events will be handled as touch events, and touch will raise fake mouse + * events. This is the behaviour of SDL <= 2.0.3. (default) + * "1" - Mouse events will be handled separately from pure touch events. + * + * The value of this hint is used at runtime, so it can be changed at any time. + */ +#define SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH" + +/** + * \brief override the binding element for keyboard inputs for Emscripten builds + * + * This hint only applies to the emscripten platform + * + * The variable can be one of + * "#window" - The javascript window object (this is the default) + * "#document" - The javascript document object + * "#screen" - the javascript window.screen object + * "#canvas" - the WebGL canvas element + * any other string without a leading # sign applies to the element on the page with that ID. + */ +#define SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT" + +/** + * \brief Tell SDL not to catch the SIGINT or SIGTERM signals. + * + * This hint only applies to Unix-like platforms. + * + * The variable can be set to the following values: + * "0" - SDL will install a SIGINT and SIGTERM handler, and when it + * catches a signal, convert it into an SDL_QUIT event. + * "1" - SDL will not install a signal handler at all. + */ +#define SDL_HINT_NO_SIGNAL_HANDLERS "SDL_NO_SIGNAL_HANDLERS" + /** * \brief An enumeration of hint priorities */ diff --git a/include/SDL_main.h b/include/SDL_main.h index 5dd73a9f5..347a44d02 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -142,14 +142,11 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void); * \brief Initializes and launches an SDL/WinRT application. * * \param mainFunction The SDL app's C-style main(). - * \param xamlBackgroundPanel An optional, XAML-based, background panel. - * For Non-XAML apps, this value must be set to NULL. For XAML apps, - * pass in a pointer to a SwapChainBackgroundPanel, casted to an - * IInspectable (via reinterpret_cast). + * \param reserved Reserved for future use; should be NULL * \ret 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more * information on the failure. */ -extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel); +extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * reserved); #endif /* __WINRT__ */ diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index e71a0c9e5..dd0842790 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -60,6 +60,15 @@ typedef enum SDL_NUM_SYSTEM_CURSORS } SDL_SystemCursor; +/** + * \brief Scroll direction types for the Scroll event + */ +typedef enum +{ + SDL_MOUSEWHEEL_NORMAL, /**< The scroll direction is normal */ + SDL_MOUSEWHEEL_FLIPPED /**< The scroll direction is flipped / natural */ +} SDL_MouseWheelDirection; + /* Function prototypes */ /** diff --git a/include/SDL_opengl_glext.h b/include/SDL_opengl_glext.h index 7e840f72a..cd3869fe7 100644 --- a/include/SDL_opengl_glext.h +++ b/include/SDL_opengl_glext.h @@ -2988,6 +2988,11 @@ GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program); #define GL_ARB_framebuffer_sRGB 1 #endif /* GL_ARB_framebuffer_sRGB */ +#ifndef GL_KHR_context_flush_control +#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB +#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC +#endif /* GL_KHR_context_flush_control */ + #ifndef GL_ARB_geometry_shader4 #define GL_ARB_geometry_shader4 1 #define GL_LINES_ADJACENCY_ARB 0x000A diff --git a/include/SDL_render.h b/include/SDL_render.h index e6084e9e7..12da6f8b3 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -81,8 +81,8 @@ typedef struct SDL_RendererInfo Uint32 flags; /**< Supported ::SDL_RendererFlags */ Uint32 num_texture_formats; /**< The number of available texture formats */ Uint32 texture_formats[16]; /**< The available texture formats */ - int max_texture_width; /**< The maximimum texture width */ - int max_texture_height; /**< The maximimum texture height */ + int max_texture_width; /**< The maximum texture width */ + int max_texture_height; /**< The maximum texture height */ } SDL_RendererInfo; /** @@ -792,7 +792,7 @@ extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer, * \param dstrect A pointer to the destination rectangle, or NULL for the * entire rendering target. * \param angle An angle in degrees that indicates the rotation that will be applied to dstrect - * \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done aroud dstrect.w/2, dstrect.h/2) + * \param center A pointer to a point indicating the point around which dstrect will be rotated (if NULL, rotation will be done around dstrect.w/2, dstrect.h/2). * \param flip An SDL_RendererFlip value stating which flipping actions should be performed on the texture * * \return 0 on success, or -1 on error diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 78d3402e7..2a0aba442 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -172,7 +172,9 @@ typedef uint64_t Uint64; #ifdef PRIs64 #define SDL_PRIs64 PRIs64 #elif defined(__WIN32__) -#define SDL_PRIs64 "I64" +#define SDL_PRIs64 "I64d" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIs64 "ld" #else #define SDL_PRIs64 "lld" #endif @@ -182,10 +184,34 @@ typedef uint64_t Uint64; #define SDL_PRIu64 PRIu64 #elif defined(__WIN32__) #define SDL_PRIu64 "I64u" +#elif defined(__LINUX__) && defined(__LP64__) +#define SDL_PRIu64 "lu" #else #define SDL_PRIu64 "llu" #endif #endif +#ifndef SDL_PRIx64 +#ifdef PRIx64 +#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 +#endif +#ifndef SDL_PRIX64 +#ifdef PRIX64 +#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 +#endif /* Annotations to help code analysis tools */ #ifdef SDL_DISABLE_ANALYZE_MACROS @@ -200,7 +226,7 @@ typedef uint64_t Uint64; #define SDL_PRINTF_VARARG_FUNC( fmtargnumber ) #define SDL_SCANF_VARARG_FUNC( fmtargnumber ) #else -#if _MSC_VER >= 1600 /* VS 2010 and above */ +#if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */ #include #define SDL_IN_BYTECAP(x) _In_bytecount_(x) @@ -361,11 +387,6 @@ SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords) extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len); -SDL_FORCE_INLINE void *SDL_memcpy4(SDL_OUT_BYTECAP(dwords*4) void *dst, SDL_IN_BYTECAP(dwords*4) const void *src, size_t dwords) -{ - return SDL_memcpy(dst, src, dwords * 4); -} - extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len); extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len); @@ -462,6 +483,39 @@ extern DECLSPEC char *SDLCALL SDL_iconv_string(const char *tocode, #define SDL_iconv_utf8_ucs2(S) (Uint16 *)SDL_iconv_string("UCS-2-INTERNAL", "UTF-8", S, SDL_strlen(S)+1) #define SDL_iconv_utf8_ucs4(S) (Uint32 *)SDL_iconv_string("UCS-4-INTERNAL", "UTF-8", S, SDL_strlen(S)+1) +/* force builds using Clang's static analysis tools to use literal C runtime + here, since there are possibly tests that are ineffective otherwise. */ +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_malloc malloc +#define SDL_calloc calloc +#define SDL_realloc realloc +#define SDL_free free +#define SDL_memset memset +#define SDL_memcpy memcpy +#define SDL_memmove memmove +#define SDL_memcmp memcmp +#define SDL_strlen strlen +#define SDL_strlcpy strlcpy +#define SDL_strlcat strlcat +#define SDL_strdup strdup +#define SDL_strchr strchr +#define SDL_strrchr strrchr +#define SDL_strstr strstr +#define SDL_strcmp strcmp +#define SDL_strncmp strncmp +#define SDL_strcasecmp strcasecmp +#define SDL_strncasecmp strncasecmp +#define SDL_sscanf sscanf +#define SDL_vsscanf vsscanf +#define SDL_snprintf snprintf +#define SDL_vsnprintf vsnprintf +#endif + +SDL_FORCE_INLINE void *SDL_memcpy4(SDL_OUT_BYTECAP(dwords*4) void *dst, SDL_IN_BYTECAP(dwords*4) const void *src, size_t dwords) +{ + return SDL_memcpy(dst, src, dwords * 4); +} + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/include/SDL_system.h b/include/SDL_system.h index 78d5b0d0a..ee9bb4816 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -43,19 +43,25 @@ extern "C" { /* Platform specific functions for Windows */ #ifdef __WIN32__ -/* Returns the D3D9 adapter index that matches the specified display index. +/** + \brief Returns the D3D9 adapter index that matches the specified display index. + This adapter index can be passed to IDirect3D9::CreateDevice and controls on which monitor a full screen application will appear. */ extern DECLSPEC int SDLCALL SDL_Direct3D9GetAdapterIndex( int displayIndex ); -/* Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer. +typedef struct IDirect3DDevice9 IDirect3DDevice9; +/** + \brief Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer. + Once you are done using the device, you should release it to avoid a resource leak. */ -typedef struct IDirect3DDevice9 IDirect3DDevice9; extern DECLSPEC IDirect3DDevice9* SDLCALL SDL_RenderGetD3D9Device(SDL_Renderer * renderer); -/* Returns the DXGI Adapter and Output indices for the specified display index. +/** + \brief Returns the DXGI Adapter and Output indices for the specified display index. + These can be passed to EnumAdapters and EnumOutputs respectively to get the objects required to create a DX10 or DX11 device and swap chain. */ @@ -67,7 +73,10 @@ extern DECLSPEC SDL_bool SDLCALL SDL_DXGIGetOutputInfo( int displayIndex, int *a /* Platform specific functions for iOS */ #if defined(__IPHONEOS__) && __IPHONEOS__ +#define SDL_iOSSetAnimationCallback(window, interval, callback, callbackParam) SDL_iPhoneSetAnimationCallback(window, interval, callback, callbackParam) extern DECLSPEC int SDLCALL SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam); + +#define SDL_iOSSetEventPump(enabled) SDL_iPhoneSetEventPump(enabled) extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled); #endif /* __IPHONEOS__ */ @@ -76,12 +85,16 @@ extern DECLSPEC void SDLCALL SDL_iPhoneSetEventPump(SDL_bool enabled); /* Platform specific functions for Android */ #if defined(__ANDROID__) && __ANDROID__ -/* Get the JNI environment for the current thread +/** + \brief Get the JNI environment for the current thread + This returns JNIEnv*, but the prototype is void* so we don't need jni.h */ extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(); -/* Get the SDL Activity object for the application +/** + \brief Get the SDL Activity object for the application + This returns jobject, but the prototype is void* so we don't need jni.h The jobject returned by SDL_AndroidGetActivity is a local reference. It is the caller's responsibility to properly release it @@ -89,26 +102,33 @@ extern DECLSPEC void * SDLCALL SDL_AndroidGetJNIEnv(); */ extern DECLSPEC void * SDLCALL SDL_AndroidGetActivity(); -/* See the official Android developer guide for more information: +/** + See the official Android developer guide for more information: http://developer.android.com/guide/topics/data/data-storage.html */ #define SDL_ANDROID_EXTERNAL_STORAGE_READ 0x01 #define SDL_ANDROID_EXTERNAL_STORAGE_WRITE 0x02 -/* Get the path used for internal storage for this application. +/** + \brief Get the path used for internal storage for this application. + This path is unique to your application and cannot be written to by other applications. */ extern DECLSPEC const char * SDLCALL SDL_AndroidGetInternalStoragePath(); -/* Get the current state of external storage, a bitmask of these values: +/** + \brief Get the current state of external storage, a bitmask of these values: SDL_ANDROID_EXTERNAL_STORAGE_READ SDL_ANDROID_EXTERNAL_STORAGE_WRITE + If external storage is currently unavailable, this will return 0. */ extern DECLSPEC int SDLCALL SDL_AndroidGetExternalStorageState(); -/* Get the path used for external storage for this application. +/** + \brief Get the path used for external storage for this application. + This path is unique to your application, but is public and can be written to by other applications. */ @@ -151,7 +171,7 @@ typedef enum * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx * * \param pathType The type of path to retrieve. - * \ret A UCS-2 string (16-bit, wide-char) containing the path, or NULL + * \return A UCS-2 string (16-bit, wide-char) containing the path, or NULL * if the path is not available for any reason. Not all paths are * available on all versions of Windows. This is especially true on * Windows Phone. Check the documentation for the given @@ -168,7 +188,7 @@ extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx * * \param pathType The type of path to retrieve. - * \ret A UTF-8 string (8-bit, multi-byte) containing the path, or NULL + * \return A UTF-8 string (8-bit, multi-byte) containing the path, or NULL * if the path is not available for any reason. Not all paths are * available on all versions of Windows. This is especially true on * Windows Phone. Check the documentation for the given diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index 03c3b025d..fa1145534 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -98,6 +98,7 @@ typedef struct _NSWindow NSWindow; typedef struct _UIWindow UIWindow; typedef struct _UIViewController UIViewController; #endif +typedef Uint32 GLuint; #endif #if defined(SDL_VIDEO_DRIVER_ANDROID) @@ -186,6 +187,7 @@ struct SDL_SysWMinfo struct { HWND window; /**< The window handle */ + HDC hdc; /**< The window device context */ } win; #endif #if defined(SDL_VIDEO_DRIVER_WINRT) @@ -227,6 +229,8 @@ struct SDL_SysWMinfo #else UIWindow *window; /* The UIKit window */ #endif + GLuint framebuffer; /* The GL view's Framebuffer Object. It must be bound when rendering to the screen using GL. */ + GLuint colorbuffer; /* The GL view's color Renderbuffer Object. It must be bound when SDL_GL_SwapWindow is called. */ } uikit; #endif #if defined(SDL_VIDEO_DRIVER_WAYLAND) diff --git a/include/SDL_video.h b/include/SDL_video.h index 4a2fb0458..fe1386889 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -189,7 +189,8 @@ typedef enum SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_SHARE_WITH_CURRENT_CONTEXT, - SDL_GL_FRAMEBUFFER_SRGB_CAPABLE + SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, + SDL_GL_CONTEXT_RELEASE_BEHAVIOR } SDL_GLattr; typedef enum @@ -207,6 +208,12 @@ typedef enum SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008 } SDL_GLcontextFlag; +typedef enum +{ + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000, + SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001 +} SDL_GLcontextReleaseFlag; + /* Function prototypes */ @@ -715,6 +722,9 @@ extern DECLSPEC int SDLCALL SDL_UpdateWindowSurfaceRects(SDL_Window * window, * \param window The window for which the input grab mode should be set. * \param grabbed This is SDL_TRUE to grab input, and SDL_FALSE to release input. * + * If the caller enables a grab while another window is currently grabbed, + * the other window loses its grab in favor of the caller's window. + * * \sa SDL_GetWindowGrab() */ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, @@ -729,6 +739,15 @@ extern DECLSPEC void SDLCALL SDL_SetWindowGrab(SDL_Window * window, */ extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window); +/** + * \brief Get the window that currently has an input grab enabled. + * + * \return This returns the window if input is grabbed, and NULL otherwise. + * + * \sa SDL_SetWindowGrab() + */ +extern DECLSPEC SDL_Window * SDLCALL SDL_GetGrabbedWindow(void); + /** * \brief Set the brightness (gamma correction) for a window. * diff --git a/premake/Xcode-iOS/SDL_config_premake.h b/premake/Xcode-iOS/SDL_config_premake.h index e0a864173..bae64b187 100644 --- a/premake/Xcode-iOS/SDL_config_premake.h +++ b/premake/Xcode-iOS/SDL_config_premake.h @@ -126,6 +126,9 @@ #ifndef SDL_IPHONE_KEYBOARD #define SDL_IPHONE_KEYBOARD 1 #endif +#ifndef SDL_IPHONE_LAUNCHSCREEN +#define SDL_IPHONE_LAUNCHSCREEN 1 +#endif #ifndef SDL_POWER_UIKIT #define SDL_POWER_UIKIT 1 #endif diff --git a/src/SDL.c b/src/SDL.c index 69872dd6c..0e3512009 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -405,6 +405,8 @@ SDL_GetPlatform() return "BSDI"; #elif __DREAMCAST__ return "Dreamcast"; +#elif __EMSCRIPTEN__ + return "Emscripten"; #elif __FREEBSD__ return "FreeBSD"; #elif __HAIKU__ diff --git a/src/SDL_error.c b/src/SDL_error.c index 2df29aa13..80e8620f8 100644 --- a/src/SDL_error.c +++ b/src/SDL_error.c @@ -120,7 +120,7 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) so that it supports internationalization and thread-safe errors. */ static char * -SDL_GetErrorMsg(char *errstr, unsigned int maxlen) +SDL_GetErrorMsg(char *errstr, int maxlen) { SDL_error *error; @@ -163,37 +163,55 @@ SDL_GetErrorMsg(char *errstr, unsigned int maxlen) len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_i); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 'f': len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_f); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 'p': len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_ptr); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + case 's': len = SDL_snprintf(msg, maxlen, tmp, SDL_LookupString(error->args[argi++]. buf)); - msg += len; - maxlen -= len; + if (len > 0) { + msg += len; + maxlen -= len; + } break; + } } else { *msg++ = *fmt++; maxlen -= 1; } } + + /* slide back if we've overshot the end of our buffer. */ + if (maxlen < 0) { + msg -= (-maxlen) + 1; + } + *msg = 0; /* NULL terminate the string */ } return (errstr); diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 7559d6ca4..dfc55fa62 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -51,9 +51,7 @@ extern AudioBootStrap QSAAUDIO_bootstrap; extern AudioBootStrap SUNAUDIO_bootstrap; extern AudioBootStrap ARTS_bootstrap; extern AudioBootStrap ESD_bootstrap; -#if SDL_AUDIO_DRIVER_NACL extern AudioBootStrap NACLAUD_bootstrap; -#endif extern AudioBootStrap NAS_bootstrap; extern AudioBootStrap XAUDIO2_bootstrap; extern AudioBootStrap DSOUND_bootstrap; @@ -71,6 +69,7 @@ extern AudioBootStrap FUSIONSOUND_bootstrap; extern AudioBootStrap ANDROIDAUD_bootstrap; extern AudioBootStrap PSPAUD_bootstrap; extern AudioBootStrap SNDIO_bootstrap; +extern AudioBootStrap EmscriptenAudio_bootstrap; /* Available audio drivers */ @@ -140,6 +139,9 @@ static const AudioBootStrap *const bootstrap[] = { #endif #if SDL_AUDIO_DRIVER_PSP &PSPAUD_bootstrap, +#endif +#if SDL_AUDIO_DRIVER_EMSCRIPTEN + &EmscriptenAudio_bootstrap, #endif NULL }; @@ -159,8 +161,16 @@ get_audio_device(SDL_AudioDeviceID id) /* stubs for audio drivers that don't need a specific entry point... */ static void -SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn) -{ /* no-op. */ +SDL_AudioDetectDevices_Default(void) +{ + /* you have to write your own implementation if these assertions fail. */ + SDL_assert(current_audio.impl.OnlyHasDefaultOutputDevice); + SDL_assert(current_audio.impl.OnlyHasDefaultInputDevice || !current_audio.impl.HasCaptureSupport); + + SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) ((size_t) 0x1)); + if (current_audio.impl.HasCaptureSupport) { + SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) ((size_t) 0x2)); + } } static void @@ -205,10 +215,16 @@ SDL_AudioDeinitialize_Default(void) { /* no-op. */ } +static void +SDL_AudioFreeDeviceHandle_Default(void *handle) +{ /* no-op. */ +} + + static int -SDL_AudioOpenDevice_Default(_THIS, const char *devname, int iscapture) +SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture) { - return -1; + return SDL_Unsupported(); } static SDL_INLINE SDL_bool @@ -265,71 +281,139 @@ finalize_audio_entry_points(void) FILL_STUB(CloseDevice); FILL_STUB(LockDevice); FILL_STUB(UnlockDevice); + FILL_STUB(FreeDeviceHandle); FILL_STUB(Deinitialize); #undef FILL_STUB } -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ -/* Streaming functions (for when the input and output buffer sizes are different) */ -/* Write [length] bytes from buf into the streamer */ -static void -SDL_StreamWrite(SDL_AudioStreamer * stream, Uint8 * buf, int length) -{ - int i; - for (i = 0; i < length; ++i) { - stream->buffer[stream->write_pos] = buf[i]; - ++stream->write_pos; - } -} - -/* Read [length] bytes out of the streamer into buf */ -static void -SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length) -{ - int i; - - for (i = 0; i < length; ++i) { - buf[i] = stream->buffer[stream->read_pos]; - ++stream->read_pos; - } -} +/* device hotplug support... */ static int -SDL_StreamLength(SDL_AudioStreamer * stream) +add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount) { - return (stream->write_pos - stream->read_pos) % stream->max_len; -} - -/* Initialize the stream by allocating the buffer and setting the read/write heads to the beginning */ -#if 0 -static int -SDL_StreamInit(SDL_AudioStreamer * stream, int max_len, Uint8 silence) -{ - /* First try to allocate the buffer */ - stream->buffer = (Uint8 *) SDL_malloc(max_len); - if (stream->buffer == NULL) { + int retval = -1; + const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1; + SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size); + if (item == NULL) { return -1; } - stream->max_len = max_len; - stream->read_pos = 0; - stream->write_pos = 0; + SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */ - /* Zero out the buffer */ - SDL_memset(stream->buffer, silence, max_len); + item->handle = handle; + SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem)); - return 0; + SDL_LockMutex(current_audio.detectionLock); + item->next = *devices; + *devices = item; + retval = (*devCount)++; + SDL_UnlockMutex(current_audio.detectionLock); + + return retval; } -#endif -/* Deinitialize the stream simply by freeing the buffer */ -static void -SDL_StreamDeinit(SDL_AudioStreamer * stream) +static SDL_INLINE int +add_capture_device(const char *name, void *handle) { - SDL_free(stream->buffer); + /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/ + return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); } -#endif + +static SDL_INLINE int +add_output_device(const char *name, void *handle) +{ + return add_audio_device(name, handle, ¤t_audio.outputDevices, ¤t_audio.outputDeviceCount); +} + +static void +free_device_list(SDL_AudioDeviceItem **devices, int *devCount) +{ + SDL_AudioDeviceItem *item, *next; + for (item = *devices; item != NULL; item = next) { + next = item->next; + if (item->handle != NULL) { + current_audio.impl.FreeDeviceHandle(item->handle); + } + SDL_free(item); + } + *devices = NULL; + *devCount = 0; +} + + +/* The audio backends call this when a new device is plugged in. */ +void +SDL_AddAudioDevice(const int iscapture, const char *name, void *handle) +{ + const int device_index = iscapture ? add_capture_device(name, handle) : add_output_device(name, handle); + if (device_index != -1) { + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_AUDIODEVICEADDED) == SDL_ENABLE) { + SDL_Event event; + SDL_zero(event); + event.adevice.type = SDL_AUDIODEVICEADDED; + event.adevice.which = device_index; + event.adevice.iscapture = iscapture; + SDL_PushEvent(&event); + } + } +} + +/* The audio backends call this when a currently-opened device is lost. */ +void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device) +{ + SDL_assert(get_audio_device(device->id) == device); + + if (!device->enabled) { + return; + } + + /* Ends the audio callback and mark the device as STOPPED, but the + app still needs to close the device to free resources. */ + current_audio.impl.LockDevice(device); + device->enabled = 0; + current_audio.impl.UnlockDevice(device); + + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) { + SDL_Event event; + SDL_zero(event); + event.adevice.type = SDL_AUDIODEVICEREMOVED; + event.adevice.which = device->id; + event.adevice.iscapture = device->iscapture ? 1 : 0; + SDL_PushEvent(&event); + } +} + +static void +mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag) +{ + SDL_AudioDeviceItem *item; + SDL_assert(handle != NULL); + for (item = devices; item != NULL; item = item->next) { + if (item->handle == handle) { + item->handle = NULL; + *removedFlag = SDL_TRUE; + return; + } + } +} + +/* The audio backends call this when a device is removed from the system. */ +void +SDL_RemoveAudioDevice(const int iscapture, void *handle) +{ + SDL_LockMutex(current_audio.detectionLock); + if (iscapture) { + mark_device_removed(handle, current_audio.inputDevices, ¤t_audio.captureDevicesRemoved); + } else { + mark_device_removed(handle, current_audio.outputDevices, ¤t_audio.outputDevicesRemoved); + } + SDL_UnlockMutex(current_audio.detectionLock); + current_audio.impl.FreeDeviceHandle(handle); +} + /* buffer queueing support... */ @@ -506,26 +590,17 @@ SDL_ClearQueuedAudio(SDL_AudioDeviceID devid) } -#if defined(__ANDROID__) -#include -#endif - /* The general mixing thread function */ int SDLCALL SDL_RunAudio(void *devicep) { SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; + const int silence = (int) device->spec.silence; + const Uint32 delay = ((device->spec.samples * 1000) / device->spec.freq); + const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size; Uint8 *stream; - int stream_len; - void *udata; - void (SDLCALL * fill) (void *userdata, Uint8 * stream, int len); - Uint32 delay; - -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - /* For streaming when the buffer sizes don't match up */ - Uint8 *istream; - int istream_len = 0; -#endif + void *udata = device->spec.userdata; + void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback; /* The audio mixing is always a high priority thread */ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); @@ -534,197 +609,60 @@ SDL_RunAudio(void *devicep) device->threadid = SDL_ThreadID(); current_audio.impl.ThreadInit(device); - /* Set up the mixing function */ - fill = device->spec.callback; - udata = device->spec.userdata; - - /* By default do not stream */ - device->use_streamer = 0; - - if (device->convert.needed) { -#if 0 /* !!! FIXME: I took len_div out of the structure. Use rate_incr instead? */ - /* If the result of the conversion alters the length, i.e. resampling is being used, use the streamer */ - if (device->convert.len_mult != 1 || device->convert.len_div != 1) { - /* The streamer's maximum length should be twice whichever is larger: spec.size or len_cvt */ - stream_max_len = 2 * device->spec.size; - if (device->convert.len_mult > device->convert.len_div) { - stream_max_len *= device->convert.len_mult; - stream_max_len /= device->convert.len_div; - } - if (SDL_StreamInit(&device->streamer, stream_max_len, silence) < - 0) - return -1; - device->use_streamer = 1; - - /* istream_len should be the length of what we grab from the callback and feed to conversion, - so that we get close to spec_size. I.e. we want device.spec_size = istream_len * u / d - */ - istream_len = - device->spec.size * device->convert.len_div / - device->convert.len_mult; + /* Loop, filling the audio buffers */ + while (!device->shutdown) { + /* Fill the current buffer with sound */ + if (device->convert.needed) { + stream = device->convert.buf; + } else if (device->enabled) { + stream = current_audio.impl.GetDeviceBuf(device); + } else { + /* if the device isn't enabled, we still write to the + fake_stream, so the app's callback will fire with + a regular frequency, in case they depend on that + for timing or progress. They can use hotplug + now to know if the device failed. */ + stream = NULL; } -#endif - stream_len = device->convert.len; - } else { - stream_len = device->spec.size; - } - - /* Calculate the delay while paused */ - delay = ((device->spec.samples * 1000) / device->spec.freq); - - /* Determine if the streamer is necessary here */ -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - if (device->use_streamer == 1) { - /* This code is almost the same as the old code. The difference is, instead of reading - directly from the callback into "stream", then converting and sending the audio off, - we go: callback -> "istream" -> (conversion) -> streamer -> stream -> device. - However, reading and writing with streamer are done separately: - - We only call the callback and write to the streamer when the streamer does not - contain enough samples to output to the device. - - We only read from the streamer and tell the device to play when the streamer - does have enough samples to output. - This allows us to perform resampling in the conversion step, where the output of the - resampling process can be any number. We will have to see what a good size for the - stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure. - */ - while (device->enabled) { - - if (device->paused) { - SDL_Delay(delay); - continue; - } - - /* Only read in audio if the streamer doesn't have enough already (if it does not have enough samples to output) */ - if (SDL_StreamLength(&device->streamer) < stream_len) { - /* Set up istream */ - if (device->convert.needed) { - if (device->convert.buf) { - istream = device->convert.buf; - } else { - continue; - } - } else { -/* FIXME: Ryan, this is probably wrong. I imagine we don't want to get - * a device buffer both here and below in the stream output. - */ - istream = current_audio.impl.GetDeviceBuf(device); - if (istream == NULL) { - istream = device->fake_stream; - } - } - - /* Read from the callback into the _input_ stream */ - SDL_LockMutex(device->mixer_lock); - (*fill) (udata, istream, istream_len); - SDL_UnlockMutex(device->mixer_lock); - - /* Convert the audio if necessary and write to the streamer */ - if (device->convert.needed) { - SDL_ConvertAudio(&device->convert); - if (istream == NULL) { - istream = device->fake_stream; - } - /* SDL_memcpy(istream, device->convert.buf, device->convert.len_cvt); */ - SDL_StreamWrite(&device->streamer, device->convert.buf, - device->convert.len_cvt); - } else { - SDL_StreamWrite(&device->streamer, istream, istream_len); - } - } - - /* Only output audio if the streamer has enough to output */ - if (SDL_StreamLength(&device->streamer) >= stream_len) { - /* Set up the output stream */ - if (device->convert.needed) { - if (device->convert.buf) { - stream = device->convert.buf; - } else { - continue; - } - } else { - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } - } - - /* Now read from the streamer */ - SDL_StreamRead(&device->streamer, stream, stream_len); - - /* Ready current buffer for play and change current buffer */ - if (stream != device->fake_stream) { - current_audio.impl.PlayDevice(device); - /* Wait for an audio buffer to become available */ - current_audio.impl.WaitDevice(device); - } else { - SDL_Delay(delay); - } - } + if (stream == NULL) { + stream = device->fake_stream; } - } else -#endif - { - /* Otherwise, do not use the streamer. This is the old code. */ - const int silence = (int) device->spec.silence; - /* Loop, filling the audio buffers */ - while (device->enabled) { + /* !!! FIXME: this should be LockDevice. */ + SDL_LockMutex(device->mixer_lock); + if (device->paused) { + SDL_memset(stream, silence, stream_len); + } else { + (*fill) (udata, stream, stream_len); + } + SDL_UnlockMutex(device->mixer_lock); - /* Fill the current buffer with sound */ - if (device->convert.needed) { - if (device->convert.buf) { - stream = device->convert.buf; - } else { - continue; - } + /* Convert the audio if necessary */ + if (device->enabled && device->convert.needed) { + SDL_ConvertAudio(&device->convert); + stream = current_audio.impl.GetDeviceBuf(device); + if (stream == NULL) { + stream = device->fake_stream; } else { - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } - } - - SDL_LockMutex(device->mixer_lock); - if (device->paused) { - SDL_memset(stream, silence, stream_len); - } else { - (*fill) (udata, stream, stream_len); - } - SDL_UnlockMutex(device->mixer_lock); - - /* Convert the audio if necessary */ - if (device->convert.needed) { - SDL_ConvertAudio(&device->convert); - stream = current_audio.impl.GetDeviceBuf(device); - if (stream == NULL) { - stream = device->fake_stream; - } SDL_memcpy(stream, device->convert.buf, device->convert.len_cvt); } + } - /* Ready current buffer for play and change current buffer */ - if (stream != device->fake_stream) { - current_audio.impl.PlayDevice(device); - /* Wait for an audio buffer to become available */ - current_audio.impl.WaitDevice(device); - } else { - SDL_Delay(delay); - } + /* Ready current buffer for play and change current buffer */ + if (stream == device->fake_stream) { + SDL_Delay(delay); + } else { + current_audio.impl.PlayDevice(device); + current_audio.impl.WaitDevice(device); } } - /* Wait for the audio to drain.. */ + /* Wait for the audio to drain. */ current_audio.impl.WaitDone(device); - /* If necessary, deinit the streamer */ -#if 0 /* !!! FIXME: rewrite/remove this streamer code. */ - if (device->use_streamer == 1) - SDL_StreamDeinit(&device->streamer); -#endif - - return (0); + return 0; } @@ -757,16 +695,16 @@ SDL_ParseAudioFormat(const char *string) int SDL_GetNumAudioDrivers(void) { - return (SDL_arraysize(bootstrap) - 1); + return SDL_arraysize(bootstrap) - 1; } const char * SDL_GetAudioDriver(int index) { if (index >= 0 && index < SDL_GetNumAudioDrivers()) { - return (bootstrap[index]->name); + return bootstrap[index]->name; } - return (NULL); + return NULL; } int @@ -780,8 +718,8 @@ SDL_AudioInit(const char *driver_name) SDL_AudioQuit(); /* shutdown driver if already running. */ } - SDL_memset(¤t_audio, '\0', sizeof(current_audio)); - SDL_memset(open_devices, '\0', sizeof(open_devices)); + SDL_zero(current_audio); + SDL_zero(open_devices); /* Select the proper audio driver */ if (driver_name == NULL) { @@ -797,7 +735,7 @@ SDL_AudioInit(const char *driver_name) } tried_to_init = 1; - SDL_memset(¤t_audio, 0, sizeof(current_audio)); + SDL_zero(current_audio); current_audio.name = backend->name; current_audio.desc = backend->desc; initialized = backend->init(¤t_audio.impl); @@ -813,13 +751,18 @@ SDL_AudioInit(const char *driver_name) } } - SDL_memset(¤t_audio, 0, sizeof(current_audio)); - return (-1); /* No driver was available, so fail. */ + SDL_zero(current_audio); + return -1; /* No driver was available, so fail. */ } + current_audio.detectionLock = SDL_CreateMutex(); + finalize_audio_entry_points(); - return (0); + /* Make sure we have a list of devices available at startup. */ + current_audio.impl.DetectDevices(); + + return 0; } /* @@ -831,50 +774,32 @@ SDL_GetCurrentAudioDriver() return current_audio.name; } +/* Clean out devices that we've removed but had to keep around for stability. */ static void -free_device_list(char ***devices, int *devCount) +clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *removedFlag) { - int i = *devCount; - if ((i > 0) && (*devices != NULL)) { - while (i--) { - SDL_free((*devices)[i]); + SDL_AudioDeviceItem *item = *devices; + SDL_AudioDeviceItem *prev = NULL; + int total = 0; + + while (item) { + SDL_AudioDeviceItem *next = item->next; + if (item->handle != NULL) { + total++; + prev = item; + } else { + if (prev) { + prev->next = next; + } else { + *devices = next; + } + SDL_free(item); } + item = next; } - SDL_free(*devices); - - *devices = NULL; - *devCount = 0; -} - -static -void SDL_AddCaptureAudioDevice(const char *_name) -{ - char *name = NULL; - void *ptr = SDL_realloc(current_audio.inputDevices, - (current_audio.inputDeviceCount+1) * sizeof(char*)); - if (ptr == NULL) { - return; /* oh well. */ - } - - current_audio.inputDevices = (char **) ptr; - name = SDL_strdup(_name); /* if this returns NULL, that's okay. */ - current_audio.inputDevices[current_audio.inputDeviceCount++] = name; -} - -static -void SDL_AddOutputAudioDevice(const char *_name) -{ - char *name = NULL; - void *ptr = SDL_realloc(current_audio.outputDevices, - (current_audio.outputDeviceCount+1) * sizeof(char*)); - if (ptr == NULL) { - return; /* oh well. */ - } - - current_audio.outputDevices = (char **) ptr; - name = SDL_strdup(_name); /* if this returns NULL, that's okay. */ - current_audio.outputDevices[current_audio.outputDeviceCount++] = name; + *devCount = total; + *removedFlag = SDL_FALSE; } @@ -887,29 +812,18 @@ SDL_GetNumAudioDevices(int iscapture) return -1; } - if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) { - return 0; + SDL_LockMutex(current_audio.detectionLock); + if (iscapture && current_audio.captureDevicesRemoved) { + clean_out_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount, ¤t_audio.captureDevicesRemoved); } - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { - return 1; + if (!iscapture && current_audio.outputDevicesRemoved) { + clean_out_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount, ¤t_audio.outputDevicesRemoved); + current_audio.outputDevicesRemoved = SDL_FALSE; } - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { - return 1; - } - - if (iscapture) { - free_device_list(¤t_audio.inputDevices, - ¤t_audio.inputDeviceCount); - current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice); - retval = current_audio.inputDeviceCount; - } else { - free_device_list(¤t_audio.outputDevices, - ¤t_audio.outputDeviceCount); - current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice); - retval = current_audio.outputDeviceCount; - } + retval = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + SDL_UnlockMutex(current_audio.detectionLock); return retval; } @@ -918,6 +832,8 @@ SDL_GetNumAudioDevices(int iscapture) const char * SDL_GetAudioDeviceName(int index, int iscapture) { + const char *retval = NULL; + if (!SDL_WasInit(SDL_INIT_AUDIO)) { SDL_SetError("Audio subsystem is not initialized"); return NULL; @@ -928,39 +844,28 @@ SDL_GetAudioDeviceName(int index, int iscapture) return NULL; } - if (index < 0) { - goto no_such_device; + if (index >= 0) { + SDL_AudioDeviceItem *item; + int i; + + SDL_LockMutex(current_audio.detectionLock); + item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; + i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + if (index < i) { + for (i--; i > index; i--, item = item->next) { + SDL_assert(item != NULL); + } + SDL_assert(item != NULL); + retval = item->name; + } + SDL_UnlockMutex(current_audio.detectionLock); } - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { - if (index > 0) { - goto no_such_device; - } - return DEFAULT_INPUT_DEVNAME; + if (retval == NULL) { + SDL_SetError("No such device"); } - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { - if (index > 0) { - goto no_such_device; - } - return DEFAULT_OUTPUT_DEVNAME; - } - - if (iscapture) { - if (index >= current_audio.inputDeviceCount) { - goto no_such_device; - } - return current_audio.inputDevices[index]; - } else { - if (index >= current_audio.outputDeviceCount) { - goto no_such_device; - } - return current_audio.outputDevices[index]; - } - -no_such_device: - SDL_SetError("No such device"); - return NULL; + return retval; } @@ -968,6 +873,7 @@ static void close_audio_device(SDL_AudioDevice * device) { device->enabled = 0; + device->shutdown = 1; if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); } @@ -1061,6 +967,8 @@ open_audio_device(const char *devname, int iscapture, SDL_AudioSpec _obtained; SDL_AudioDevice *device; SDL_bool build_cvt; + void *handle = NULL; + Uint32 stream_len; int i = 0; if (!SDL_WasInit(SDL_INIT_AUDIO)) { @@ -1073,6 +981,18 @@ open_audio_device(const char *devname, int iscapture, return 0; } + /* Find an available device ID... */ + for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) { + if (open_devices[id] == NULL) { + break; + } + } + + if (id == SDL_arraysize(open_devices)) { + SDL_SetError("Too many open audio devices"); + return 0; + } + if (!obtained) { obtained = &_obtained; } @@ -1108,9 +1028,7 @@ open_audio_device(const char *devname, int iscapture, return 0; } } - } - - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { + } else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) { SDL_SetError("No such device"); return 0; @@ -1123,6 +1041,30 @@ open_audio_device(const char *devname, int iscapture, return 0; } } + } else if (devname != NULL) { + /* if the app specifies an exact string, we can pass the backend + an actual device handle thingey, which saves them the effort of + figuring out what device this was (such as, reenumerating + everything again to find the matching human-readable name). + It might still need to open a device based on the string for, + say, a network audio server, but this optimizes some cases. */ + SDL_AudioDeviceItem *item; + SDL_LockMutex(current_audio.detectionLock); + for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) { + if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) { + handle = item->handle; + break; + } + } + SDL_UnlockMutex(current_audio.detectionLock); + } + + if (!current_audio.impl.AllowsArbitraryDeviceNames) { + /* has to be in our device list, or the default device. */ + if ((handle == NULL) && (devname != NULL)) { + SDL_SetError("No such device."); + return 0; + } } device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice)); @@ -1131,12 +1073,13 @@ open_audio_device(const char *devname, int iscapture, return 0; } SDL_zerop(device); + device->id = id + 1; device->spec = *obtained; device->enabled = 1; device->paused = 1; device->iscapture = iscapture; - /* Create a semaphore for locking the sound buffers */ + /* Create a mutex for locking the sound buffers */ if (!current_audio.impl.SkipMixerLock) { device->mixer_lock = SDL_CreateMutex(); if (device->mixer_lock == NULL) { @@ -1146,26 +1089,12 @@ open_audio_device(const char *devname, int iscapture, } } - /* force a device detection if we haven't done one yet. */ - if ( ((iscapture) && (current_audio.inputDevices == NULL)) || - ((!iscapture) && (current_audio.outputDevices == NULL)) ) { - SDL_GetNumAudioDevices(iscapture); - } - - if (current_audio.impl.OpenDevice(device, devname, iscapture) < 0) { + if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) { close_audio_device(device); return 0; } device->opened = 1; - /* Allocate a fake audio memory buffer */ - device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size); - if (device->fake_stream == NULL) { - close_audio_device(device); - SDL_OutOfMemory(); - return 0; - } - /* See if we need to do any conversion */ build_cvt = SDL_FALSE; if (obtained->freq != device->spec.freq) { @@ -1224,6 +1153,19 @@ open_audio_device(const char *devname, int iscapture, } } + /* Allocate a fake audio memory buffer */ + stream_len = (device->convert.needed) ? device->convert.len_cvt : 0; + if (device->spec.size > stream_len) { + stream_len = device->spec.size; + } + SDL_assert(stream_len > 0); + device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len); + if (device->fake_stream == NULL) { + close_audio_device(device); + SDL_OutOfMemory(); + return 0; + } + if (device->spec.callback == NULL) { /* use buffer queueing? */ /* pool a few packets to start. Enough for two callbacks. */ const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN; @@ -1243,25 +1185,14 @@ open_audio_device(const char *devname, int iscapture, device->spec.userdata = device; } - /* Find an available device ID and store the structure... */ - for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) { - if (open_devices[id] == NULL) { - open_devices[id] = device; - break; - } - } - - if (id == SDL_arraysize(open_devices)) { - SDL_SetError("Too many open audio devices"); - close_audio_device(device); - return 0; - } + /* add it to our list of open devices. */ + open_devices[id] = device; /* Start the audio thread if necessary */ if (!current_audio.impl.ProvidesOwnCallbackThread) { /* Start the audio thread */ char name[64]; - SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) (id + 1)); + SDL_snprintf(name, sizeof (name), "SDLAudioDev%d", (int) device->id); /* !!! FIXME: this is nasty. */ #if defined(__WIN32__) && !defined(HAVE_LIBC) #undef SDL_CreateThread @@ -1274,13 +1205,13 @@ open_audio_device(const char *devname, int iscapture, device->thread = SDL_CreateThread(SDL_RunAudio, name, device); #endif if (device->thread == NULL) { - SDL_CloseAudioDevice(id + 1); + SDL_CloseAudioDevice(device->id); SDL_SetError("Couldn't create audio thread"); return 0; } } - return id + 1; + return device->id; } @@ -1292,14 +1223,14 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) /* Start up the audio driver, if necessary. This is legacy behaviour! */ if (!SDL_WasInit(SDL_INIT_AUDIO)) { if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { - return (-1); + return -1; } } /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */ if (open_devices[0] != NULL) { SDL_SetError("Audio device is already opened"); - return (-1); + return -1; } if (obtained) { @@ -1310,7 +1241,7 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) } SDL_assert((id == 0) || (id == 1)); - return ((id == 0) ? -1 : 0); + return (id == 0) ? -1 : 0; } SDL_AudioDeviceID @@ -1334,7 +1265,7 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid) status = SDL_AUDIO_PLAYING; } } - return (status); + return status; } @@ -1425,14 +1356,16 @@ SDL_AudioQuit(void) } } + free_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount); + free_device_list(¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); + /* Free the driver data */ current_audio.impl.Deinitialize(); - free_device_list(¤t_audio.outputDevices, - ¤t_audio.outputDeviceCount); - free_device_list(¤t_audio.inputDevices, - ¤t_audio.inputDeviceCount); - SDL_memset(¤t_audio, '\0', sizeof(current_audio)); - SDL_memset(open_devices, '\0', sizeof(open_devices)); + + SDL_DestroyMutex(current_audio.detectionLock); + + SDL_zero(current_audio); + SDL_zero(open_devices); } #define NUM_FORMATS 10 @@ -1470,16 +1403,16 @@ SDL_FirstAudioFormat(SDL_AudioFormat format) } } format_idx_sub = 0; - return (SDL_NextAudioFormat()); + return SDL_NextAudioFormat(); } SDL_AudioFormat SDL_NextAudioFormat(void) { if ((format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS)) { - return (0); + return 0; } - return (format_list[format_idx][format_idx_sub++]); + return format_list[format_idx][format_idx_sub++]; } void diff --git a/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c index e9af62119..4a50c097d 100644 --- a/src/audio/SDL_audiodev.c +++ b/src/audio/SDL_audiodev.c @@ -46,18 +46,21 @@ #define _PATH_DEV_AUDIO "/dev/audio" #endif -static SDL_INLINE void -test_device(const char *fname, int flags, int (*test) (int fd), - SDL_AddAudioDevice addfn) +static void +test_device(const int iscapture, const char *fname, int flags, int (*test) (int fd)) { struct stat sb; if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) { const int audio_fd = open(fname, flags, 0); if (audio_fd >= 0) { - if (test(audio_fd)) { - addfn(fname); - } + const int okay = test(audio_fd); close(audio_fd); + if (okay) { + static size_t dummyhandle = 0; + dummyhandle++; + SDL_assert(dummyhandle != 0); + SDL_AddAudioDevice(iscapture, fname, (void *) dummyhandle); + } } } } @@ -68,11 +71,10 @@ test_stub(int fd) return 1; } -void -SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd), - SDL_AddAudioDevice addfn) +static void +SDL_EnumUnixAudioDevices_Internal(const int iscapture, const int classic, int (*test)(int)) { - const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT; const char *audiodev; char audiopath[1024]; @@ -97,17 +99,25 @@ SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd), } } } - test_device(audiodev, flags, test, addfn); + test_device(iscapture, audiodev, flags, test); if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) { int instance = 0; while (instance++ <= 64) { SDL_snprintf(audiopath, SDL_arraysize(audiopath), "%s%d", audiodev, instance); - test_device(audiopath, flags, test, addfn); + test_device(iscapture, audiopath, flags, test); } } } +void +SDL_EnumUnixAudioDevices(const int classic, int (*test)(int)) +{ + SDL_EnumUnixAudioDevices_Internal(SDL_TRUE, classic, test); + SDL_EnumUnixAudioDevices_Internal(SDL_FALSE, classic, test); +} + #endif /* Audio driver selection */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/SDL_audiodev_c.h b/src/audio/SDL_audiodev_c.h index 1ad0dc101..3544bfab8 100644 --- a/src/audio/SDL_audiodev_c.h +++ b/src/audio/SDL_audiodev_c.h @@ -33,7 +33,6 @@ #define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK) #endif -void SDL_EnumUnixAudioDevices(int iscapture, int classic, - int (*test) (int fd), SDL_AddAudioDevice addfn); +extern void SDL_EnumUnixAudioDevices(const int classic, int (*test)(int)); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 4f933205d..502a0d317 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -30,8 +30,21 @@ typedef struct SDL_AudioDevice SDL_AudioDevice; #define _THIS SDL_AudioDevice *_this -/* Used by audio targets during DetectDevices() */ -typedef void (*SDL_AddAudioDevice)(const char *name); +/* Audio targets should call this as devices are added to the system (such as + a USB headset being plugged in), and should also be called for + for every device found during DetectDevices(). */ +extern void SDL_AddAudioDevice(const int iscapture, const char *name, void *handle); + +/* Audio targets should call this as devices are removed, so SDL can update + its list of available devices. */ +extern void SDL_RemoveAudioDevice(const int iscapture, void *handle); + +/* Audio targets should call this if an opened audio device is lost while + being used. This can happen due to i/o errors, or a device being unplugged, + etc. If the device is totally gone, please also call SDL_RemoveAudioDevice() + as appropriate so SDL's list of devices is accurate. */ +extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device); + /* This is the size of a packet when using SDL_QueueAudio(). We allocate these as necessary and pool them, under the assumption that we'll @@ -55,8 +68,8 @@ typedef struct SDL_AudioBufferQueue typedef struct SDL_AudioDriverImpl { - void (*DetectDevices) (int iscapture, SDL_AddAudioDevice addfn); - int (*OpenDevice) (_THIS, const char *devname, int iscapture); + void (*DetectDevices) (void); + int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture); void (*ThreadInit) (_THIS); /* Called by audio thread at start */ void (*WaitDevice) (_THIS); void (*PlayDevice) (_THIS); @@ -66,19 +79,34 @@ typedef struct SDL_AudioDriverImpl void (*CloseDevice) (_THIS); void (*LockDevice) (_THIS); void (*UnlockDevice) (_THIS); + void (*FreeDeviceHandle) (void *handle); /**< SDL is done with handle from SDL_AddAudioDevice() */ void (*Deinitialize) (void); /* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */ /* Some flags to push duplicate code into the core and reduce #ifdefs. */ + /* !!! FIXME: these should be SDL_bool */ int ProvidesOwnCallbackThread; int SkipMixerLock; /* !!! FIXME: do we need this anymore? */ int HasCaptureSupport; int OnlyHasDefaultOutputDevice; int OnlyHasDefaultInputDevice; + int AllowsArbitraryDeviceNames; } SDL_AudioDriverImpl; +typedef struct SDL_AudioDeviceItem +{ + void *handle; + struct SDL_AudioDeviceItem *next; + #if (defined(__GNUC__) && (__GNUC__ <= 2)) + char name[1]; /* actually variable length. */ + #else + char name[]; + #endif +} SDL_AudioDeviceItem; + + typedef struct SDL_AudioDriver { /* * * */ @@ -91,11 +119,14 @@ typedef struct SDL_AudioDriver SDL_AudioDriverImpl impl; - char **outputDevices; + /* A mutex for device detection */ + SDL_mutex *detectionLock; + SDL_bool captureDevicesRemoved; + SDL_bool outputDevicesRemoved; int outputDeviceCount; - - char **inputDevices; int inputDeviceCount; + SDL_AudioDeviceItem *outputDevices; + SDL_AudioDeviceItem *inputDevices; } SDL_AudioDriver; @@ -113,6 +144,7 @@ struct SDL_AudioDevice { /* * * */ /* Data common to all devices */ + SDL_AudioDeviceID id; /* The current audio specification (shared with audio thread) */ SDL_AudioSpec spec; @@ -125,15 +157,17 @@ struct SDL_AudioDevice SDL_AudioStreamer streamer; /* Current state flags */ + /* !!! FIXME: should be SDL_bool */ int iscapture; - int enabled; + int enabled; /* true if device is functioning and connected. */ + int shutdown; /* true if we are signaling the play thread to end. */ int paused; int opened; /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; - /* A semaphore for locking the mixing buffers */ + /* A mutex for locking the mixing buffers */ SDL_mutex *mixer_lock; /* A thread to feed the audio device */ diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 1f3def3f6..216383cae 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -320,7 +320,7 @@ ALSA_PlayDevice(_THIS) /* Hmm, not much we can do - abort */ fprintf(stderr, "ALSA write failed (unrecoverable): %s\n", ALSA_snd_strerror(status)); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); return; } continue; @@ -465,7 +465,7 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params, int override) } static int -ALSA_OpenDevice(_THIS, const char *devname, int iscapture) +ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int status = 0; snd_pcm_t *pcm_handle = NULL; diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index fe66763b8..00537baa3 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -35,7 +35,7 @@ static SDL_AudioDevice* audioDevice = NULL; static int -AndroidAUD_OpenDevice(_THIS, const char *devname, int iscapture) +AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format; diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 72fba70cc..628d6e6ec 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -151,7 +151,7 @@ ARTS_WaitDevice(_THIS) /* Check every 10 loops */ if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } } @@ -179,7 +179,7 @@ ARTS_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -229,7 +229,7 @@ ARTS_Suspend(void) } static int -ARTS_OpenDevice(_THIS, const char *devname, int iscapture) +ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int rc = 0; int bits = 0, frag_spec = 0; diff --git a/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index f415fe040..d1159e995 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -51,9 +51,9 @@ static void -BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +BSDAUDIO_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); + SDL_EnumUnixAudioDevices(0, NULL); } @@ -150,7 +150,7 @@ BSDAUDIO_WaitDevice(_THIS) the user know what happened. */ fprintf(stderr, "SDL: %s\n", message); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); /* Don't try to close - may hang */ this->hidden->audio_fd = -1; #ifdef DEBUG_AUDIO @@ -195,7 +195,7 @@ BSDAUDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -224,7 +224,7 @@ BSDAUDIO_CloseDevice(_THIS) } static int -BSDAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); SDL_AudioFormat format = 0; @@ -348,6 +348,8 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->CloseDevice = BSDAUDIO_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 7fc9ea94b..22210b050 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -19,6 +19,9 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_COREAUDIO + #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "../SDL_sysaudio.h" @@ -37,31 +40,48 @@ static void COREAUDIO_CloseDevice(_THIS); } #if MACOSX_COREAUDIO -typedef void (*addDevFn)(const char *name, AudioDeviceID devId, void *data); +static const AudioObjectPropertyAddress devlist_address = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; -static void -addToDevList(const char *name, AudioDeviceID devId, void *data) +typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data); + +typedef struct AudioDeviceList { - SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data; - addfn(name); + AudioDeviceID devid; + SDL_bool alive; + struct AudioDeviceList *next; +} AudioDeviceList; + +static AudioDeviceList *output_devs = NULL; +static AudioDeviceList *capture_devs = NULL; + +static SDL_bool +add_to_internal_dev_list(const int iscapture, AudioDeviceID devId) +{ + AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList)); + if (item == NULL) { + return SDL_FALSE; + } + item->devid = devId; + item->alive = SDL_TRUE; + item->next = iscapture ? capture_devs : output_devs; + if (iscapture) { + capture_devs = item; + } else { + output_devs = item; + } + + return SDL_TRUE; } -typedef struct -{ - const char *findname; - AudioDeviceID devId; - int found; -} FindDevIdData; - static void -findDevId(const char *name, AudioDeviceID devId, void *_data) +addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data) { - FindDevIdData *data = (FindDevIdData *) _data; - if (!data->found) { - if (SDL_strcmp(name, data->findname) == 0) { - data->found = 1; - data->devId = devId; - } + if (add_to_internal_dev_list(iscapture, devId)) { + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); } } @@ -74,14 +94,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) UInt32 i = 0; UInt32 max = 0; - AudioObjectPropertyAddress addr = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, - 0, NULL, &size); + result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size); if (result != kAudioHardwareNoError) return; @@ -89,8 +103,8 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) if (devs == NULL) return; - result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - 0, NULL, &size, devs); + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size, devs); if (result != kAudioHardwareNoError) return; @@ -102,10 +116,17 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) AudioBufferList *buflist = NULL; int usable = 0; CFIndex len = 0; + const AudioObjectPropertyAddress addr = { + kAudioDevicePropertyStreamConfiguration, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; - addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : - kAudioDevicePropertyScopeOutput; - addr.mSelector = kAudioDevicePropertyStreamConfiguration; + const AudioObjectPropertyAddress nameaddr = { + kAudioObjectPropertyName, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size); if (result != noErr) @@ -133,9 +154,9 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) if (!usable) continue; - addr.mSelector = kAudioObjectPropertyName; + size = sizeof (CFStringRef); - result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, &cfstr); + result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr); if (result != kAudioHardwareNoError) continue; @@ -166,79 +187,84 @@ build_device_list(int iscapture, addDevFn addfn, void *addfndata) ((iscapture) ? "capture" : "output"), (int) *devCount, ptr, (int) dev); #endif - addfn(ptr, dev, addfndata); + addfn(ptr, iscapture, dev, addfndata); } SDL_free(ptr); /* addfn() would have copied the string. */ } } static void -COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +free_audio_device_list(AudioDeviceList **list) { - build_device_list(iscapture, addToDevList, addfn); + AudioDeviceList *item = *list; + while (item) { + AudioDeviceList *next = item->next; + SDL_free(item); + item = next; + } + *list = NULL; } -static int -find_device_by_name(_THIS, const char *devname, int iscapture) +static void +COREAUDIO_DetectDevices(void) { - AudioDeviceID devid = 0; - OSStatus result = noErr; - UInt32 size = 0; - UInt32 alive = 0; - pid_t pid = 0; + build_device_list(SDL_TRUE, addToDevList, NULL); + build_device_list(SDL_FALSE, addToDevList, NULL); +} - AudioObjectPropertyAddress addr = { - 0, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - if (devname == NULL) { - size = sizeof (AudioDeviceID); - addr.mSelector = - ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice : - kAudioHardwarePropertyDefaultOutputDevice); - result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - 0, NULL, &size, &devid); - CHECK_RESULT("AudioHardwareGetProperty (default device)"); - } else { - FindDevIdData data; - SDL_zero(data); - data.findname = devname; - build_device_list(iscapture, findDevId, &data); - if (!data.found) { - SDL_SetError("CoreAudio: No such audio device."); - return 0; +static void +build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data) +{ + AudioDeviceList **list = (AudioDeviceList **) data; + AudioDeviceList *item; + for (item = *list; item != NULL; item = item->next) { + if (item->devid == devId) { + item->alive = SDL_TRUE; + return; } - devid = data.devId; } - addr.mSelector = kAudioDevicePropertyDeviceIsAlive; - addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : - kAudioDevicePropertyScopeOutput; + add_to_internal_dev_list(iscapture, devId); /* new device, add it. */ + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); +} - size = sizeof (alive); - result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive); - CHECK_RESULT - ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)"); - - if (!alive) { - SDL_SetError("CoreAudio: requested device exists, but isn't alive."); - return 0; +static void +reprocess_device_list(const int iscapture, AudioDeviceList **list) +{ + AudioDeviceList *item; + AudioDeviceList *prev = NULL; + for (item = *list; item != NULL; item = item->next) { + item->alive = SDL_FALSE; } - addr.mSelector = kAudioDevicePropertyHogMode; - size = sizeof (pid); - result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid); + build_device_list(iscapture, build_device_change_list, list); - /* some devices don't support this property, so errors are fine here. */ - if ((result == noErr) && (pid != -1)) { - SDL_SetError("CoreAudio: requested device is being hogged."); - return 0; + /* free items in the list that aren't still alive. */ + item = *list; + while (item != NULL) { + AudioDeviceList *next = item->next; + if (item->alive) { + prev = item; + } else { + SDL_RemoveAudioDevice(iscapture, (void *) ((size_t) item->devid)); + if (prev) { + prev->next = item->next; + } else { + *list = item->next; + } + SDL_free(item); + } + item = next; } +} - this->hidden->deviceID = devid; - return 1; +/* this is called when the system's list of available audio devices changes. */ +static OSStatus +device_list_changed(AudioObjectID systemObj, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data) +{ + reprocess_device_list(SDL_TRUE, &capture_devs); + reprocess_device_list(SDL_FALSE, &output_devs); + return 0; } #endif @@ -314,11 +340,54 @@ inputCallback(void *inRefCon, } +#if MACOSX_COREAUDIO +static const AudioObjectPropertyAddress alive_address = +{ + kAudioDevicePropertyDeviceIsAlive, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; + +static OSStatus +device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) data; + SDL_bool dead = SDL_FALSE; + UInt32 isAlive = 1; + UInt32 size = sizeof (isAlive); + OSStatus error; + + if (!this->enabled) { + return 0; /* already known to be dead. */ + } + + error = AudioObjectGetPropertyData(this->hidden->deviceID, &alive_address, + 0, NULL, &size, &isAlive); + + if (error == kAudioHardwareBadDeviceError) { + dead = SDL_TRUE; /* device was unplugged. */ + } else if ((error == kAudioHardwareNoError) && (!isAlive)) { + dead = SDL_TRUE; /* device died in some other way. */ + } + + if (dead) { + SDL_OpenedAudioDeviceDisconnected(this); + } + + return 0; +} +#endif + static void COREAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { if (this->hidden->audioUnitOpened) { + #if MACOSX_COREAUDIO + /* Unregister our disconnect callback. */ + AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); + #endif + AURenderCallbackStruct callback; const AudioUnitElement output_bus = 0; const AudioUnitElement input_bus = 1; @@ -352,9 +421,63 @@ COREAUDIO_CloseDevice(_THIS) } } +#if MACOSX_COREAUDIO +static int +prepare_device(_THIS, void *handle, int iscapture) +{ + AudioDeviceID devid = (AudioDeviceID) ((size_t) handle); + OSStatus result = noErr; + UInt32 size = 0; + UInt32 alive = 0; + pid_t pid = 0; + + AudioObjectPropertyAddress addr = { + 0, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (handle == NULL) { + size = sizeof (AudioDeviceID); + addr.mSelector = + ((iscapture) ? kAudioHardwarePropertyDefaultInputDevice : + kAudioHardwarePropertyDefaultOutputDevice); + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, + 0, NULL, &size, &devid); + CHECK_RESULT("AudioHardwareGetProperty (default device)"); + } + + addr.mSelector = kAudioDevicePropertyDeviceIsAlive; + addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : + kAudioDevicePropertyScopeOutput; + + size = sizeof (alive); + result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive); + CHECK_RESULT + ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)"); + + if (!alive) { + SDL_SetError("CoreAudio: requested device exists, but isn't alive."); + return 0; + } + + addr.mSelector = kAudioDevicePropertyHogMode; + size = sizeof (pid); + result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid); + + /* some devices don't support this property, so errors are fine here. */ + if ((result == noErr) && (pid != -1)) { + SDL_SetError("CoreAudio: requested device is being hogged."); + return 0; + } + + this->hidden->deviceID = devid; + return 1; +} +#endif static int -prepare_audiounit(_THIS, const char *devname, int iscapture, +prepare_audiounit(_THIS, void *handle, int iscapture, const AudioStreamBasicDescription * strdesc) { OSStatus result = noErr; @@ -373,8 +496,7 @@ prepare_audiounit(_THIS, const char *devname, int iscapture, kAudioUnitScope_Input); #if MACOSX_COREAUDIO - if (!find_device_by_name(this, devname, iscapture)) { - SDL_SetError("Couldn't find requested CoreAudio device"); + if (!prepare_device(this, handle, iscapture)) { return 0; } #endif @@ -451,13 +573,18 @@ prepare_audiounit(_THIS, const char *devname, int iscapture, result = AudioOutputUnitStart(this->hidden->audioUnit); CHECK_RESULT("AudioOutputUnitStart"); +#if MACOSX_COREAUDIO + /* Fire a callback if the device stops being "alive" (disconnected, etc). */ + AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); +#endif + /* We're running! */ return 1; } static int -COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { AudioStreamBasicDescription strdesc; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); @@ -516,7 +643,7 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; - if (!prepare_audiounit(this, devname, iscapture, &strdesc)) { + if (!prepare_audiounit(this, handle, iscapture, &strdesc)) { COREAUDIO_CloseDevice(this); return -1; /* prepare_audiounit() will call SDL_SetError()... */ } @@ -524,15 +651,27 @@ COREAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return 0; /* good to go. */ } +static void +COREAUDIO_Deinitialize(void) +{ +#if MACOSX_COREAUDIO + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); + free_audio_device_list(&capture_devs); + free_audio_device_list(&output_devs); +#endif +} + static int COREAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ impl->OpenDevice = COREAUDIO_OpenDevice; impl->CloseDevice = COREAUDIO_CloseDevice; + impl->Deinitialize = COREAUDIO_Deinitialize; #if MACOSX_COREAUDIO impl->DetectDevices = COREAUDIO_DetectDevices; + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); #else impl->OnlyHasDefaultOutputDevice = 1; @@ -554,4 +693,6 @@ AudioBootStrap COREAUDIO_bootstrap = { "coreaudio", "CoreAudio", COREAUDIO_Init, 0 }; +#endif /* SDL_AUDIO_DRIVER_COREAUDIO */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 067683ccc..99e34521f 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -144,15 +144,22 @@ SetDSerror(const char *function, int code) return SDL_SetError("%s", errbuf); } +static void +DSOUND_FreeDeviceHandle(void *handle) +{ + SDL_free(handle); +} static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) { - SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data; + const int iscapture = (int) ((size_t) data); if (guid != NULL) { /* skip default device */ char *str = WIN_StringToUTF8(desc); if (str != NULL) { - addfn(str); + LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID)); + SDL_memcpy(cpyguid, guid, sizeof (GUID)); + SDL_AddAudioDevice(iscapture, str, cpyguid); SDL_free(str); /* addfn() makes a copy of this string. */ } } @@ -160,13 +167,10 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) } static void -DSOUND_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +DSOUND_DetectDevices(void) { - if (iscapture) { - pDirectSoundCaptureEnumerateW(FindAllDevs, addfn); - } else { - pDirectSoundEnumerateW(FindAllDevs, addfn); - } + pDirectSoundCaptureEnumerateW(FindAllDevs, (void *) ((size_t) 1)); + pDirectSoundEnumerateW(FindAllDevs, (void *) ((size_t) 0)); } @@ -419,53 +423,14 @@ CreateSecondary(_THIS, HWND focus) return (numchunks); } -typedef struct FindDevGUIDData -{ - const char *devname; - GUID guid; - int found; -} FindDevGUIDData; - -static BOOL CALLBACK -FindDevGUID(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID _data) -{ - if (guid != NULL) { /* skip the default device. */ - FindDevGUIDData *data = (FindDevGUIDData *) _data; - char *str = WIN_StringToUTF8(desc); - const int match = (SDL_strcmp(str, data->devname) == 0); - SDL_free(str); - if (match) { - data->found = 1; - SDL_memcpy(&data->guid, guid, sizeof (data->guid)); - return FALSE; /* found it! stop enumerating. */ - } - } - return TRUE; /* keep enumerating. */ -} - static int -DSOUND_OpenDevice(_THIS, const char *devname, int iscapture) +DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { HRESULT result; SDL_bool valid_format = SDL_FALSE; SDL_bool tried_format = SDL_FALSE; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - FindDevGUIDData devguid; - LPGUID guid = NULL; - - if (devname != NULL) { - devguid.found = 0; - devguid.devname = devname; - if (iscapture) - pDirectSoundCaptureEnumerateW(FindDevGUID, &devguid); - else - pDirectSoundEnumerateW(FindDevGUID, &devguid); - - if (!devguid.found) { - return SDL_SetError("DirectSound: Requested device not found"); - } - guid = &devguid.guid; - } + LPGUID guid = (LPGUID) handle; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -536,6 +501,8 @@ DSOUND_Init(SDL_AudioDriverImpl * impl) impl->WaitDone = DSOUND_WaitDone; impl->GetDeviceBuf = DSOUND_GetDeviceBuf; impl->CloseDevice = DSOUND_CloseDevice; + impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; + impl->Deinitialize = DSOUND_Deinitialize; return 1; /* this audio target is available. */ diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index cc4e3efc6..1577b6f23 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -71,7 +71,7 @@ DISKAUD_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written != this->hidden->mixlen) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -100,7 +100,7 @@ DISKAUD_CloseDevice(_THIS) } static int -DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture) +DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const char *envr = SDL_getenv(DISKENVR_WRITEDELAY); const char *fname = DISKAUD_GetOutputFilename(devname); @@ -151,6 +151,8 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; impl->CloseDevice = DISKAUD_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index eea5a5f86..0d34e9512 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -51,9 +51,9 @@ static void -DSP_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +DSP_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn); + SDL_EnumUnixAudioDevices(0, NULL); } @@ -74,7 +74,7 @@ DSP_CloseDevice(_THIS) static int -DSP_OpenDevice(_THIS, const char *devname, int iscapture) +DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); int format; @@ -270,7 +270,7 @@ DSP_PlayDevice(_THIS) const int mixlen = this->hidden->mixlen; if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { perror("Audio write"); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); @@ -293,6 +293,8 @@ DSP_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = DSP_GetDeviceBuf; impl->CloseDevice = DSP_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index 671e222cf..965b4ce56 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -27,7 +27,7 @@ #include "SDL_dummyaudio.h" static int -DUMMYAUD_OpenDevice(_THIS, const char *devname, int iscapture) +DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { return 0; /* always succeeds. */ } diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c new file mode 100644 index 000000000..2147baedb --- /dev/null +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -0,0 +1,275 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_EMSCRIPTEN + +#include "SDL_audio.h" +#include "SDL_log.h" +#include "../SDL_audio_c.h" +#include "SDL_emscriptenaudio.h" + +#include + +static int +copyData(_THIS) +{ + int byte_len; + + if (this->hidden->write_off + this->convert.len_cvt > this->hidden->mixlen) { + if (this->hidden->write_off > this->hidden->read_off) { + SDL_memmove(this->hidden->mixbuf, + this->hidden->mixbuf + this->hidden->read_off, + this->hidden->mixlen - this->hidden->read_off); + this->hidden->write_off = this->hidden->write_off - this->hidden->read_off; + } else { + this->hidden->write_off = 0; + } + this->hidden->read_off = 0; + } + + SDL_memcpy(this->hidden->mixbuf + this->hidden->write_off, + this->convert.buf, + this->convert.len_cvt); + this->hidden->write_off += this->convert.len_cvt; + byte_len = this->hidden->write_off - this->hidden->read_off; + + return byte_len; +} + +static void +HandleAudioProcess(_THIS) +{ + Uint8 *buf = NULL; + int byte_len = 0; + int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8; + int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; + + /* Only do soemthing if audio is enabled */ + if (!this->enabled) + return; + + if (this->paused) + return; + + if (this->convert.needed) { + if (this->hidden->conv_in_len != 0) { + this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels; + } + + (*this->spec.callback) (this->spec.userdata, + this->convert.buf, + this->convert.len); + SDL_ConvertAudio(&this->convert); + buf = this->convert.buf; + byte_len = this->convert.len_cvt; + + /* size mismatch*/ + if (byte_len != this->spec.size) { + if (!this->hidden->mixbuf) { + this->hidden->mixlen = this->spec.size > byte_len ? this->spec.size * 2 : byte_len * 2; + this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen); + } + + /* copy existing data */ + byte_len = copyData(this); + + /* read more data*/ + while (byte_len < this->spec.size) { + (*this->spec.callback) (this->spec.userdata, + this->convert.buf, + this->convert.len); + SDL_ConvertAudio(&this->convert); + byte_len = copyData(this); + } + + byte_len = this->spec.size; + buf = this->hidden->mixbuf + this->hidden->read_off; + this->hidden->read_off += byte_len; + } + + } else { + if (!this->hidden->mixbuf) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = SDL_malloc(this->hidden->mixlen); + } + (*this->spec.callback) (this->spec.userdata, + this->hidden->mixbuf, + this->hidden->mixlen); + buf = this->hidden->mixbuf; + byte_len = this->hidden->mixlen; + } + + if (buf) { + EM_ASM_ARGS({ + var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels']; + for (var c = 0; c < numChannels; ++c) { + var channelData = SDL2.audio.currentOutputBuffer['getChannelData'](c); + if (channelData.length != $1) { + throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; + } + + for (var j = 0; j < $1; ++j) { + channelData[j] = getValue($0 + (j*numChannels + c)*4, 'float'); + } + } + }, buf, byte_len / bytes / this->spec.channels); + } +} + +static void +Emscripten_CloseDevice(_THIS) +{ + if (this->hidden != NULL) { + if (this->hidden->mixbuf != NULL) { + /* Clean up the audio buffer */ + SDL_free(this->hidden->mixbuf); + this->hidden->mixbuf = NULL; + } + + SDL_free(this->hidden); + this->hidden = NULL; + } +} + +static int +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) { + case AUDIO_F32: /* web audio only supports floats */ + this->spec.format = test_format; + + valid_format = SDL_TRUE; + break; + } + test_format = SDL_NextAudioFormat(); + } + + if (!valid_format) { + /* Didn't find a compatible format :( */ + return SDL_SetError("No compatible audio format!"); + } + + /* Initialize all variables that we clean on shutdown */ + this->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc((sizeof *this->hidden)); + if (this->hidden == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + + /* based on parts of library_sdl.js */ + + /* create context (TODO: this puts stuff in the global namespace...)*/ + result = EM_ASM_INT_V({ + if(typeof(SDL2) === 'undefined') + SDL2 = {}; + + if(typeof(SDL2.audio) === 'undefined') + SDL2.audio = {}; + + if (!SDL2.audioContext) { + if (typeof(AudioContext) !== 'undefined') { + SDL2.audioContext = new AudioContext(); + } else if (typeof(webkitAudioContext) !== 'undefined') { + SDL2.audioContext = new webkitAudioContext(); + } else { + 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({ + return SDL2.audioContext['sampleRate']; + }); + + if(this->spec.freq != sampleRate) { + for (i = this->spec.samples; i > 0; i--) { + f = (float)i / (float)sampleRate * (float)this->spec.freq; + if (SDL_floor(f) == f) { + this->hidden->conv_in_len = SDL_floor(f); + break; + } + } + + this->spec.freq = sampleRate; + } + + SDL_CalculateAudioSpec(&this->spec); + + /* setup a ScriptProcessorNode */ + EM_ASM_ARGS({ + SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); + SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { + SDL2.audio.currentOutputBuffer = e['outputBuffer']; + Runtime.dynCall('vi', $2, [$3]); + }; + SDL2.audio.scriptProcessorNode['connect'](SDL2.audioContext['destination']); + }, this->spec.channels, this->spec.samples, HandleAudioProcess, this); + return 0; +} + +static int +Emscripten_Init(SDL_AudioDriverImpl * impl) +{ + /* Set the function pointers */ + impl->OpenDevice = Emscripten_OpenDevice; + impl->CloseDevice = Emscripten_CloseDevice; + + /* only one output */ + impl->OnlyHasDefaultOutputDevice = 1; + + /* no threads here */ + impl->SkipMixerLock = 1; + impl->ProvidesOwnCallbackThread = 1; + + /* check availability */ + int available = EM_ASM_INT_V({ + if (typeof(AudioContext) !== 'undefined') { + return 1; + } else if (typeof(webkitAudioContext) !== 'undefined') { + return 1; + } + return 0; + }); + + return available; +} + +AudioBootStrap EmscriptenAudio_bootstrap = { + "emscripten", "SDL emscripten audio driver", Emscripten_Init, 0 +}; + +#endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/emscripten/SDL_emscriptenaudio.h b/src/audio/emscripten/SDL_emscriptenaudio.h new file mode 100644 index 000000000..2cec72b1c --- /dev/null +++ b/src/audio/emscripten/SDL_emscriptenaudio.h @@ -0,0 +1,42 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef _SDL_emscriptenaudio_h +#define _SDL_emscriptenaudio_h + +#include "../SDL_sysaudio.h" + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +struct SDL_PrivateAudioData +{ + Uint8 *mixbuf; + Uint32 mixlen; + + Uint32 conv_in_len; + + Uint32 write_off, read_off; +}; + +#endif /* _SDL_emscriptenaudio_h */ +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index e675272dc..7f18337d9 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -129,7 +129,7 @@ ESD_WaitDevice(_THIS) /* Check every 10 loops */ if (this->hidden->parent && (((++cnt) % 10) == 0)) { if (kill(this->hidden->parent, 0) < 0 && errno == ESRCH) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } } @@ -161,7 +161,7 @@ ESD_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -215,7 +215,7 @@ get_progname(void) static int -ESD_OpenDevice(_THIS, const char *devname, int iscapture) +ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { esd_format_t format = (ESD_STREAM | ESD_PLAY); SDL_AudioFormat test_format = 0; diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index b8367715f..dae4f4afa 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -143,7 +143,7 @@ SDL_FS_PlayDevice(_THIS) this->hidden->mixsamples); /* If we couldn't write, assume fatal error for now */ if (ret) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen); @@ -186,7 +186,7 @@ SDL_FS_CloseDevice(_THIS) static int -SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture) +SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int bytes; SDL_AudioFormat test_format = 0, format = 0; diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index dddb77922..648987a14 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -111,7 +111,7 @@ UnmaskSignals(sigset_t * omask) static int -HAIKUAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int valid_datatype = 0; media_raw_audio_format format; diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index d9179f272..643666d6a 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -20,6 +20,9 @@ */ #include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_NACL + #include "SDL_naclaudio.h" #include "SDL_audio.h" @@ -40,7 +43,7 @@ #define SAMPLE_FRAME_COUNT 4096 /* Audio driver functions */ -static int NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture); +static int NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture); static void NACLAUD_CloseDevice(_THIS); static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data); @@ -82,7 +85,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) { } static int -NACLAUD_OpenDevice(_THIS, const char *devname, int iscapture) { +NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { PP_Instance instance = PSGetInstanceId(); const PPB_Audio *ppb_audio = PSInterfaceAudio(); const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig(); @@ -127,9 +130,7 @@ NACLAUD_Init(SDL_AudioDriverImpl * impl) /* Set the function pointers */ impl->OpenDevice = NACLAUD_OpenDevice; impl->CloseDevice = NACLAUD_CloseDevice; - impl->HasCaptureSupport = 0; impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; impl->ProvidesOwnCallbackThread = 1; /* * impl->WaitDevice = NACLAUD_WaitDevice; @@ -145,3 +146,7 @@ AudioBootStrap NACLAUD_bootstrap = { NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver", NACLAUD_Init, 0 }; + +#endif /* SDL_AUDIO_DRIVER_NACL */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index a41a480f2..fe5bd8eda 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -276,7 +276,7 @@ find_device(_THIS, int nch) } static int -NAS_OpenDevice(_THIS, const char *devname, int iscapture) +NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { AuElement elms[3]; int buffer_size; diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 032d8d2cd..5f7d26c92 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -176,7 +176,7 @@ PAUDIO_WaitDevice(_THIS) * the user know what happened. */ fprintf(stderr, "SDL: %s - %s\n", strerror(errno), message); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); /* Don't try to close - may hang */ this->hidden->audio_fd = -1; #ifdef DEBUG_AUDIO @@ -212,7 +212,7 @@ PAUDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (written < 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -241,7 +241,7 @@ PAUDIO_CloseDevice(_THIS) } static int -PAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); char audiodev[1024]; diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 5b1705926..59cbeb41c 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_AUDIO_DRIVER_PSP #include #include @@ -40,7 +43,7 @@ #define PSPAUD_DRIVER_NAME "psp" static int -PSPAUD_OpenDevice(_THIS, const char *devname, int iscapture) +PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int format, mixlen, i; this->hidden = (struct SDL_PrivateAudioData *) @@ -191,5 +194,6 @@ AudioBootStrap PSPAUD_bootstrap = { /* SDL_AUDI */ +#endif /* SDL_AUDIO_DRIVER_PSP */ - +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/psp/SDL_pspaudio.h b/src/audio/psp/SDL_pspaudio.h index 8e420f313..3b7ffb0a0 100644 --- a/src/audio/psp/SDL_pspaudio.h +++ b/src/audio/psp/SDL_pspaudio.h @@ -24,7 +24,7 @@ #include "../SDL_sysaudio.h" -/* Hidden "this" pointer for the video functions */ +/* Hidden "this" pointer for the audio functions */ #define _THIS SDL_AudioDevice *this #define NUM_BUFFERS 2 diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index c3e1238b4..adcbdee2d 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -26,6 +26,7 @@ Stéphan Kochen: stephan .a.t. kochen.nl */ #include "../../SDL_internal.h" +#include "SDL_assert.h" #if SDL_AUDIO_DRIVER_PULSEAUDIO @@ -38,7 +39,6 @@ #include #include #include -#include #include "SDL_timer.h" #include "SDL_audio.h" @@ -66,16 +66,14 @@ static SDL_INLINE int PA_STREAM_IS_GOOD(pa_stream_state_t x) { static const char *(*PULSEAUDIO_pa_get_library_version) (void); -static pa_simple *(*PULSEAUDIO_pa_simple_new) (const char *, const char *, - pa_stream_direction_t, const char *, const char *, const pa_sample_spec *, - const pa_channel_map *, const pa_buffer_attr *, int *); -static void (*PULSEAUDIO_pa_simple_free) (pa_simple *); static pa_channel_map *(*PULSEAUDIO_pa_channel_map_init_auto) ( pa_channel_map *, unsigned, pa_channel_map_def_t); static const char * (*PULSEAUDIO_pa_strerror) (int); static pa_mainloop * (*PULSEAUDIO_pa_mainloop_new) (void); static pa_mainloop_api * (*PULSEAUDIO_pa_mainloop_get_api) (pa_mainloop *); static int (*PULSEAUDIO_pa_mainloop_iterate) (pa_mainloop *, int, int *); +static int (*PULSEAUDIO_pa_mainloop_run) (pa_mainloop *, int *); +static void (*PULSEAUDIO_pa_mainloop_quit) (pa_mainloop *, int); static void (*PULSEAUDIO_pa_mainloop_free) (pa_mainloop *); static pa_operation_state_t (*PULSEAUDIO_pa_operation_get_state) ( @@ -87,7 +85,13 @@ static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *, const char *); static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *, pa_context_flags_t, const pa_spawn_api *); +static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list) (pa_context *, pa_sink_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list) (pa_context *, pa_source_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_by_index) (pa_context *, uint32_t, pa_sink_info_cb_t, void *); +static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_by_index) (pa_context *, uint32_t, pa_source_info_cb_t, void *); static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *); +static pa_operation * (*PULSEAUDIO_pa_context_subscribe) (pa_context *, pa_subscription_mask_t, pa_context_success_cb_t, void *); +static void (*PULSEAUDIO_pa_context_set_subscribe_callback) (pa_context *, pa_context_subscribe_cb_t, void *); static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *); static void (*PULSEAUDIO_pa_context_unref) (pa_context *); @@ -179,18 +183,24 @@ static int load_pulseaudio_syms(void) { SDL_PULSEAUDIO_SYM(pa_get_library_version); - SDL_PULSEAUDIO_SYM(pa_simple_new); - SDL_PULSEAUDIO_SYM(pa_simple_free); SDL_PULSEAUDIO_SYM(pa_mainloop_new); SDL_PULSEAUDIO_SYM(pa_mainloop_get_api); SDL_PULSEAUDIO_SYM(pa_mainloop_iterate); + SDL_PULSEAUDIO_SYM(pa_mainloop_run); + SDL_PULSEAUDIO_SYM(pa_mainloop_quit); SDL_PULSEAUDIO_SYM(pa_mainloop_free); SDL_PULSEAUDIO_SYM(pa_operation_get_state); SDL_PULSEAUDIO_SYM(pa_operation_cancel); SDL_PULSEAUDIO_SYM(pa_operation_unref); SDL_PULSEAUDIO_SYM(pa_context_new); SDL_PULSEAUDIO_SYM(pa_context_connect); + SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list); + SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list); + SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_by_index); + SDL_PULSEAUDIO_SYM(pa_context_get_source_info_by_index); SDL_PULSEAUDIO_SYM(pa_context_get_state); + SDL_PULSEAUDIO_SYM(pa_context_subscribe); + SDL_PULSEAUDIO_SYM(pa_context_set_subscribe_callback); SDL_PULSEAUDIO_SYM(pa_context_disconnect); SDL_PULSEAUDIO_SYM(pa_context_unref); SDL_PULSEAUDIO_SYM(pa_stream_new); @@ -206,122 +216,6 @@ load_pulseaudio_syms(void) return 0; } - -/* Check to see if we can connect to PulseAudio */ -static SDL_bool -CheckPulseAudioAvailable() -{ - pa_simple *s; - pa_sample_spec ss; - - ss.format = PA_SAMPLE_S16NE; - ss.channels = 1; - ss.rate = 22050; - - s = PULSEAUDIO_pa_simple_new(NULL, "SDL", PA_STREAM_PLAYBACK, NULL, - "Test", &ss, NULL, NULL, NULL); - if (s) { - PULSEAUDIO_pa_simple_free(s); - return SDL_TRUE; - } else { - return SDL_FALSE; - } -} - -/* This function waits until it is possible to write a full sound buffer */ -static void -PULSEAUDIO_WaitDevice(_THIS) -{ - struct SDL_PrivateAudioData *h = this->hidden; - - while(1) { - if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || - PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || - PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - this->enabled = 0; - return; - } - if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { - return; - } - } -} - -static void -PULSEAUDIO_PlayDevice(_THIS) -{ - /* Write the audio data */ - struct SDL_PrivateAudioData *h = this->hidden; - if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, - PA_SEEK_RELATIVE) < 0) { - this->enabled = 0; - } -} - -static void -stream_drain_complete(pa_stream *s, int success, void *userdata) -{ - /* no-op for pa_stream_drain() to use for callback. */ -} - -static void -PULSEAUDIO_WaitDone(_THIS) -{ - struct SDL_PrivateAudioData *h = this->hidden; - pa_operation *o; - - o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); - if (!o) { - return; - } - - while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || - PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || - PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_pa_operation_cancel(o); - break; - } - } - - PULSEAUDIO_pa_operation_unref(o); -} - - - -static Uint8 * -PULSEAUDIO_GetDeviceBuf(_THIS) -{ - return (this->hidden->mixbuf); -} - - -static void -PULSEAUDIO_CloseDevice(_THIS) -{ - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); - PULSEAUDIO_pa_stream_unref(this->hidden->stream); - this->hidden->stream = NULL; - } - if (this->hidden->context != NULL) { - PULSEAUDIO_pa_context_disconnect(this->hidden->context); - PULSEAUDIO_pa_context_unref(this->hidden->context); - this->hidden->context = NULL; - } - if (this->hidden->mainloop != NULL) { - PULSEAUDIO_pa_mainloop_free(this->hidden->mainloop); - this->hidden->mainloop = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; - } -} - - static SDL_INLINE int squashVersion(const int major, const int minor, const int patch) { @@ -344,8 +238,193 @@ getAppName(void) return "SDL Application"; /* oh well. */ } +static void +WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o) +{ + /* This checks for NO errors currently. Either fix that, check results elsewhere, or do things you don't care about. */ + if (mainloop && o) { + SDL_bool okay = SDL_TRUE; + while (okay && (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_RUNNING)) { + okay = (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) >= 0); + } + PULSEAUDIO_pa_operation_unref(o); + } +} + +static void +DisconnectFromPulseServer(pa_mainloop *mainloop, pa_context *context) +{ + if (context) { + PULSEAUDIO_pa_context_disconnect(context); + PULSEAUDIO_pa_context_unref(context); + } + if (mainloop != NULL) { + PULSEAUDIO_pa_mainloop_free(mainloop); + } +} + static int -PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +ConnectToPulseServer_Internal(pa_mainloop **_mainloop, pa_context **_context) +{ + pa_mainloop *mainloop = NULL; + pa_context *context = NULL; + pa_mainloop_api *mainloop_api = NULL; + int state = 0; + + *_mainloop = NULL; + *_context = NULL; + + /* Set up a new main loop */ + if (!(mainloop = PULSEAUDIO_pa_mainloop_new())) { + return SDL_SetError("pa_mainloop_new() failed"); + } + + *_mainloop = mainloop; + + mainloop_api = PULSEAUDIO_pa_mainloop_get_api(mainloop); + SDL_assert(mainloop_api); /* this never fails, right? */ + + context = PULSEAUDIO_pa_context_new(mainloop_api, getAppName()); + if (!context) { + return SDL_SetError("pa_context_new() failed"); + } + *_context = context; + + /* Connect to the PulseAudio server */ + if (PULSEAUDIO_pa_context_connect(context, NULL, 0, NULL) < 0) { + return SDL_SetError("Could not setup connection to PulseAudio"); + } + + do { + if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) { + return SDL_SetError("pa_mainloop_iterate() failed"); + } + state = PULSEAUDIO_pa_context_get_state(context); + if (!PA_CONTEXT_IS_GOOD(state)) { + return SDL_SetError("Could not connect to PulseAudio"); + } + } while (state != PA_CONTEXT_READY); + + return 0; /* connected and ready! */ +} + +static int +ConnectToPulseServer(pa_mainloop **_mainloop, pa_context **_context) +{ + const int retval = ConnectToPulseServer_Internal(_mainloop, _context); + if (retval < 0) { + DisconnectFromPulseServer(*_mainloop, *_context); + } + return retval; +} + + +/* This function waits until it is possible to write a full sound buffer */ +static void +PULSEAUDIO_WaitDevice(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + + while (this->enabled) { + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + return; + } + if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { + return; + } + } +} + +static void +PULSEAUDIO_PlayDevice(_THIS) +{ + /* Write the audio data */ + struct SDL_PrivateAudioData *h = this->hidden; + if (this->enabled) { + if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + } + } +} + +static void +stream_drain_complete(pa_stream *s, int success, void *userdata) +{ + /* no-op for pa_stream_drain() to use for callback. */ +} + +static void +PULSEAUDIO_WaitDone(_THIS) +{ + if (this->enabled) { + struct SDL_PrivateAudioData *h = this->hidden; + pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); + if (o) { + while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + PULSEAUDIO_pa_operation_cancel(o); + break; + } + } + PULSEAUDIO_pa_operation_unref(o); + } + } +} + + + +static Uint8 * +PULSEAUDIO_GetDeviceBuf(_THIS) +{ + return (this->hidden->mixbuf); +} + + +static void +PULSEAUDIO_CloseDevice(_THIS) +{ + if (this->hidden != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + SDL_free(this->hidden->device_name); + if (this->hidden->stream) { + PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); + PULSEAUDIO_pa_stream_unref(this->hidden->stream); + } + DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); + SDL_free(this->hidden); + this->hidden = NULL; + } +} + +static void +DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + char **devname = (char **) data; + *devname = SDL_strdup(i->name); + } +} + +static SDL_bool +FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) +{ + const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; + + if (handle == NULL) { /* NULL == default device. */ + return SDL_TRUE; + } + + WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name)); + return (h->device_name != NULL); +} + +static int +PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { struct SDL_PrivateAudioData *h = NULL; Uint16 test_format = 0; @@ -442,42 +521,21 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) paattr.minreq = h->mixlen; #endif + if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) { + PULSEAUDIO_CloseDevice(this); + return SDL_SetError("Could not connect to PulseAudio server"); + } + + if (!FindDeviceName(h, handle)) { + PULSEAUDIO_CloseDevice(this); + return SDL_SetError("Requested PulseAudio sink missing?"); + } + /* The SDL ALSA output hints us that we use Windows' channel mapping */ /* http://bugzilla.libsdl.org/show_bug.cgi?id=110 */ PULSEAUDIO_pa_channel_map_init_auto(&pacmap, this->spec.channels, PA_CHANNEL_MAP_WAVEEX); - /* Set up a new main loop */ - if (!(h->mainloop = PULSEAUDIO_pa_mainloop_new())) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_new() failed"); - } - - h->mainloop_api = PULSEAUDIO_pa_mainloop_get_api(h->mainloop); - h->context = PULSEAUDIO_pa_context_new(h->mainloop_api, getAppName()); - if (!h->context) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_context_new() failed"); - } - - /* Connect to the PulseAudio server */ - if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not setup connection to PulseAudio"); - } - - do { - if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_iterate() failed"); - } - state = PULSEAUDIO_pa_context_get_state(h->context); - if (!PA_CONTEXT_IS_GOOD(state)) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not connect to PulseAudio"); - } - } while (state != PA_CONTEXT_READY); - h->stream = PULSEAUDIO_pa_stream_new( h->context, "Simple DirectMedia Layer", /* stream description */ @@ -490,7 +548,13 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return SDL_SetError("Could not set up PulseAudio stream"); } - if (PULSEAUDIO_pa_stream_connect_playback(h->stream, NULL, &paattr, flags, + /* now that we have multi-device support, don't move a stream from + a device that was unplugged to something else, unless we're default. */ + if (h->device_name != NULL) { + flags |= PA_STREAM_DONT_MOVE; + } + + if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL) < 0) { PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); @@ -504,7 +568,7 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) state = PULSEAUDIO_pa_stream_get_state(h->stream); if (!PA_STREAM_IS_GOOD(state)) { PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not create to PulseAudio stream"); + return SDL_SetError("Could not connect PulseAudio stream"); } } while (state != PA_STREAM_READY); @@ -512,10 +576,92 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) return 0; } +static pa_mainloop *hotplug_mainloop = NULL; +static pa_context *hotplug_context = NULL; +static SDL_Thread *hotplug_thread = NULL; + +/* device handles are device index + 1, cast to void*, so we never pass a NULL. */ + +/* This is called when PulseAudio adds an output ("sink") device. */ +static void +SinkInfoCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + SDL_AddAudioDevice(SDL_FALSE, i->description, (void *) ((size_t) i->index+1)); + } +} + +/* This is called when PulseAudio adds a capture ("source") device. */ +static void +SourceInfoCallback(pa_context *c, const pa_source_info *i, int is_last, void *data) +{ + if (i) { + /* Skip "monitor" sources. These are just output from other sinks. */ + if (i->monitor_of_sink == PA_INVALID_INDEX) { + SDL_AddAudioDevice(SDL_TRUE, i->description, (void *) ((size_t) i->index+1)); + } + } +} + +/* This is called when PulseAudio has a device connected/removed/changed. */ +static void +HotplugCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *data) +{ + const SDL_bool added = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW); + const SDL_bool removed = ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE); + + if (added || removed) { /* we only care about add/remove events. */ + const SDL_bool sink = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK); + const SDL_bool source = ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE); + + /* adds need sink details from the PulseAudio server. Another callback... */ + if (added && sink) { + PULSEAUDIO_pa_context_get_sink_info_by_index(hotplug_context, idx, SinkInfoCallback, NULL); + } else if (added && source) { + PULSEAUDIO_pa_context_get_source_info_by_index(hotplug_context, idx, SourceInfoCallback, NULL); + } else if (removed && (sink || source)) { + /* removes we can handle just with the device index. */ + SDL_RemoveAudioDevice(source != 0, (void *) ((size_t) idx+1)); + } + } +} + +/* this runs as a thread while the Pulse target is initialized to catch hotplug events. */ +static int SDLCALL +HotplugThread(void *data) +{ + pa_operation *o; + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_LOW); + PULSEAUDIO_pa_context_set_subscribe_callback(hotplug_context, HotplugCallback, NULL); + o = PULSEAUDIO_pa_context_subscribe(hotplug_context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL); + PULSEAUDIO_pa_operation_unref(o); /* don't wait for it, just do our thing. */ + PULSEAUDIO_pa_mainloop_run(hotplug_mainloop, NULL); + return 0; +} + +static void +PULSEAUDIO_DetectDevices() +{ + WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_sink_info_list(hotplug_context, SinkInfoCallback, NULL)); + WaitForPulseOperation(hotplug_mainloop, PULSEAUDIO_pa_context_get_source_info_list(hotplug_context, SourceInfoCallback, NULL)); + + /* ok, we have a sane list, let's set up hotplug notifications now... */ + hotplug_thread = SDL_CreateThread(HotplugThread, "PulseHotplug", NULL); +} static void PULSEAUDIO_Deinitialize(void) { + if (hotplug_thread) { + PULSEAUDIO_pa_mainloop_quit(hotplug_mainloop, 0); + SDL_WaitThread(hotplug_thread, NULL); + hotplug_thread = NULL; + } + + DisconnectFromPulseServer(hotplug_mainloop, hotplug_context); + hotplug_mainloop = NULL; + hotplug_context = NULL; + UnloadPulseAudioLibrary(); } @@ -526,12 +672,13 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) return 0; } - if (!CheckPulseAudioAvailable()) { + if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) { UnloadPulseAudioLibrary(); return 0; } /* Set the function pointers */ + impl->DetectDevices = PULSEAUDIO_DetectDevices; impl->OpenDevice = PULSEAUDIO_OpenDevice; impl->PlayDevice = PULSEAUDIO_PlayDevice; impl->WaitDevice = PULSEAUDIO_WaitDevice; @@ -539,12 +686,10 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = PULSEAUDIO_CloseDevice; impl->WaitDone = PULSEAUDIO_WaitDone; impl->Deinitialize = PULSEAUDIO_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; return 1; /* this audio target is available. */ } - AudioBootStrap PULSEAUDIO_bootstrap = { "pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0 }; diff --git a/src/audio/pulseaudio/SDL_pulseaudio.h b/src/audio/pulseaudio/SDL_pulseaudio.h index a75409bc0..10568ffb9 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.h +++ b/src/audio/pulseaudio/SDL_pulseaudio.h @@ -32,9 +32,10 @@ struct SDL_PrivateAudioData { + char *device_name; + /* pulseaudio structures */ pa_mainloop *mainloop; - pa_mainloop_api *mainloop_api; pa_context *context; pa_stream *stream; diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index d6b8a6800..dcb7d38da 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -19,6 +19,15 @@ 3. This notice may not be removed or altered from any source distribution. */ +/* + * !!! FIXME: streamline this a little by removing all the + * !!! FIXME: if (capture) {} else {} sections that are identical + * !!! FIXME: except for one flag. + */ + +/* !!! FIXME: can this target support hotplugging? */ +/* !!! FIXME: ...does SDL2 even support QNX? */ + #include "../../SDL_internal.h" #if SDL_AUDIO_DRIVER_QSA @@ -300,7 +309,7 @@ QSA_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if (towrite != 0) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -337,8 +346,9 @@ QSA_CloseDevice(_THIS) } static int -QSA_OpenDevice(_THIS, const char *devname, int iscapture) +QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { + const QSA_Device *device = (const QSA_Device *) handle; int status = 0; int format = 0; SDL_AudioFormat test_format = 0; @@ -363,80 +373,19 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture) /* Initialize channel direction: capture or playback */ this->hidden->iscapture = iscapture; - /* Find deviceid and cardid by device name for playback */ - if ((!this->hidden->iscapture) && (devname != NULL)) { - uint32_t device; - int32_t status; - - /* Search in the playback devices */ - device = 0; - do { - status = SDL_strcmp(qsa_playback_device[device].name, devname); - if (status == 0) { - /* Found requested device */ - this->hidden->deviceno = qsa_playback_device[device].deviceno; - this->hidden->cardno = qsa_playback_device[device].cardno; - break; - } - device++; - if (device >= qsa_playback_devices) { - QSA_CloseDevice(this); - return SDL_SetError("No such playback device"); - } - } while (1); - } - - /* Find deviceid and cardid by device name for capture */ - if ((this->hidden->iscapture) && (devname != NULL)) { - /* Search in the capture devices */ - uint32_t device; - int32_t status; - - /* Searching in the playback devices */ - device = 0; - do { - status = SDL_strcmp(qsa_capture_device[device].name, devname); - if (status == 0) { - /* Found requested device */ - this->hidden->deviceno = qsa_capture_device[device].deviceno; - this->hidden->cardno = qsa_capture_device[device].cardno; - break; - } - device++; - if (device >= qsa_capture_devices) { - QSA_CloseDevice(this); - return SDL_SetError("No such capture device"); - } - } while (1); - } - - /* Check if SDL requested default audio device */ - if (devname == NULL) { - /* Open system default audio device */ - if (!this->hidden->iscapture) { - status = snd_pcm_open_preferred(&this->hidden->audio_handle, - &this->hidden->cardno, - &this->hidden->deviceno, - SND_PCM_OPEN_PLAYBACK); - } else { - status = snd_pcm_open_preferred(&this->hidden->audio_handle, - &this->hidden->cardno, - &this->hidden->deviceno, - SND_PCM_OPEN_CAPTURE); - } - } else { + if (device != NULL) { /* Open requested audio device */ - if (!this->hidden->iscapture) { - status = - snd_pcm_open(&this->hidden->audio_handle, - this->hidden->cardno, this->hidden->deviceno, - SND_PCM_OPEN_PLAYBACK); - } else { - status = - snd_pcm_open(&this->hidden->audio_handle, - this->hidden->cardno, this->hidden->deviceno, - SND_PCM_OPEN_CAPTURE); - } + this->hidden->deviceno = device->deviceno; + this->hidden->cardno = device->cardno; + status = snd_pcm_open(&this->hidden->audio_handle, + device->cardno, device->deviceno, + iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE); + } else { + /* Open system default audio device */ + status = snd_pcm_open_preferred(&this->hidden->audio_handle, + &this->hidden->cardno, + &this->hidden->deviceno, + iscapture ? SND_PCM_OPEN_PLAYBACK : SND_PCM_OPEN_CAPTURE); } /* Check if requested device is opened */ @@ -638,7 +587,7 @@ QSA_OpenDevice(_THIS, const char *devname, int iscapture) } static void -QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +QSA_DetectDevices(void) { uint32_t it; uint32_t cards; @@ -656,8 +605,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) return; } + /* !!! FIXME: code duplication */ /* Find requested devices by type */ - if (!iscapture) { + { /* output devices */ /* Playback devices enumeration requested */ for (it = 0; it < cards; it++) { devices = 0; @@ -688,7 +638,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) devices; status = snd_pcm_close(handle); if (status == EOK) { - addfn(qsa_playback_device[qsa_playback_devices].name); + SDL_AddAudioDevice(SDL_FALSE, qsa_playback_device[qsa_playback_devices].name, &qsa_playback_device[qsa_playback_devices]); qsa_playback_devices++; } } else { @@ -713,7 +663,9 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) break; } } - } else { + } + + { /* capture devices */ /* Capture devices enumeration requested */ for (it = 0; it < cards; it++) { devices = 0; @@ -744,7 +696,7 @@ QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) devices; status = snd_pcm_close(handle); if (status == EOK) { - addfn(qsa_capture_device[qsa_capture_devices].name); + SDL_AddAudioDevice(SDL_TRUE, qsa_capture_device[qsa_capture_devices].name, &qsa_capture_device[qsa_capture_devices]); qsa_capture_devices++; } } else { diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 5c0636500..f8757d127 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -158,7 +158,7 @@ SNDIO_PlayDevice(_THIS) /* If we couldn't write, assume fatal error for now */ if ( written == 0 ) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO fprintf(stderr, "Wrote %d bytes of audio data\n", written); @@ -193,7 +193,7 @@ SNDIO_CloseDevice(_THIS) } static int -SNDIO_OpenDevice(_THIS, const char *devname, int iscapture) +SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); struct sio_par par; diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index 7efe30ece..ff35b6b1c 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -56,9 +56,9 @@ static Uint8 snd2au(int sample); /* Audio driver bootstrap functions */ static void -SUNAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +SUNAUDIO_DetectDevices(void) { - SDL_EnumUnixAudioDevices(iscapture, 1, (int (*)(int fd)) NULL, addfn); + SDL_EnumUnixAudioDevices(1, (int (*)(int)) NULL); } #ifdef DEBUG_AUDIO @@ -158,7 +158,7 @@ SUNAUDIO_PlayDevice(_THIS) if (write(this->hidden->audio_fd, this->hidden->ulaw_buf, this->hidden->fragsize) < 0) { /* Assume fatal error, for now */ - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } this->hidden->written += this->hidden->fragsize; } else { @@ -168,7 +168,7 @@ SUNAUDIO_PlayDevice(_THIS) if (write(this->hidden->audio_fd, this->hidden->mixbuf, this->spec.size) < 0) { /* Assume fatal error, for now */ - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } this->hidden->written += this->hidden->fragsize; } @@ -198,7 +198,7 @@ SUNAUDIO_CloseDevice(_THIS) } static int -SUNAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) +SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); SDL_AudioFormat format = 0; @@ -414,6 +414,8 @@ SUNAUDIO_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf; impl->CloseDevice = SUNAUDIO_CloseDevice; + impl->AllowsArbitraryDeviceNames = 1; + return 1; /* this audio target is available. */ } diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 88a8154ec..a61ac237d 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -36,8 +36,9 @@ #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif -#define DETECT_DEV_IMPL(typ, capstyp) \ -static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \ +#define DETECT_DEV_IMPL(iscap, typ, capstyp) \ +static void DetectWave##typ##Devs(void) { \ + const UINT iscapture = iscap ? 1 : 0; \ const UINT devcount = wave##typ##GetNumDevs(); \ capstyp caps; \ UINT i; \ @@ -45,24 +46,21 @@ static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \ if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ char *name = WIN_StringToUTF8(caps.szPname); \ if (name != NULL) { \ - addfn(name); \ + SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \ SDL_free(name); \ } \ } \ } \ } -DETECT_DEV_IMPL(Out, WAVEOUTCAPS) -DETECT_DEV_IMPL(In, WAVEINCAPS) +DETECT_DEV_IMPL(SDL_FALSE, Out, WAVEOUTCAPS) +DETECT_DEV_IMPL(SDL_TRUE, In, WAVEINCAPS) static void -WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +WINMM_DetectDevices(void) { - if (iscapture) { - DetectWaveInDevs(addfn); - } else { - DetectWaveOutDevs(addfn); - } + DetectWaveInDevs(); + DetectWaveOutDevs(); } static void CALLBACK @@ -220,48 +218,19 @@ PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture) } static int -WINMM_OpenDevice(_THIS, const char *devname, int iscapture) +WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); int valid_datatype = 0; MMRESULT result; WAVEFORMATEX waveformat; UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */ - char *utf8 = NULL; UINT i; - if (devname != NULL) { /* specific device requested? */ - if (iscapture) { - const UINT devcount = waveInGetNumDevs(); - WAVEINCAPS caps; - for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { - result = waveInGetDevCaps(i, &caps, sizeof (caps)); - if (result != MMSYSERR_NOERROR) - continue; - else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) - continue; - else if (SDL_strcmp(devname, utf8) == 0) - devId = i; - SDL_free(utf8); - } - } else { - const UINT devcount = waveOutGetNumDevs(); - WAVEOUTCAPS caps; - for (i = 0; (i < devcount) && (devId == WAVE_MAPPER); i++) { - result = waveOutGetDevCaps(i, &caps, sizeof (caps)); - if (result != MMSYSERR_NOERROR) - continue; - else if ((utf8 = WIN_StringToUTF8(caps.szPname)) == NULL) - continue; - else if (SDL_strcmp(devname, utf8) == 0) - devId = i; - SDL_free(utf8); - } - } - - if (devId == WAVE_MAPPER) { - return SDL_SetError("Requested device not found"); - } + if (handle != NULL) { /* specific device requested? */ + /* -1 because we increment the original value to avoid NULL. */ + const size_t val = ((size_t) handle) - 1; + devId = (UINT) val; } /* Initialize all variables that we clean on shutdown */ @@ -279,10 +248,6 @@ WINMM_OpenDevice(_THIS, const char *devname, int iscapture) if (this->spec.channels > 2) this->spec.channels = 2; /* !!! FIXME: is this right? */ - /* Check the buffer size -- minimum of 1/4 second (word aligned) */ - if (this->spec.samples < (this->spec.freq / 4)) - this->spec.samples = ((this->spec.freq / 4) + 3) & ~3; - while ((!valid_datatype) && (test_format)) { switch (test_format) { case AUDIO_U8: diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index 85ac14602..15fce4a8d 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -126,16 +126,13 @@ struct SDL_PrivateAudioData static void -XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +XAUDIO2_DetectDevices(void) { IXAudio2 *ixa2 = NULL; UINT32 devcount = 0; UINT32 i = 0; - if (iscapture) { - SDL_SetError("XAudio2: capture devices unsupported."); - return; - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { + if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { SDL_SetError("XAudio2: XAudio2Create() failed at detection."); return; } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { @@ -149,8 +146,8 @@ XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { char *str = WIN_StringToUTF8(details.DisplayName); if (str != NULL) { - addfn(str); - SDL_free(str); /* addfn() made a copy of the string. */ + SDL_AddAudioDevice(SDL_FALSE, str, (void *) ((size_t) i+1)); + SDL_free(str); /* SDL_AddAudioDevice made a copy of the string. */ } } } @@ -169,8 +166,8 @@ VoiceCBOnBufferEnd(THIS_ void *data) static void STDMETHODCALLTYPE VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error) { - /* !!! FIXME: attempt to recover, or mark device disconnected. */ - SDL_assert(0 && "write me!"); + SDL_AudioDevice *this = (SDL_AudioDevice *) data; + SDL_OpenedAudioDeviceDisconnected(this); } /* no-op callbacks... */ @@ -221,7 +218,7 @@ XAUDIO2_PlayDevice(_THIS) if (result != S_OK) { /* uhoh, panic! */ IXAudio2SourceVoice_FlushSourceBuffers(source); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -289,7 +286,7 @@ XAUDIO2_CloseDevice(_THIS) } static int -XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) +XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { HRESULT result = S_OK; WAVEFORMATEX waveformat; @@ -315,9 +312,17 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) static IXAudio2VoiceCallback callbacks = { &callbacks_vtable }; - if (iscapture) { - return SDL_SetError("XAudio2: capture devices unsupported."); - } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { +#if defined(SDL_XAUDIO2_WIN8) + /* !!! FIXME: hook up hotplugging. */ +#else + if (handle != NULL) { /* specific device requested? */ + /* -1 because we increment the original value to avoid NULL. */ + const size_t val = ((size_t) handle) - 1; + devId = (UINT32) val; + } +#endif + + if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) { return SDL_SetError("XAudio2: XAudio2Create() failed at open."); } @@ -332,37 +337,6 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) ixa2->SetDebugConfiguration(&debugConfig); */ -#if ! defined(__WINRT__) - if (devname != NULL) { - UINT32 devcount = 0; - UINT32 i = 0; - - if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed."); - } - for (i = 0; i < devcount; i++) { - XAUDIO2_DEVICE_DETAILS details; - if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) { - char *str = WIN_StringToUTF8(details.DisplayName); - if (str != NULL) { - const int match = (SDL_strcmp(str, devname) == 0); - SDL_free(str); - if (match) { - devId = i; - break; - } - } - } - } - - if (i == devcount) { - IXAudio2_Release(ixa2); - return SDL_SetError("XAudio2: Requested device not found."); - } - } -#endif - /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); @@ -529,6 +503,16 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = XAUDIO2_CloseDevice; impl->Deinitialize = XAUDIO2_Deinitialize; + /* !!! FIXME: We can apparently use a C++ interface on Windows 8 + * !!! FIXME: (Windows::Devices::Enumeration::DeviceInformation) for device + * !!! FIXME: detection, but it's not implemented here yet. + * !!! FIXME: see http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx + * !!! FIXME: for now, force the default device. + */ +#if defined(SDL_XAUDIO2_WIN8) || defined(__WINRT__) + impl->OnlyHasDefaultOutputDevice = 1; +#endif + return 1; /* this audio target is available. */ #endif } diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index b62ab1a9f..e7f90bacd 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -32,6 +32,7 @@ #include "../../events/SDL_events_c.h" #include "../../video/android/SDL_androidkeyboard.h" +#include "../../video/android/SDL_androidmouse.h" #include "../../video/android/SDL_androidtouch.h" #include "../../video/android/SDL_androidvideo.h" #include "../../video/android/SDL_androidwindow.h" @@ -44,8 +45,8 @@ #define LOG_TAG "SDL_android" /* #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) */ /* #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) */ -#define LOGI(...) do {} while (false) -#define LOGE(...) do {} while (false) +#define LOGI(...) do {} while (0) +#define LOGE(...) do {} while (0) /* Uncomment this to log messages entering and exiting methods in this file */ /* #define DEBUG_JNI */ @@ -57,7 +58,6 @@ static void Android_JNI_ThreadDestroyed(void*); *******************************************************************************/ #include #include -#include /******************************************************************************* @@ -80,7 +80,7 @@ static jmethodID midPollInputDevices; /* Accelerometer data storage */ static float fLastAccelerometer[3]; -static bool bHasNewData; +static SDL_bool bHasNewData; /******************************************************************************* Functions called by JNI @@ -132,7 +132,7 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "pollInputDevices", "()V"); - bHasNewData = false; + bHasNewData = SDL_FALSE; if(!midGetNativeSurface || !midFlipBuffers || !midAudioInit || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) { @@ -144,9 +144,9 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) /* Resize */ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeResize( JNIEnv* env, jclass jcls, - jint width, jint height, jint format) + jint width, jint height, jint format, jfloat rate) { - Android_SetScreenResolution(width, height, format); + Android_SetScreenResolution(width, height, format, rate); } /* Paddown */ @@ -294,6 +294,14 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeTouch( Android_OnTouch(touch_device_id_in, pointer_finger_id_in, action, x, y, p); } +/* Mouse */ +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeMouse( + JNIEnv* env, jclass jcls, + jint button, jint action, jfloat x, jfloat y) +{ + Android_OnMouse(button, action, x, y); +} + /* Accelerometer */ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeAccel( JNIEnv* env, jclass jcls, @@ -302,7 +310,7 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeAccel( fLastAccelerometer[0] = x; fLastAccelerometer[1] = y; fLastAccelerometer[2] = z; - bHasNewData = true; + bHasNewData = SDL_TRUE; } /* Low memory */ @@ -386,7 +394,7 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLInputConnection_nativeSetComposing (*env)->ReleaseStringUTFChars(env, text, utftext); } -jstring Java_org_libsdl_app_SDLActivity_nativeGetHint(JNIEnv* env, jclass cls, jstring name) { +JNIEXPORT jstring JNICALL Java_org_libsdl_app_SDLActivity_nativeGetHint(JNIEnv* env, jclass cls, jstring name) { const char *utfname = (*env)->GetStringUTFChars(env, name, NULL); const char *hint = SDL_GetHint(utfname); @@ -487,7 +495,7 @@ SDL_bool Android_JNI_GetAccelerometerValues(float values[3]) for (i = 0; i < 3; ++i) { values[i] = fLastAccelerometer[i]; } - bHasNewData = false; + bHasNewData = SDL_FALSE; retval = SDL_TRUE; } @@ -549,12 +557,12 @@ int Android_JNI_SetupThread(void) * Audio support */ static jboolean audioBuffer16Bit = JNI_FALSE; -static jboolean audioBufferStereo = JNI_FALSE; static jobject audioBuffer = NULL; static void* audioBufferPinned = NULL; int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) { + jboolean audioBufferStereo; int audioBufferFrames; JNIEnv *env = Android_JNI_GetEnv(); @@ -647,7 +655,7 @@ void Android_JNI_CloseAudioDevice() /* Test for an exception and call SDL_SetError with its detail if one occurs */ /* If the parameter silent is truthy then SDL_SetError() will not be called. */ -static bool Android_JNI_ExceptionOccurred(bool silent) +static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent) { SDL_assert(LocalReferenceHolder_IsActive()); JNIEnv *mEnv = Android_JNI_GetEnv(); @@ -681,10 +689,10 @@ static bool Android_JNI_ExceptionOccurred(bool silent) (*mEnv)->ReleaseStringUTFChars(mEnv, exceptionName, exceptionNameUTF8); } - return true; + return SDL_TRUE; } - return false; + return SDL_FALSE; } static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) @@ -728,19 +736,19 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) */ mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager), "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;"); inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString); - if (Android_JNI_ExceptionOccurred(true)) { + if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { goto fallback; } mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getStartOffset", "()J"); ctx->hidden.androidio.offset = (*mEnv)->CallLongMethod(mEnv, inputStream, mid); - if (Android_JNI_ExceptionOccurred(true)) { + if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { goto fallback; } mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getDeclaredLength", "()J"); ctx->hidden.androidio.size = (*mEnv)->CallLongMethod(mEnv, inputStream, mid); - if (Android_JNI_ExceptionOccurred(true)) { + if (Android_JNI_ExceptionOccurred(SDL_TRUE)) { goto fallback; } @@ -754,7 +762,7 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) /* Seek to the correct offset in the file. */ lseek(ctx->hidden.androidio.fd, (off_t)ctx->hidden.androidio.offset, SEEK_SET); - if (false) { + if (0) { fallback: /* Disabled log message because of spam on the Nexus 7 */ /* __android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file"); */ @@ -766,13 +774,13 @@ fallback: mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager), "open", "(Ljava/lang/String;I)Ljava/io/InputStream;"); inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { // Try fallback to APK Extension files mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context), "openAPKExtensionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;"); inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { goto failure; } } @@ -790,7 +798,7 @@ fallback: mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "available", "()I"); ctx->hidden.androidio.size = (long)(*mEnv)->CallIntMethod(mEnv, inputStream, mid); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { goto failure; } @@ -801,7 +809,7 @@ fallback: "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;"); readableByteChannel = (*mEnv)->CallStaticObjectMethod( mEnv, channels, mid, inputStream); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { goto failure; } @@ -814,7 +822,7 @@ fallback: ctx->hidden.androidio.readMethod = mid; } - if (false) { + if (0) { failure: result = -1; @@ -907,7 +915,7 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, /* result = readableByteChannel.read(...); */ int result = (*mEnv)->CallIntMethod(mEnv, readableByteChannel, readMethod, byteBuffer); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { LocalReferenceHolder_Cleanup(&refs); return 0; } @@ -932,7 +940,7 @@ size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer, return 0; } -static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, bool release) +static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, SDL_bool release) { struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); @@ -955,7 +963,7 @@ static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, bool release) "close", "()V"); (*mEnv)->CallVoidMethod(mEnv, inputStream, mid); (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.assetFileDescriptorRef); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { result = -1; } } @@ -968,7 +976,7 @@ static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, bool release) (*mEnv)->CallVoidMethod(mEnv, inputStream, mid); (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.inputStreamRef); (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.readableByteChannelRef); - if (Android_JNI_ExceptionOccurred(false)) { + if (Android_JNI_ExceptionOccurred(SDL_FALSE)) { result = -1; } } @@ -1059,7 +1067,7 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) } else if (movement < 0) { /* We can't seek backwards so we have to reopen the file and seek */ /* forwards which obviously isn't very efficient */ - Internal_Android_JNI_FileClose(ctx, false); + Internal_Android_JNI_FileClose(ctx, SDL_FALSE); Internal_Android_JNI_FileOpen(ctx); Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET); } @@ -1071,7 +1079,7 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) int Android_JNI_FileClose(SDL_RWops* ctx) { - return Internal_Android_JNI_FileClose(ctx, true); + return Internal_Android_JNI_FileClose(ctx, SDL_TRUE); } /* returns a new global reference which needs to be released later */ @@ -1602,6 +1610,11 @@ const char * SDL_AndroidGetExternalStoragePath() return s_AndroidExternalFilesPath; } +jclass Android_JNI_GetActivityClass(void) +{ + return mActivityClass; +} + #endif /* __ANDROID__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 051958a49..d749bf101 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -78,6 +78,7 @@ int Android_JNI_GetTouchDeviceIds(int **ids); #include JNIEnv *Android_JNI_GetEnv(void); int Android_JNI_SetupThread(void); +jclass Android_JNI_GetActivityClass(void); /* Generic messages */ int Android_JNI_SendMessage(int command, int param); diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c index c4a7d05ce..1f4c31657 100644 --- a/src/core/linux/SDL_evdev.c +++ b/src/core/linux/SDL_evdev.c @@ -681,10 +681,10 @@ SDL_EVDEV_Poll(void) SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value); break; case REL_WHEEL: - SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value); + SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL); break; case REL_HWHEEL: - SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0); + SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL); break; default: break; diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index 1a0729f26..e901bece3 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -462,6 +462,9 @@ SDL_IBus_Init(void) ibus_addr_file = SDL_strdup(addr_file); addr = IBus_ReadAddressFromFile(addr_file); + if (!addr) { + return SDL_FALSE; + } if (inotify_fd < 0) { inotify_fd = inotify_init(); @@ -476,8 +479,10 @@ SDL_IBus_Init(void) inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY); SDL_free(addr_file); - result = IBus_SetupConnection(dbus, addr); - SDL_free(addr); + if (addr) { + result = IBus_SetupConnection(dbus, addr); + SDL_free(addr); + } } return result; diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index 585018381..b1310bc3f 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -350,17 +350,19 @@ guess_device_class(struct udev_device *dev) devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ } else if (test_bit(BTN_TOUCH, bitmask_key)) { ; /* ID_INPUT_TOUCHSCREEN */ - } else if (test_bit(BTN_TRIGGER, bitmask_key) || - test_bit(BTN_A, bitmask_key) || - test_bit(BTN_1, bitmask_key) || - test_bit(ABS_RX, bitmask_abs) || - test_bit(ABS_RY, bitmask_abs) || - test_bit(ABS_RZ, bitmask_abs) || - test_bit(ABS_THROTTLE, bitmask_abs) || - test_bit(ABS_RUDDER, bitmask_abs) || - test_bit(ABS_WHEEL, bitmask_abs) || - test_bit(ABS_GAS, bitmask_abs) || - test_bit(ABS_BRAKE, bitmask_abs)) { + } + + if (test_bit(BTN_TRIGGER, bitmask_key) || + test_bit(BTN_A, bitmask_key) || + test_bit(BTN_1, bitmask_key) || + test_bit(ABS_RX, bitmask_abs) || + test_bit(ABS_RY, bitmask_abs) || + test_bit(ABS_RZ, bitmask_abs) || + test_bit(ABS_THROTTLE, bitmask_abs) || + test_bit(ABS_RUDDER, bitmask_abs) || + test_bit(ABS_WHEEL, bitmask_abs) || + test_bit(ABS_GAS, bitmask_abs) || + test_bit(ABS_BRAKE, bitmask_abs)) { devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */ } } @@ -371,10 +373,10 @@ guess_device_class(struct udev_device *dev) devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ } - /* the first 32 bits are ESC, numbers, and Q to D; if we have all of - * those, consider it a full keyboard; do not test KEY_RESERVED, though */ + /* the first 32 bits are ESC, numbers, and Q to D; if we have any of + * those, consider it a keyboard device; do not test KEY_RESERVED, though */ keyboard_mask = 0xFFFFFFFE; - if ((bitmask_key[0] & keyboard_mask) == keyboard_mask) + if ((bitmask_key[0] & keyboard_mask) != 0) devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */ return devclass; diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index d91451068..009d1a52c 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -126,6 +126,16 @@ static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *n { SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0); + /* HACK: prevent SDL from altering an app's .appxmanifest-set orientation + * from being changed on startup, by detecting when SDL_HINT_ORIENTATIONS + * is getting registered. + * + * TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'. + */ + if ((oldValue == NULL) && (newValue == NULL)) { + return; + } + // Start with no orientation flags, then add each in as they're parsed // from newValue. unsigned int orientationFlags = 0; diff --git a/src/core/winrt/SDL_winrtapp_xaml.h b/src/core/winrt/SDL_winrtapp_xaml.h index 2296475b0..7f5d7f1d7 100644 --- a/src/core/winrt/SDL_winrtapp_xaml.h +++ b/src/core/winrt/SDL_winrtapp_xaml.h @@ -23,7 +23,7 @@ #ifndef _SDL_winrtapp_xaml_h #define _SDL_winrtapp_xaml_h -#include "SDL_types.h" +#include "SDL_stdinc.h" #ifdef __cplusplus extern SDL_bool WINRT_XAMLWasEnabled; diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c index c725c01a0..48e8001f3 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -79,6 +79,7 @@ CPU_haveCPUID(void) { int has_CPUID = 0; /* *INDENT-OFF* */ +#ifndef SDL_CPUINFO_DISABLED #if defined(__GNUC__) && defined(i386) __asm__ ( " pushfl # Get original EFLAGS \n" @@ -165,6 +166,7 @@ done: "1: \n" ); #endif +#endif /* *INDENT-ON* */ return has_CPUID; } @@ -272,6 +274,7 @@ static int CPU_haveAltiVec(void) { volatile int altivec = 0; +#ifndef SDL_CPUINFO_DISABLED #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__)) #ifdef __OpenBSD__ int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC }; @@ -291,6 +294,7 @@ CPU_haveAltiVec(void) altivec = 1; } signal(SIGILL, handler); +#endif #endif return altivec; } @@ -418,6 +422,7 @@ int SDL_GetCPUCount(void) { if (!SDL_CPUCount) { +#ifndef SDL_CPUINFO_DISABLED #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) if (SDL_CPUCount <= 0) { SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN); @@ -435,6 +440,7 @@ SDL_GetCPUCount(void) GetSystemInfo(&info); SDL_CPUCount = info.dwNumberOfProcessors; } +#endif #endif /* There has to be at least 1, right? :) */ if (SDL_CPUCount <= 0) { @@ -452,10 +458,11 @@ SDL_GetCPUType(void) if (!SDL_CPUType[0]) { int i = 0; - int a, b, c, d; if (CPU_haveCPUID()) { + int a, b, c, d; cpuid(0x00000000, a, b, c, d); + (void) a; SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8; SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8; SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8; @@ -557,15 +564,12 @@ int SDL_GetCPUCacheLineSize(void) { const char *cpuType = SDL_GetCPUType(); - + int a, b, c, d; + (void) a; (void) b; (void) c; (void) d; if (SDL_strcmp(cpuType, "GenuineIntel") == 0) { - int a, b, c, d; - cpuid(0x00000001, a, b, c, d); return (((b >> 8) & 0xff) * 8); } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) { - int a, b, c, d; - cpuid(0x80000005, a, b, c, d); return (c & 0xff); } else { @@ -723,6 +727,7 @@ int SDL_GetSystemRAM(void) { if (!SDL_SystemRAM) { +#ifndef SDL_CPUINFO_DISABLED #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) if (SDL_SystemRAM <= 0) { SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024)); @@ -756,6 +761,7 @@ SDL_GetSystemRAM(void) SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024)); } } +#endif #endif } return SDL_SystemRAM; diff --git a/src/dynapi/SDL_dynapi.c b/src/dynapi/SDL_dynapi.c index c378699d4..f14cda948 100644 --- a/src/dynapi/SDL_dynapi.c +++ b/src/dynapi/SDL_dynapi.c @@ -206,7 +206,14 @@ SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize) static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) { HANDLE lib = LoadLibraryA(fname); - return lib ? GetProcAddress(lib, sym) : NULL; + void *retval = NULL; + if (lib) { + retval = GetProcAddress(lib, sym); + if (retval == NULL) { + FreeLibrary(lib); + } + } + return retval; } #elif defined(__HAIKU__) @@ -215,8 +222,11 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) { image_id lib = load_add_on(fname); void *retval = NULL; - if ((lib < 0) || (get_image_symbol(lib, sym, B_SYMBOL_TYPE_TEXT, &retval) != B_NO_ERROR)) { - retval = NULL; + if (lib >= 0) { + if (get_image_symbol(lib, sym, B_SYMBOL_TYPE_TEXT, &retval) != B_NO_ERROR) { + unload_add_on(lib); + retval = NULL; + } } return retval; } @@ -225,7 +235,14 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym) { void *lib = dlopen(fname, RTLD_NOW | RTLD_LOCAL); - return lib ? dlsym(lib, sym) : NULL; + void *retval = NULL; + if (lib != NULL) { + retval = dlsym(lib, sym); + if (retval == NULL) { + dlclose(lib); + } + } + return retval; } #else #error Please define your platform. diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h index 2a5403a4e..5f4ea8d28 100644 --- a/src/dynapi/SDL_dynapi.h +++ b/src/dynapi/SDL_dynapi.h @@ -43,13 +43,16 @@ #include "TargetConditionals.h" #endif -#if TARGET_OS_IPHONE || __native_client__ /* probably not useful on iOS or NACL. */ +#if TARGET_OS_IPHONE || __native_client__ || __EMSCRIPTEN__ /* probably not useful on iOS, NACL or Emscripten. */ #define SDL_DYNAMIC_API 0 #elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */ #define SDL_DYNAMIC_API 0 #elif defined(__clang_analyzer__) #define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */ -#else /* everyone else. */ +#endif + +/* everyone else. This is where we turn on the API if nothing forced it off. */ +#ifndef SDL_DYNAMIC_API #define SDL_DYNAMIC_API 1 #endif diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8bcde6312..dcc6d4677 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -591,3 +591,4 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index c41cdc9f0..6408e3f89 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -623,3 +623,4 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX2,(void),(),return) SDL_DYNAPI_PROC(int,SDL_QueueAudio,(SDL_AudioDeviceID a, const void *b, Uint32 c),(a,b,c),return) SDL_DYNAPI_PROC(Uint32,SDL_GetQueuedAudioSize,(SDL_AudioDeviceID a),(a),return) SDL_DYNAPI_PROC(void,SDL_ClearQueuedAudio,(SDL_AudioDeviceID a),(a),) +SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 963b9bd7c..cfbdcf89a 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -75,12 +75,13 @@ static struct SDL_mutex *lock; volatile SDL_bool active; volatile int count; + volatile int max_events_seen; SDL_EventEntry *head; SDL_EventEntry *tail; SDL_EventEntry *free; SDL_SysWMEntry *wmmsg_used; SDL_SysWMEntry *wmmsg_free; -} SDL_EventQ = { NULL, SDL_TRUE }; +} SDL_EventQ = { NULL, SDL_TRUE, 0, 0, NULL, NULL, NULL, NULL, NULL }; /* Public functions */ @@ -88,6 +89,7 @@ static struct void SDL_StopEventLoop(void) { + const char *report = SDL_GetHint("SDL_EVENT_QUEUE_STATISTICS"); int i; SDL_EventEntry *entry; SDL_SysWMEntry *wmmsg; @@ -98,6 +100,11 @@ SDL_StopEventLoop(void) SDL_EventQ.active = SDL_FALSE; + if (report && SDL_atoi(report)) { + SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n", + SDL_EventQ.max_events_seen); + } + /* Clean out EventQ */ for (entry = SDL_EventQ.head; entry; ) { SDL_EventEntry *next = entry->next; @@ -119,7 +126,9 @@ SDL_StopEventLoop(void) SDL_free(wmmsg); wmmsg = next; } + SDL_EventQ.count = 0; + SDL_EventQ.max_events_seen = 0; SDL_EventQ.head = NULL; SDL_EventQ.tail = NULL; SDL_EventQ.free = NULL; @@ -218,6 +227,10 @@ SDL_AddEvent(SDL_Event * event) } ++SDL_EventQ.count; + if (SDL_EventQ.count > SDL_EventQ.max_events_seen) { + SDL_EventQ.max_events_seen = SDL_EventQ.count; + } + return 1; } diff --git a/src/events/SDL_gesture.c b/src/events/SDL_gesture.c index 46a554635..746d11630 100644 --- a/src/events/SDL_gesture.c +++ b/src/events/SDL_gesture.c @@ -24,6 +24,7 @@ /* General mouse handling code for SDL */ #include "SDL_events.h" +#include "SDL_endian.h" #include "SDL_events_c.h" #include "SDL_gesture_c.h" @@ -114,14 +115,34 @@ static unsigned long SDL_HashDollar(SDL_FloatPoint* points) static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops *dst) { - if (dst == NULL) return 0; + if (dst == NULL) { + return 0; + } /* No Longer storing the Hash, rehash on load */ /* if (SDL_RWops.write(dst, &(templ->hash), sizeof(templ->hash), 1) != 1) return 0; */ +#if SDL_BYTEORDER == SDL_LIL_ENDIAN if (SDL_RWwrite(dst, templ->path, - sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) + sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) { return 0; + } +#else + { + SDL_DollarTemplate copy = *templ; + SDL_FloatPoint *p = copy.path; + int i; + for (i = 0; i < DOLLARNPOINTS; i++, p++) { + p->x = SDL_SwapFloatLE(p->x); + p->y = SDL_SwapFloatLE(p->y); + } + + if (SDL_RWwrite(dst, copy.path, + sizeof(copy.path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) { + return 0; + } + } +#endif return 1; } @@ -184,7 +205,7 @@ static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch, SDL_FloatPoint* path) int index = -1; int i = 0; if (inTouch == NULL) { - if (SDL_numGestureTouches == 0) return -1; + if (SDL_numGestureTouches == 0) return SDL_SetError("no gesture touch devices registered"); for (i = 0; i < SDL_numGestureTouches; i++) { inTouch = &SDL_gestureTouch[i]; index = SDL_AddDollarGesture_one(inTouch, path); @@ -203,17 +224,33 @@ int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) SDL_GestureTouch *touch = NULL; if (src == NULL) return 0; if (touchId >= 0) { - for (i = 0; i < SDL_numGestureTouches; i++) - if (SDL_gestureTouch[i].id == touchId) + for (i = 0; i < SDL_numGestureTouches; i++) { + if (SDL_gestureTouch[i].id == touchId) { touch = &SDL_gestureTouch[i]; - if (touch == NULL) return -1; + } + } + if (touch == NULL) { + return SDL_SetError("given touch id not found"); + } } while (1) { SDL_DollarTemplate templ; - if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < - DOLLARNPOINTS) break; + if (SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < DOLLARNPOINTS) { + if (loaded == 0) { + return SDL_SetError("could not read any dollar gesture from rwops"); + } + break; + } + +#if SDL_BYTEORDER != SDL_LIL_ENDIAN + for (i = 0; i < DOLLARNPOINTS; i++) { + SDL_FloatPoint *p = &templ.path[i]; + p->x = SDL_SwapFloatLE(p->x); + p->y = SDL_SwapFloatLE(p->y); + } +#endif if (touchId >= 0) { /* printf("Adding loaded gesture to 1 touch\n"); */ diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 21fb87771..326bbbadc 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -293,9 +293,14 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ event.motion.yrel = yrel; posted = (SDL_PushEvent(&event) > 0); } - /* Use unclamped values if we're getting events outside the window */ - mouse->last_x = x; - mouse->last_y = y; + if (relative) { + mouse->last_x = mouse->x; + mouse->last_y = mouse->y; + } else { + /* Use unclamped values if we're getting events outside the window */ + mouse->last_x = x; + mouse->last_y = y; + } return posted; } @@ -303,10 +308,11 @@ static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button) { if (button >= mouse->num_clickstates) { int i, count = button + 1; - mouse->clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); - if (!mouse->clickstate) { + SDL_MouseClickState *clickstate = (SDL_MouseClickState *)SDL_realloc(mouse->clickstate, count * sizeof(*mouse->clickstate)); + if (!clickstate) { return NULL; } + mouse->clickstate = clickstate; for (i = mouse->num_clickstates; i < count; ++i) { SDL_zero(mouse->clickstate[i]); @@ -397,7 +403,7 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 } int -SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y) +SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction) { SDL_Mouse *mouse = SDL_GetMouse(); int posted; @@ -419,6 +425,7 @@ SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y) event.wheel.which = mouseID; event.wheel.x = x; event.wheel.y = y; + event.wheel.direction = (Uint32)direction; posted = (SDL_PushEvent(&event) > 0); } return posted; diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index df95e1e52..56c061a56 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -120,7 +120,7 @@ extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int rel extern int SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button); /* Send a mouse wheel event */ -extern int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y); +extern int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction); /* Shutdown the mouse subsystem */ extern void SDL_MouseQuit(void); diff --git a/src/events/SDL_quit.c b/src/events/SDL_quit.c index db7af98fa..c80812202 100644 --- a/src/events/SDL_quit.c +++ b/src/events/SDL_quit.c @@ -19,6 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../SDL_internal.h" +#include "SDL_hints.h" /* General quit handling code for SDL */ @@ -30,6 +31,8 @@ #include "SDL_events_c.h" +static SDL_bool disable_signals = SDL_FALSE; + #ifdef HAVE_SIGNAL_H static void SDL_HandleSIG(int sig) @@ -43,8 +46,8 @@ SDL_HandleSIG(int sig) #endif /* HAVE_SIGNAL_H */ /* Public functions */ -int -SDL_QuitInit(void) +static int +SDL_QuitInit_Internal(void) { #ifdef HAVE_SIGACTION struct sigaction action; @@ -80,11 +83,22 @@ SDL_QuitInit(void) #endif /* HAVE_SIGNAL_H */ /* That's it! */ - return (0); + return 0; } -void -SDL_QuitQuit(void) +int +SDL_QuitInit(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_NO_SIGNAL_HANDLERS); + disable_signals = hint && (SDL_atoi(hint) == 1); + if (!disable_signals) { + return SDL_QuitInit_Internal(); + } + return 0; +} + +static void +SDL_QuitQuit_Internal(void) { #ifdef HAVE_SIGACTION struct sigaction action; @@ -110,6 +124,14 @@ SDL_QuitQuit(void) #endif /* HAVE_SIGNAL_H */ } +void +SDL_QuitQuit(void) +{ + if (!disable_signals) { + SDL_QuitQuit_Internal(); + } +} + /* This function returns 1 if it's okay to close the application window */ int SDL_SendQuit(void) diff --git a/src/file/cocoa/SDL_rwopsbundlesupport.m b/src/file/cocoa/SDL_rwopsbundlesupport.m index 1ae399c2d..a56879e63 100644 --- a/src/file/cocoa/SDL_rwopsbundlesupport.m +++ b/src/file/cocoa/SDL_rwopsbundlesupport.m @@ -50,14 +50,13 @@ FILE* SDL_OpenFPFromBundleOrFallback(const char *file, const char *mode) NSString* full_path_with_file_to_try = [resource_path stringByAppendingPathComponent:ns_string_file_component]; if([file_manager fileExistsAtPath:full_path_with_file_to_try]) { fp = fopen([full_path_with_file_to_try fileSystemRepresentation], mode); - } - else { + } else { fp = fopen(file, mode); } return fp; }} -#endif /* __MACOSX__ */ +#endif /* __APPLE__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/filesystem/cocoa/SDL_sysfilesystem.m b/src/filesystem/cocoa/SDL_sysfilesystem.m index dab51c501..74e1e7b39 100644 --- a/src/filesystem/cocoa/SDL_sysfilesystem.m +++ b/src/filesystem/cocoa/SDL_sysfilesystem.m @@ -41,6 +41,7 @@ SDL_GetBasePath(void) const char* baseType = [[[bundle infoDictionary] objectForKey:@"SDL_FILESYSTEM_BASE_DIR_TYPE"] UTF8String]; const char *base = NULL; char *retval = NULL; + if (baseType == NULL) { baseType = "resource"; } @@ -52,6 +53,7 @@ SDL_GetBasePath(void) /* this returns the exedir for non-bundled and the resourceDir for bundled apps */ base = [[bundle resourcePath] fileSystemRepresentation]; } + if (base) { const size_t len = SDL_strlen(base) + 2; retval = (char *) SDL_malloc(len); @@ -69,9 +71,10 @@ char * SDL_GetPrefPath(const char *org, const char *app) { @autoreleasepool { - NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); char *retval = NULL; + NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + if ([array count] > 0) { /* we only want the first item in the list. */ NSString *str = [array objectAtIndex:0]; const char *base = [str fileSystemRepresentation]; diff --git a/src/filesystem/emscripten/SDL_sysfilesystem.c b/src/filesystem/emscripten/SDL_sysfilesystem.c new file mode 100644 index 000000000..02471d394 --- /dev/null +++ b/src/filesystem/emscripten/SDL_sysfilesystem.c @@ -0,0 +1,69 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifdef SDL_FILESYSTEM_EMSCRIPTEN + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* System dependent filesystem routines */ +#include +#include + +#include "SDL_error.h" +#include "SDL_filesystem.h" + +#include + +char * +SDL_GetBasePath(void) +{ + char *retval = "/"; + return SDL_strdup(retval); +} + +char * +SDL_GetPrefPath(const char *org, const char *app) +{ + const char *append = "/libsdl/"; + char *retval; + size_t len = 0; + + len = SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; + retval = (char *) SDL_malloc(len); + if (!retval) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_snprintf(retval, len, "%s%s/%s/", append, org, app); + + if (mkdir(retval, 0700) != 0 && errno != EEXIST) { + SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno)); + SDL_free(retval); + return NULL; + } + + return retval; +} + +#endif /* SDL_FILESYSTEM_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/filesystem/nacl/SDL_sysfilesystem.c b/src/filesystem/nacl/SDL_sysfilesystem.c index ff55b2ba9..0111683a2 100644 --- a/src/filesystem/nacl/SDL_sysfilesystem.c +++ b/src/filesystem/nacl/SDL_sysfilesystem.c @@ -38,4 +38,5 @@ SDL_GetPrefPath(const char *org, const char *app) return NULL; } -#endif /* __NACL__ */ \ No newline at end of file +#endif /* SDL_FILESYSTEM_NACL */ + diff --git a/src/haptic/SDL_syshaptic.h b/src/haptic/SDL_syshaptic.h index c808adc30..fa91f9beb 100644 --- a/src/haptic/SDL_syshaptic.h +++ b/src/haptic/SDL_syshaptic.h @@ -27,12 +27,6 @@ #include "SDL_haptic.h" -/* - * Number of haptic devices on the system. - */ -extern Uint8 SDL_numhaptics; - - struct haptic_effect { SDL_HapticEffect effect; /* The current event */ diff --git a/src/haptic/darwin/SDL_syshaptic.c b/src/haptic/darwin/SDL_syshaptic.c index 6d85bf0ed..1516d5d43 100644 --- a/src/haptic/darwin/SDL_syshaptic.c +++ b/src/haptic/darwin/SDL_syshaptic.c @@ -262,13 +262,13 @@ MacHaptic_MaybeAddDevice( io_object_t device ) CFSTR(kIOHIDPrimaryUsagePageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usagePage)) { - SDL_SetError("Haptic: Recieving device's usage page."); + SDL_SetError("Haptic: Receiving device's usage page."); } refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usage)) { - SDL_SetError("Haptic: Recieving device's usage."); + SDL_SetError("Haptic: Receiving device's usage."); } } } @@ -551,7 +551,7 @@ SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service) FFReleaseDevice(haptic->hwdata->device); creat_err: if (haptic->hwdata != NULL) { - free(haptic->hwdata); + SDL_free(haptic->hwdata); haptic->hwdata = NULL; } return -1; diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c index bab3ddbf8..fba536b48 100644 --- a/src/haptic/linux/SDL_syshaptic.c +++ b/src/haptic/linux/SDL_syshaptic.c @@ -288,8 +288,7 @@ MaybeAddDevice(const char *path) } item->fname = SDL_strdup(path); - if ( (item->fname == NULL) ) { - SDL_free(item->fname); + if (item->fname == NULL) { SDL_free(item); return -1; } @@ -441,7 +440,7 @@ SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd) open_err: close(fd); if (haptic->hwdata != NULL) { - free(haptic->hwdata); + SDL_free(haptic->hwdata); haptic->hwdata = NULL; } return -1; @@ -959,7 +958,7 @@ SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, return 0; new_effect_err: - free(effect->hweffect); + SDL_free(effect->hweffect); effect->hweffect = NULL; return -1; } diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 633a23cd1..766cfdf86 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -89,6 +89,7 @@ typedef struct _ControllerMapping_t static ControllerMapping_t *s_pSupportedControllers = NULL; static ControllerMapping_t *s_pXInputMapping = NULL; +static ControllerMapping_t *s_pEmscriptenMapping = NULL; /* The SDL game controller structure */ struct _SDL_GameController @@ -263,7 +264,13 @@ ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) return s_pXInputMapping; } else -#endif /* SDL_JOYSTICK_XINPUT */ +#endif +#if defined(SDL_JOYSTICK_EMSCRIPTEN) + if (s_pEmscriptenMapping) { + return s_pEmscriptenMapping; + } + else +#endif { SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index); return SDL_PrivateGetControllerMappingForGUID(&jGUID); @@ -668,6 +675,7 @@ SDL_GameControllerAddMapping(const char *mappingString) SDL_JoystickGUID jGUID; ControllerMapping_t *pControllerMapping; SDL_bool is_xinput_mapping = SDL_FALSE; + SDL_bool is_emscripten_mapping = SDL_FALSE; if (!mappingString) { return SDL_InvalidParamError("mappingString"); @@ -680,6 +688,9 @@ SDL_GameControllerAddMapping(const char *mappingString) if (!SDL_strcasecmp(pchGUID, "xinput")) { is_xinput_mapping = SDL_TRUE; } + if (!SDL_strcasecmp(pchGUID, "emscripten")) { + is_emscripten_mapping = SDL_TRUE; + } jGUID = SDL_JoystickGetGUIDFromString(pchGUID); SDL_free(pchGUID); @@ -715,6 +726,9 @@ SDL_GameControllerAddMapping(const char *mappingString) if (is_xinput_mapping) { s_pXInputMapping = pControllerMapping; } + if (is_emscripten_mapping) { + s_pEmscriptenMapping = pControllerMapping; + } pControllerMapping->guid = jGUID; pControllerMapping->name = pchName; pControllerMapping->mapping = pchMapping; diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index fe3a1671a..0f0e63746 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -63,7 +63,9 @@ static const char *s_ControllerMappings [] = "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", - "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,", + "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,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,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,", "050000004c050000c405000000010000,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,9 +75,13 @@ static const char *s_ControllerMappings [] = "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e040000d102000001010000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", #endif #if defined(__ANDROID__) "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", +#endif +#if defined(SDL_JOYSTICK_EMSCRIPTEN) + "emscripten,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", #endif NULL }; diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 2a60c0036..44cc21677 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -206,10 +206,6 @@ SDL_PrivateJoystickValid(SDL_Joystick * joystick) valid = 1; } - if (joystick && joystick->closed) { - valid = 0; - } - return valid; } @@ -412,6 +408,7 @@ SDL_JoystickClose(SDL_Joystick * joystick) } SDL_SYS_JoystickClose(joystick); + joystick->hwdata = NULL; joysticklist = SDL_joysticks; joysticklistprev = NULL; @@ -668,7 +665,7 @@ SDL_JoystickUpdate(void) SDL_SYS_JoystickUpdate(joystick); - if (joystick->closed && joystick->uncentered) { + if (joystick->force_recentering) { int i; /* Tell the app that everything is centered/unpressed... */ @@ -681,7 +678,7 @@ SDL_JoystickUpdate(void) for (i = 0; i < joystick->nhats; i++) SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); - joystick->uncentered = SDL_FALSE; + joystick->force_recentering = SDL_FALSE; } SDL_updating_joystick = NULL; diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index a39869575..f126e7519 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -53,8 +53,7 @@ struct _SDL_Joystick int ref_count; /* Reference count for multiple opens */ - SDL_bool closed; /* SDL_TRUE if this device is no longer valid */ - SDL_bool uncentered; /* SDL_TRUE if this device needs to have its state reset to 0 */ + SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */ struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */ }; @@ -78,14 +77,14 @@ extern const char *SDL_SYS_JoystickNameForDeviceIndex(int device_index); extern SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index); /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ extern int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index); /* Function to query if the joystick is currently attached - * It returns 1 if attached, 0 otherwise. + * It returns SDL_TRUE if attached, SDL_FALSE otherwise. */ extern SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick); diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index cce94b80c..bd67d5e6d 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -467,7 +467,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -495,10 +495,10 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) return (0); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return !joystick->closed && (joystick->hwdata != NULL); + return joystick->hwdata != NULL; } void @@ -529,11 +529,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - if (joystick->hwdata) { - ((SDL_joylist_item*)joystick->hwdata)->joystick = NULL; - joystick->hwdata = NULL; - } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/android/SDL_sysjoystick_c.h b/src/joystick/android/SDL_sysjoystick_c.h index 3d56b0b99..6ad6aa7a5 100644 --- a/src/joystick/android/SDL_sysjoystick_c.h +++ b/src/joystick/android/SDL_sysjoystick_c.h @@ -19,7 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include "SDL_config.h" +#include "../../SDL_internal.h" #ifdef SDL_JOYSTICK_ANDROID #include "../SDL_sysjoystick.h" diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c index 65a32ed2e..f0d356256 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -421,7 +421,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index) return (-1); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; @@ -558,8 +558,6 @@ SDL_SYS_JoystickClose(SDL_Joystick * joy) close(joy->hwdata->fd); SDL_free(joy->hwdata->path); SDL_free(joy->hwdata); - - return; } void diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 0518cc75b..fc7ae7554 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -138,7 +138,7 @@ static void JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender) { recDevice *device = (recDevice *) ctx; - device->removed = 1; + device->removed = SDL_TRUE; device->deviceRef = NULL; // deviceRef was invalidated due to the remove #if SDL_HAPTIC_IOKIT MacHaptic_MaybeRemoveDevice(device->ffservice); @@ -412,12 +412,12 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */ const io_service_t ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); +#if SDL_HAPTIC_IOKIT if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { device->ffservice = ioservice; -#if SDL_HAPTIC_IOKIT MacHaptic_MaybeAddDevice(ioservice); -#endif } +#endif } device->send_open_event = 1; @@ -446,9 +446,9 @@ ConfigHIDManager(CFArrayRef matchingArray) return SDL_FALSE; } + IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray); IOHIDManagerRegisterDeviceMatchingCallback(hidman, JoystickDeviceWasAddedCallback, NULL); IOHIDManagerScheduleWithRunLoop(hidman, runloop, SDL_JOYSTICK_RUNLOOP_MODE); - IOHIDManagerSetDeviceMatchingMultiple(hidman, matchingArray); while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { /* no-op. Callback fires once per existing device. */ @@ -560,10 +560,6 @@ SDL_SYS_NumJoysticks() void SDL_SYS_JoystickDetect() { - while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { - /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */ - } - if (s_bDeviceAdded || s_bDeviceRemoved) { recDevice *device = gpDeviceList; s_bDeviceAdded = SDL_FALSE; @@ -613,6 +609,12 @@ SDL_SYS_JoystickDetect() } } } + + // run this after the checks above so we don't set device->removed and delete the device before + // SDL_SYS_JoystickUpdate can run to clean up the SDL_Joystick object that owns this device + while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) { + /* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */ + } } /* Function to get the device-dependent name of a joystick */ @@ -644,7 +646,7 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - * The joystick to open is specified by the index field of the joystick. + * The joystick to open is specified by the device index. * This should fill the nbuttons and naxes fields of the joystick structure. * It returns 0, or -1 if there is an error. */ @@ -670,21 +672,12 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) } /* Function to query if the joystick is currently attached - * It returns 1 if attached, 0 otherwise. + * It returns SDL_TRUE if attached, SDL_FALSE otherwise. */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick) { - recDevice *device = gpDeviceList; - - while (device) { - if (joystick->instance_id == device->instance_id) { - return SDL_TRUE; - } - device = device->pNext; - } - - return SDL_FALSE; + return joystick->hwdata != NULL; } /* Function to update the state of a joystick - called as a device poll. @@ -705,9 +698,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) } if (device->removed) { /* device was unplugged; ignore it. */ - joystick->closed = 1; - joystick->uncentered = 1; - joystick->hwdata = NULL; + if (joystick->hwdata) { + joystick->force_recentering = SDL_TRUE; + joystick->hwdata = NULL; + } return; } @@ -795,7 +789,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/darwin/SDL_sysjoystick_c.h b/src/joystick/darwin/SDL_sysjoystick_c.h index 0a15ba18d..4c3300dca 100644 --- a/src/joystick/darwin/SDL_sysjoystick_c.h +++ b/src/joystick/darwin/SDL_sysjoystick_c.h @@ -58,8 +58,7 @@ struct joystick_hwdata recElement *firstButton; recElement *firstHat; - int removed; - int uncentered; + SDL_bool removed; int instance_id; SDL_JoystickGUID guid; diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c index 9baa79500..1cf2e28ce 100644 --- a/src/joystick/dummy/SDL_sysjoystick.c +++ b/src/joystick/dummy/SDL_sysjoystick.c @@ -34,7 +34,7 @@ int SDL_SYS_JoystickInit(void) { - return (0); + return 0; } int SDL_SYS_NumJoysticks() @@ -61,7 +61,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -71,7 +71,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) return SDL_SetError("Logic error: No joysticks available"); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; @@ -85,21 +85,18 @@ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { - return; } /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - return; } /* Function to perform any system-specific joystick related cleanup */ void SDL_SYS_JoystickQuit(void) { - return; } SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c new file mode 100644 index 000000000..3eb50e2a2 --- /dev/null +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -0,0 +1,427 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#ifdef SDL_JOYSTICK_EMSCRIPTEN + +#include /* For the definition of NULL */ +#include "SDL_error.h" +#include "SDL_events.h" + +#if !SDL_EVENTS_DISABLED +#include "../../events/SDL_events_c.h" +#endif + +#include "SDL_joystick.h" +#include "SDL_hints.h" +#include "SDL_assert.h" +#include "SDL_timer.h" +#include "SDL_log.h" +#include "SDL_sysjoystick_c.h" +#include "../SDL_joystick_c.h" + +static SDL_joylist_item * JoystickByIndex(int index); + +static SDL_joylist_item *SDL_joylist = NULL; +static SDL_joylist_item *SDL_joylist_tail = NULL; +static int numjoysticks = 0; +static int instance_counter = 0; + +EM_BOOL +Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) +{ + int i; + + SDL_joylist_item *item; + + if (JoystickByIndex(gamepadEvent->index) != NULL) { + return 1; + } + +#if !SDL_EVENTS_DISABLED + SDL_Event event; +#endif + + item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item)); + if (item == NULL) { + return 1; + } + + SDL_zerop(item); + item->index = gamepadEvent->index; + + item->name = SDL_strdup(gamepadEvent->id); + if ( item->name == NULL ) { + SDL_free(item); + return 1; + } + + item->mapping = SDL_strdup(gamepadEvent->mapping); + if ( item->mapping == NULL ) { + SDL_free(item->name); + SDL_free(item); + return 1; + } + + item->naxes = gamepadEvent->numAxes; + item->nbuttons = gamepadEvent->numButtons; + item->device_instance = instance_counter++; + + item->timestamp = gamepadEvent->timestamp; + + for( i = 0; i < item->naxes; i++) { + item->axis[i] = gamepadEvent->axis[i]; + } + + for( i = 0; i < item->nbuttons; i++) { + item->analogButton[i] = gamepadEvent->analogButton[i]; + item->digitalButton[i] = gamepadEvent->digitalButton[i]; + } + + if (SDL_joylist_tail == NULL) { + SDL_joylist = SDL_joylist_tail = item; + } else { + SDL_joylist_tail->next = item; + SDL_joylist_tail = item; + } + + ++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 = numjoysticks - 1; + if ( (SDL_EventOK == NULL) || + (*SDL_EventOK) (SDL_EventOKParam, &event) ) { + SDL_PushEvent(&event); + } + } +#endif /* !SDL_EVENTS_DISABLED */ + +#ifdef DEBUG_JOYSTICK + SDL_Log("Added joystick with index %d", item->index); +#endif + + return 1; +} + +EM_BOOL +Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) +{ + SDL_joylist_item *item = SDL_joylist; + SDL_joylist_item *prev = NULL; +#if !SDL_EVENTS_DISABLED + SDL_Event event; +#endif + + while (item != NULL) { + if (item->index == gamepadEvent->index) { + break; + } + prev = item; + item = item->next; + } + + if (item == NULL) { + return 1; + } + + if (item->joystick) { + item->joystick->hwdata = NULL; + } + + if (prev != NULL) { + prev->next = item->next; + } else { + SDL_assert(SDL_joylist == item); + SDL_joylist = item->next; + } + if (item == SDL_joylist_tail) { + SDL_joylist_tail = prev; + } + + /* Need to decrement the joystick count before we post the event */ + --numjoysticks; + +#if !SDL_EVENTS_DISABLED + event.type = SDL_JOYDEVICEREMOVED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = item->device_instance; + if ( (SDL_EventOK == NULL) || + (*SDL_EventOK) (SDL_EventOKParam, &event) ) { + SDL_PushEvent(&event); + } + } +#endif /* !SDL_EVENTS_DISABLED */ + +#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); + return 1; +} + +/* Function to scan the system for joysticks. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +int +SDL_SYS_JoystickInit(void) +{ + int retval, i, numjs; + EmscriptenGamepadEvent gamepadState; + + numjoysticks = 0; + numjs = emscripten_get_num_gamepads(); + + /* Check if gamepad is supported by browser */ + if (numjs == EMSCRIPTEN_RESULT_NOT_SUPPORTED) { + return -1; + } + + /* handle already connected gamepads */ + if (numjs > 0) { + for(i = 0; i < numjs; i++) { + retval = emscripten_get_gamepad_status(i, &gamepadState); + if (retval == EMSCRIPTEN_RESULT_SUCCESS) { + Emscripten_JoyStickConnected(EMSCRIPTEN_EVENT_GAMEPADCONNECTED, + &gamepadState, + NULL); + } + } + } + + retval = emscripten_set_gamepadconnected_callback(NULL, + 0, + Emscripten_JoyStickConnected); + + if(retval != EMSCRIPTEN_RESULT_SUCCESS) { + SDL_SYS_JoystickQuit(); + return -1; + } + + retval = emscripten_set_gamepaddisconnected_callback(NULL, + 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) +{ + SDL_joylist_item *item = SDL_joylist; + + if (index < 0) { + return NULL; + } + + while (item != NULL) { + if (item->index == index) { + break; + } + item = item->next; + } + + return item; +} + +int SDL_SYS_NumJoysticks() +{ + return numjoysticks; +} + +void SDL_SYS_JoystickDetect() +{ +} + +/* Function to get the device-dependent name of a joystick */ +const char * +SDL_SYS_JoystickNameForDeviceIndex(int device_index) +{ + 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 device_index) +{ + return JoystickByDeviceIndex(device_index)->device_instance; +} + +/* Function to open a joystick for use. + 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 device_index) +{ + SDL_joylist_item *item = JoystickByDeviceIndex(device_index); + + if (item == NULL ) { + return SDL_SetError("No such device"); + } + + if (item->joystick != NULL) { + return SDL_SetError("Joystick already opened"); + } + + joystick->instance_id = item->device_instance; + joystick->hwdata = (struct joystick_hwdata *) item; + item->joystick = joystick; + + /* HTML5 Gamepad API doesn't say anything about these */ + joystick->nhats = 0; + joystick->nballs = 0; + + joystick->nbuttons = item->nbuttons; + joystick->naxes = item->naxes; + + return (0); +} + +/* Function to determine if this joystick is attached to the system right now */ +SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) +{ + return joystick->hwdata != NULL; +} + +/* 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) +{ + EmscriptenGamepadEvent gamepadState; + SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; + int i, result, buttonState; + + if (item) { + result = emscripten_get_gamepad_status(item->index, &gamepadState); + if( result == EMSCRIPTEN_RESULT_SUCCESS) { + if(gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) { + for(i = 0; i < item->nbuttons; i++) { + if(item->digitalButton[i] != gamepadState.digitalButton[i]) { + buttonState = gamepadState.digitalButton[i]? SDL_PRESSED: SDL_RELEASED; + SDL_PrivateJoystickButton(item->joystick, i, buttonState); + } + + /* store values to compare them in the next update */ + item->analogButton[i] = gamepadState.analogButton[i]; + item->digitalButton[i] = gamepadState.digitalButton[i]; + } + + for(i = 0; i < item->naxes; i++) { + if(item->axis[i] != gamepadState.axis[i]) { + // do we need to do conversion? + SDL_PrivateJoystickAxis(item->joystick, i, + (Sint16) (32767.*gamepadState.axis[i])); + } + + /* store to compare in next update */ + item->axis[i] = gamepadState.axis[i]; + } + + item->timestamp = gamepadState.timestamp; + } + } + } +} + +/* Function to close a joystick after use */ +void +SDL_SYS_JoystickClose(SDL_Joystick * joystick) +{ +} + +/* Function to perform any system-specific joystick related cleanup */ +void +SDL_SYS_JoystickQuit(void) +{ + SDL_joylist_item *item = NULL; + SDL_joylist_item *next = NULL; + + for (item = SDL_joylist; item; item = next) { + next = item->next; + SDL_free(item->mapping); + SDL_free(item->name); + SDL_free(item); + } + + SDL_joylist = SDL_joylist_tail = NULL; + + 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 device_index) +{ + SDL_JoystickGUID guid; + /* the GUID is just the first 16 chars of the name for now */ + 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 guid; + /* the GUID is just the first 16 chars of the name for now */ + const char *name = joystick->name; + SDL_zero(guid); + SDL_memcpy(&guid, name, SDL_min(sizeof(guid), SDL_strlen(name))); + return guid; +} + +#endif /* SDL_JOYSTICK_EMSCRIPTEN */ diff --git a/src/joystick/emscripten/SDL_sysjoystick_c.h b/src/joystick/emscripten/SDL_sysjoystick_c.h new file mode 100644 index 000000000..4c907a66c --- /dev/null +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + */ + +#include "../../SDL_internal.h" + +#ifdef SDL_JOYSTICK_EMSCRIPTEN +#include "../SDL_sysjoystick.h" + + +#include + +/* A linked list of available joysticks */ +typedef struct SDL_joylist_item +{ + int index; + char *name; + char *mapping; + SDL_JoystickID device_instance; + SDL_Joystick *joystick; + int nbuttons; + int naxes; + double timestamp; + double axis[64]; + double analogButton[64]; + EM_BOOL digitalButton[64]; + + struct SDL_joylist_item *next; +} SDL_joylist_item; + +typedef SDL_joylist_item joystick_hwdata; + +#endif /* SDL_JOYSTICK_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc index 0caea17f6..20630c4e2 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -53,8 +53,7 @@ extern "C" static int SDL_SYS_numjoysticks = 0; /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. + * Joystick 0 should be the system default joystick. * It should return 0, or -1 on an unrecoverable fatal error. */ int SDL_SYS_JoystickInit(void) @@ -107,7 +106,7 @@ extern "C" } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -153,7 +152,7 @@ extern "C" return (0); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; @@ -229,7 +228,6 @@ extern "C" SDL_free(joystick->hwdata->new_hats); SDL_free(joystick->hwdata->new_axes); SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } } diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index a4027599e..d3506b752 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -23,6 +23,7 @@ /* This is the iOS implementation of the SDL joystick API */ #include "SDL_joystick.h" +#include "SDL_hints.h" #include "SDL_stdinc.h" #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" @@ -32,24 +33,30 @@ /* needed for SDL_IPHONE_MAX_GFORCE macro */ #import "SDL_config_iphoneos.h" -const char *accelerometerName = "iOS accelerometer"; +const char *accelerometerName = "iOS Accelerometer"; static CMMotionManager *motionManager = nil; +static int numjoysticks = 0; /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. + * Joystick 0 should be the system default joystick. * It should return 0, or -1 on an unrecoverable fatal error. */ int SDL_SYS_JoystickInit(void) { - return (1); + const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK); + if (!hint || SDL_atoi(hint)) { + /* Default behavior, accelerometer as joystick */ + numjoysticks = 1; + } + + return numjoysticks; } int SDL_SYS_NumJoysticks() { - return 1; + return numjoysticks; } void SDL_SYS_JoystickDetect() @@ -70,7 +77,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -82,18 +89,20 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) joystick->nballs = 0; joystick->nbuttons = 0; - if (motionManager == nil) { - motionManager = [[CMMotionManager alloc] init]; - } + @autoreleasepool { + if (motionManager == nil) { + motionManager = [[CMMotionManager alloc] init]; + } - /* Shorter times between updates can significantly increase CPU usage. */ - motionManager.accelerometerUpdateInterval = 0.1; - [motionManager startAccelerometerUpdates]; + /* Shorter times between updates can significantly increase CPU usage. */ + motionManager.accelerometerUpdateInterval = 0.1; + [motionManager startAccelerometerUpdates]; + } return 0; } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; @@ -105,11 +114,13 @@ static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) const SInt16 maxsint16 = 0x7FFF; CMAcceleration accel; - if (!motionManager.accelerometerActive) { - return; - } + @autoreleasepool { + if (!motionManager.accelerometerActive) { + return; + } - accel = [[motionManager accelerometerData] acceleration]; + accel = motionManager.accelerometerData.acceleration; + } /* Convert accelerometer data from floating point to Sint16, which is what @@ -153,18 +164,20 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - [motionManager stopAccelerometerUpdates]; - joystick->closed = 1; + @autoreleasepool { + [motionManager stopAccelerometerUpdates]; + } } /* Function to perform any system-specific joystick related cleanup */ void SDL_SYS_JoystickQuit(void) { - if (motionManager != nil) { - [motionManager release]; + @autoreleasepool { motionManager = nil; } + + numjoysticks = 0; } SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 05bf086f2..a36593077 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -142,13 +142,15 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui #if SDL_USE_LIBUDEV void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) { - if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { + if (devpath == NULL) { return; } - - switch( udev_type ) - { + + switch (udev_type) { case SDL_UDEV_DEVICEADDED: + if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { + return; + } MaybeAddDevice(devpath); break; @@ -335,13 +337,12 @@ JoystickInitWithoutUdev(void) static int JoystickInitWithUdev(void) { - if (SDL_UDEV_Init() < 0) { return SDL_SetError("Could not initialize UDEV"); } /* Set up the udev callback */ - if ( SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { + if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { SDL_UDEV_Quit(); return SDL_SetError("Could not set up joystick <-> udev callback"); } @@ -565,7 +566,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -620,10 +621,10 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) return (0); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return !joystick->closed && (joystick->hwdata->item != NULL); + return joystick->hwdata->item != NULL; } static SDL_INLINE void @@ -840,9 +841,7 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) SDL_free(joystick->hwdata->balls); SDL_free(joystick->hwdata->fname); SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } - joystick->closed = 1; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/psp/SDL_sysjoystick.c b/src/joystick/psp/SDL_sysjoystick.c index 9a2362e1d..207d4fbf1 100644 --- a/src/joystick/psp/SDL_sysjoystick.c +++ b/src/joystick/psp/SDL_sysjoystick.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_JOYSTICK_PSP /* This is the PSP implementation of the SDL joystick API */ #include @@ -97,16 +100,13 @@ int JoystickUpdate(void *data) /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. + * Joystick 0 should be the system default joystick. * It should return number of joysticks, or -1 on an unrecoverable fatal error. */ int SDL_SYS_JoystickInit(void) { int i; -/* SDL_numjoysticks = 1; */ - /* Setup input */ sceCtrlSetSamplingCycle(0); sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG); @@ -164,7 +164,7 @@ const char *SDL_SYS_JoystickName(int index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -177,17 +177,17 @@ int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index) return 0; } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; } + /* Function to update the state of a joystick - called as a device poll. * This function shouldn't update the joystick structure directly, * but instead should call SDL_PrivateJoystick*() to deliver events * and update joystick device state. */ - void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) { int i; @@ -233,7 +233,6 @@ void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick *joystick) { - /* Do nothing. */ } /* Function to perform any system-specific joystick related cleanup */ @@ -265,5 +264,7 @@ SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) return guid; } +#endif /* SDL_JOYSTICK_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c index 179f99283..3fafdea8e 100644 --- a/src/joystick/windows/SDL_dinputjoystick.c +++ b/src/joystick/windows/SDL_dinputjoystick.c @@ -340,6 +340,11 @@ EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) { JoyStick_DeviceData *pNewJoystick; JoyStick_DeviceData *pPrevJoystick = NULL; + const DWORD devtype = (pdidInstance->dwDevType & 0xFF); + + if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD)) { + return DIENUM_CONTINUE; /* Ignore touchpads, etc. */ + } if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) { return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */ diff --git a/src/joystick/windows/SDL_mmjoystick.c b/src/joystick/windows/SDL_mmjoystick.c index 0f3b6decc..3ed6892d0 100644 --- a/src/joystick/windows/SDL_mmjoystick.c +++ b/src/joystick/windows/SDL_mmjoystick.c @@ -143,8 +143,7 @@ GetJoystickName(int index, const char *szRegKey) static int SDL_SYS_numjoysticks = 0; /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. + * Joystick 0 should be the system default joystick. * It should return 0, or -1 on an unrecoverable fatal error. */ int @@ -211,7 +210,7 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -272,7 +271,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) return (0); } -/* Function to determine is this joystick is attached to the system right now */ +/* Function to determine if this joystick is attached to the system right now */ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { return SDL_TRUE; @@ -384,9 +383,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { - /* free system specific hardware data */ SDL_free(joystick->hwdata); - joystick->hwdata = NULL; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index d649edc15..5682a223f 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -278,8 +278,7 @@ void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device) } /* Function to scan the system for joysticks. - * This function should set SDL_numjoysticks to the number of available - * joysticks. Joystick 0 should be the system default joystick. + * Joystick 0 should be the system default joystick. * It should return 0, or -1 on an unrecoverable fatal error. */ int @@ -447,7 +446,7 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) } /* Function to open a joystick for use. - The joystick to open is specified by the index field of the joystick. + The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ @@ -461,7 +460,6 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) /* allocate memory for system specific hardware data */ joystick->instance_id = joystickdevice->nInstanceID; - joystick->closed = SDL_FALSE; joystick->hwdata = (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata)); if (joystick->hwdata == NULL) { @@ -481,13 +479,13 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick) { - return !joystick->closed && !joystick->hwdata->removed; + return joystick->hwdata && !joystick->hwdata->removed; } void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { - if (joystick->closed || !joystick->hwdata) { + if (!joystick->hwdata || joystick->hwdata->removed) { return; } @@ -498,8 +496,7 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) } if (joystick->hwdata->removed) { - joystick->closed = SDL_TRUE; - joystick->uncentered = SDL_TRUE; + joystick->force_recentering = SDL_TRUE; } } @@ -513,10 +510,7 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) SDL_DINPUT_JoystickClose(joystick); } - /* free system specific hardware data */ SDL_free(joystick->hwdata); - - joystick->closed = SDL_TRUE; } /* Function to perform any system-specific joystick related cleanup */ diff --git a/src/main/haiku/SDL_BApp.h b/src/main/haiku/SDL_BApp.h index 1e4a0f550..9eece5440 100644 --- a/src/main/haiku/SDL_BApp.h +++ b/src/main/haiku/SDL_BApp.h @@ -254,7 +254,7 @@ private: return; } win = GetSDLWindow(winID); - SDL_SendMouseWheel(win, 0, xTicks, yTicks); + SDL_SendMouseWheel(win, 0, xTicks, yTicks, SDL_MOUSEWHEEL_NORMAL); } void _HandleKey(BMessage *msg) { diff --git a/src/main/psp/SDL_psp_main.c b/src/main/psp/SDL_psp_main.c index d79135dbc..2ca8e446b 100644 --- a/src/main/psp/SDL_psp_main.c +++ b/src/main/psp/SDL_psp_main.c @@ -1,6 +1,9 @@ /* SDL_psp_main.c, placed in the public domain by Sam Lantinga 3/13/14 */ +#include "SDL_config.h" + +#ifdef __PSP__ #include "SDL_main.h" #include @@ -61,3 +64,7 @@ int main(int argc, char *argv[]) (void)SDL_main(argc, argv); return 0; } + +#endif /* __PSP__ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/main/windows/SDL_windows_main.c b/src/main/windows/SDL_windows_main.c index 7886fe3a8..e6378081f 100644 --- a/src/main/windows/SDL_windows_main.c +++ b/src/main/windows/SDL_windows_main.c @@ -109,13 +109,16 @@ OutOfMemory(void) } #if defined(_MSC_VER) -/* The VC++ compiler needs main defined */ -#define console_main main +/* The VC++ compiler needs main/wmain defined */ +# define console_ansi_main main +# if UNICODE +# define console_wmain wmain +# endif #endif -/* This is where execution begins [console apps] */ -int -console_main(int argc, char *argv[]) +/* WinMain, main, and wmain eventually call into here. */ +static int +main_utf8(int argc, char *argv[]) { SDL_SetMainReady(); @@ -123,6 +126,37 @@ console_main(int argc, char *argv[]) return SDL_main(argc, argv); } +/* This is where execution begins [console apps, ansi] */ +int +console_ansi_main(int argc, char *argv[]) +{ + /* !!! FIXME: are these in the system codepage? We need to convert to UTF-8. */ + return main_utf8(argc, argv); +} + + +#if UNICODE +/* This is where execution begins [console apps, unicode] */ +int +console_wmain(int argc, wchar_t *wargv[], wchar_t *wenvp) +{ + int retval = 0; + char **argv = SDL_stack_alloc(char*, argc); + int i; + + for (i = 0; i < argc; ++i) { + argv[i] = WIN_StringToUTF8(wargv[i]); + } + + retval = main_utf8(argc, argv); + + /* !!! FIXME: we are leaking all the elements of argv we allocated. */ + SDL_stack_free(argv); + + return retval; +} +#endif + /* This is where execution begins [windowed apps] */ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) @@ -136,6 +170,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) #if UNICODE cmdline = WIN_StringToUTF8(text); #else + /* !!! FIXME: are these in the system codepage? We need to convert to UTF-8. */ cmdline = SDL_strdup(text); #endif if (cmdline == NULL) { @@ -151,7 +186,7 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) ParseCommandLine(cmdline, argv); /* Run the main program */ - console_main(argc, argv); + main_utf8(argc, argv); SDL_stack_free(argv); diff --git a/src/power/SDL_power.c b/src/power/SDL_power.c index cc9ba396d..64425312c 100644 --- a/src/power/SDL_power.c +++ b/src/power/SDL_power.c @@ -38,6 +38,7 @@ SDL_bool SDL_GetPowerInfo_UIKit(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_WinRT(SDL_PowerState *, int *, int *); +SDL_bool SDL_GetPowerInfo_Emscripten(SDL_PowerState *, int *, int *); #ifndef SDL_POWER_DISABLED #ifdef SDL_POWER_HARDWIRED @@ -81,6 +82,9 @@ static SDL_GetPowerInfo_Impl implementations[] = { #ifdef SDL_POWER_WINRT /* handles WinRT */ SDL_GetPowerInfo_WinRT, #endif +#ifdef SDL_POWER_EMSCRIPTEN /* handles Emscripten */ + SDL_GetPowerInfo_Emscripten, +#endif #ifdef SDL_POWER_HARDWIRED SDL_GetPowerInfo_Hardwired, diff --git a/src/power/emscripten/SDL_syspower.c b/src/power/emscripten/SDL_syspower.c new file mode 100644 index 000000000..756773310 --- /dev/null +++ b/src/power/emscripten/SDL_syspower.c @@ -0,0 +1,62 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef SDL_POWER_DISABLED +#if SDL_POWER_EMSCRIPTEN + +#include + +#include "SDL_power.h" + +SDL_bool +SDL_GetPowerInfo_Emscripten(SDL_PowerState *state, int *seconds, int *percent) +{ + EmscriptenBatteryEvent batteryState; + int haveBattery = 0; + + if (emscripten_get_battery_status(&batteryState) == EMSCRIPTEN_RESULT_NOT_SUPPORTED) + return SDL_FALSE; + + haveBattery = batteryState.level != 1.0 || !batteryState.charging || batteryState.chargingTime != 0.0; + + if (!haveBattery) { + *state = SDL_POWERSTATE_NO_BATTERY; + *seconds = -1; + *percent = -1; + return SDL_TRUE; + } + + if (batteryState.charging) + *state = batteryState.chargingTime == 0.0 ? SDL_POWERSTATE_CHARGED : SDL_POWERSTATE_CHARGING; + else + *state = SDL_POWERSTATE_ON_BATTERY; + + *seconds = batteryState.dischargingTime; + *percent = batteryState.level * 100; + + return SDL_TRUE; +} + +#endif /* SDL_POWER_EMSCRIPTEN */ +#endif /* SDL_POWER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/power/uikit/SDL_syspower.m b/src/power/uikit/SDL_syspower.m index 60c42745a..4984b78c4 100644 --- a/src/power/uikit/SDL_syspower.m +++ b/src/power/uikit/SDL_syspower.m @@ -50,24 +50,24 @@ SDL_UIKit_UpdateBatteryMonitoring(void) SDL_bool SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent) { - UIDevice *uidev = [UIDevice currentDevice]; + @autoreleasepool { + UIDevice *uidev = [UIDevice currentDevice]; - if (!SDL_UIKitLastPowerInfoQuery) { - SDL_assert([uidev isBatteryMonitoringEnabled] == NO); - [uidev setBatteryMonitoringEnabled:YES]; - } + if (!SDL_UIKitLastPowerInfoQuery) { + SDL_assert(uidev.isBatteryMonitoringEnabled == NO); + uidev.batteryMonitoringEnabled = YES; + } - /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery - * monitoring if the app hasn't queried it in the last X seconds. - * Apparently monitoring the battery burns battery life. :) - * Apple's docs say not to monitor the battery unless you need it. - */ - SDL_UIKitLastPowerInfoQuery = SDL_GetTicks(); + /* UIKit_GL_SwapWindow() (etc) will check this and disable the battery + * monitoring if the app hasn't queried it in the last X seconds. + * Apparently monitoring the battery burns battery life. :) + * Apple's docs say not to monitor the battery unless you need it. + */ + SDL_UIKitLastPowerInfoQuery = SDL_GetTicks(); - *seconds = -1; /* no API to estimate this in UIKit. */ + *seconds = -1; /* no API to estimate this in UIKit. */ - switch ([uidev batteryState]) - { + switch (uidev.batteryState) { case UIDeviceBatteryStateCharging: *state = SDL_POWERSTATE_CHARGING; break; @@ -84,11 +84,12 @@ SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent) default: *state = SDL_POWERSTATE_UNKNOWN; break; - } + } - const float level = [uidev batteryLevel]; - *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) ); - return SDL_TRUE; /* always the definitive answer on iOS. */ + const float level = uidev.batteryLevel; + *percent = ( (level < 0.0f) ? -1 : ((int) ((level * 100) + 0.5f)) ); + return SDL_TRUE; /* always the definitive answer on iOS. */ + } } #endif /* SDL_POWER_UIKIT */ diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index f99fdb1d5..3cc212831 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -829,9 +829,24 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); renderer->driverdata = data; +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1. + * Failure to use it seems to either result in: + * + * - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned + * off (framerate doesn't get capped), but nothing appears on-screen + * + * - with the D3D11 debug runtime turned ON, vsync gets automatically + * turned back on, and the following gets output to the debug console: + * + * DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ] + */ + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; +#else if ((flags & SDL_RENDERER_PRESENTVSYNC)) { renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; } +#endif /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in * order to give init functions access to the underlying window handle: @@ -2901,7 +2916,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, */ char errorMessage[1024]; SDL_snprintf(errorMessage, sizeof(errorMessage), __FUNCTION__ ", Convert Pixels failed: %s", SDL_GetError()); - SDL_SetError(errorMessage); + SDL_SetError("%s", errorMessage); goto done; } diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index ecd0d531f..0c930f35d 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -342,9 +342,11 @@ GL_HandleDebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GL if (type == GL_DEBUG_TYPE_ERROR_ARB) { /* Record this error */ - ++data->errors; - data->error_messages = SDL_realloc(data->error_messages, data->errors * sizeof(*data->error_messages)); - if (data->error_messages) { + int errors = data->errors + 1; + char **error_messages = SDL_realloc(data->error_messages, errors * sizeof(*data->error_messages)); + if (error_messages) { + data->errors = errors; + data->error_messages = error_messages; data->error_messages[data->errors-1] = SDL_strdup(message); } } diff --git a/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 72cce305a..617bf659f 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -55,6 +55,7 @@ static const float inv255f = 1.0f / 255.0f; static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags); static void GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event); +static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h); static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, @@ -321,6 +322,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags) } renderer->WindowEvent = GLES_WindowEvent; + renderer->GetOutputSize = GLES_GetOutputSize; renderer->CreateTexture = GLES_CreateTexture; renderer->UpdateTexture = GLES_UpdateTexture; renderer->LockTexture = GLES_LockTexture; @@ -438,6 +440,13 @@ GLES_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } +static int +GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) +{ + SDL_GL_GetDrawableSize(renderer->window, w, h); + return 0; +} + static SDL_INLINE int power_of_2(int input) { diff --git a/src/render/opengles2/SDL_gles2funcs.h b/src/render/opengles2/SDL_gles2funcs.h index 2c02cdd13..105da61e7 100644 --- a/src/render/opengles2/SDL_gles2funcs.h +++ b/src/render/opengles2/SDL_gles2funcs.h @@ -69,3 +69,7 @@ SDL_PROC(GLenum, glCheckFramebufferStatus, (GLenum)) SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *)) SDL_PROC(GLint, glGetAttribLocation, (GLuint, const GLchar *)) SDL_PROC(void, glGetProgramInfoLog, (GLuint, GLsizei, GLsizei*, GLchar*)) +SDL_PROC(void, glGenBuffers, (GLsizei, GLuint *)) +SDL_PROC(void, glBindBuffer, (GLenum, GLuint)) +SDL_PROC(void, glBufferData, (GLenum, GLsizeiptr, const GLvoid *, GLenum)) +SDL_PROC(void, glBufferSubData, (GLenum, GLintptr, GLsizeiptr, const GLvoid *)) diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index fd7f1b379..05ef00af9 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -28,7 +28,20 @@ #include "../../video/SDL_blit.h" #include "SDL_shaders_gles2.h" -/* To prevent unnecessary window recreation, +/* !!! FIXME: Emscripten makes these into WebGL calls, and WebGL doesn't offer + !!! FIXME: client-side arrays (without an Emscripten compatibility hack, + !!! FIXME: at least), but the current VBO code here is dramatically + !!! FIXME: slower on actual iOS devices, even though the iOS Simulator + !!! FIXME: is okay. Some time after 2.0.4 ships, we should revisit this, + !!! FIXME: fix the performance bottleneck, and make everything use VBOs. +*/ +#ifdef __EMSCRIPTEN__ +#define SDL_GLES2_USE_VBOS 1 +#else +#define SDL_GLES2_USE_VBOS 0 +#endif + +/* To prevent unnecessary window recreation, * these should match the defaults selected in SDL_GL_ResetAttributes */ #define RENDERER_CONTEXT_MAJOR 2 @@ -180,6 +193,11 @@ typedef struct GLES2_DriverContext GLES2_ProgramCache program_cache; GLES2_ProgramCacheEntry *current_program; Uint8 clear_r, clear_g, clear_b, clear_a; + +#if SDL_GLES2_USE_VBOS + GLuint vertex_buffers[4]; + GLsizeiptr vertex_buffer_size[4]; +#endif } GLES2_DriverContext; #define GLES2_MAX_CACHED_PROGRAMS 8 @@ -351,6 +369,13 @@ GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } +static int +GLES2_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) +{ + SDL_GL_GetDrawableSize(renderer->window, w, h); + return 0; +} + static int GLES2_UpdateViewport(SDL_Renderer * renderer) { @@ -1385,6 +1410,33 @@ GLES2_SetDrawingState(SDL_Renderer * renderer) return 0; } +static int +GLES2_UpdateVertexBuffer(SDL_Renderer *renderer, GLES2_Attribute attr, + const void *vertexData, size_t dataSizeInBytes) +{ + GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; + +#if !SDL_GLES2_USE_VBOS + data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, vertexData); +#else + if (!data->vertex_buffers[attr]) + data->glGenBuffers(1, &data->vertex_buffers[attr]); + + data->glBindBuffer(GL_ARRAY_BUFFER, data->vertex_buffers[attr]); + + if (data->vertex_buffer_size[attr] < dataSizeInBytes) { + data->glBufferData(GL_ARRAY_BUFFER, dataSizeInBytes, vertexData, GL_STREAM_DRAW); + data->vertex_buffer_size[attr] = dataSizeInBytes; + } else { + data->glBufferSubData(GL_ARRAY_BUFFER, 0, dataSizeInBytes, vertexData); + } + + data->glVertexAttribPointer(attr, attr == GLES2_ATTRIBUTE_ANGLE ? 1 : 2, GL_FLOAT, GL_FALSE, 0, 0); +#endif + + return 0; +} + static int GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count) { @@ -1405,7 +1457,8 @@ GLES2_RenderDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int cou vertices[idx * 2] = x; vertices[(idx * 2) + 1] = y; } - data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat)); data->glDrawArrays(GL_POINTS, 0, count); SDL_stack_free(vertices); return 0; @@ -1431,7 +1484,8 @@ GLES2_RenderDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, int coun vertices[idx * 2] = x; vertices[(idx * 2) + 1] = y; } - data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, count * 2 * sizeof(GLfloat)); data->glDrawArrays(GL_LINE_STRIP, 0, count); /* We need to close the endpoint of the line */ @@ -1472,7 +1526,8 @@ GLES2_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count) vertices[5] = yMax; vertices[6] = xMax; vertices[7] = yMax; - data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat)); data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } return GL_CheckError("", renderer); @@ -1668,7 +1723,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s vertices[5] = (dstrect->y + dstrect->h); vertices[6] = (dstrect->x + dstrect->w); vertices[7] = (dstrect->y + dstrect->h); - data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat)); texCoords[0] = srcrect->x / (GLfloat)texture->w; texCoords[1] = srcrect->y / (GLfloat)texture->h; texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; @@ -1677,7 +1733,8 @@ GLES2_RenderCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *s texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; - data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat)); data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); return GL_CheckError("", renderer); @@ -1727,9 +1784,13 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect vertices[5] = vertices[7] = tmp; } - data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_ANGLE, 1, GL_FLOAT, GL_FALSE, 0, &fAngle); data->glVertexAttribPointer(GLES2_ATTRIBUTE_CENTER, 2, GL_FLOAT, GL_FALSE, 0, translate); - data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices); + data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);*/ + + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_ANGLE, fAngle, 4 * sizeof(GLfloat)); + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_CENTER, translate, 8 * sizeof(GLfloat)); + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_POSITION, vertices, 8 * sizeof(GLfloat)); texCoords[0] = srcrect->x / (GLfloat)texture->w; texCoords[1] = srcrect->y / (GLfloat)texture->h; @@ -1739,7 +1800,8 @@ GLES2_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect texCoords[5] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; texCoords[6] = (srcrect->x + srcrect->w) / (GLfloat)texture->w; texCoords[7] = (srcrect->y + srcrect->h) / (GLfloat)texture->h; - data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords); + /*data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);*/ + GLES2_UpdateVertexBuffer(renderer, GLES2_ATTRIBUTE_TEXCOORD, texCoords, 8 * sizeof(GLfloat)); data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_CENTER); data->glDisableVertexAttribArray(GLES2_ATTRIBUTE_ANGLE); @@ -2004,6 +2066,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) /* Populate the function pointers for the module */ renderer->WindowEvent = &GLES2_WindowEvent; + renderer->GetOutputSize = &GLES2_GetOutputSize; renderer->CreateTexture = &GLES2_CreateTexture; renderer->UpdateTexture = &GLES2_UpdateTexture; renderer->UpdateTextureYUV = &GLES2_UpdateTextureYUV; diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index cdd13e822..8d956ca5d 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -459,7 +459,7 @@ static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { /* PSP_RenderData *renderdata = (PSP_RenderData *) renderer->driverdata; */ - PSP_TextureData* psp_texture = (PSP_TextureData*) SDL_calloc(1, sizeof(*psp_texture));; + PSP_TextureData* psp_texture = (PSP_TextureData*) SDL_calloc(1, sizeof(*psp_texture)); if(!psp_texture) return -1; diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index 782b8ccb0..a2905c45f 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -18,6 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" #if defined(__WIN32__) diff --git a/src/stdlib/SDL_iconv.c b/src/stdlib/SDL_iconv.c index 5b9c20233..fdb5e2610 100644 --- a/src/stdlib/SDL_iconv.c +++ b/src/stdlib/SDL_iconv.c @@ -18,6 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" /* This file contains portable iconv functions for SDL */ diff --git a/src/stdlib/SDL_malloc.c b/src/stdlib/SDL_malloc.c index 024562240..71f5f6966 100644 --- a/src/stdlib/SDL_malloc.c +++ b/src/stdlib/SDL_malloc.c @@ -18,6 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" /* This file contains portable memory management functions for SDL */ diff --git a/src/stdlib/SDL_qsort.c b/src/stdlib/SDL_qsort.c index 8329a35e3..0d1978424 100644 --- a/src/stdlib/SDL_qsort.c +++ b/src/stdlib/SDL_qsort.c @@ -41,6 +41,11 @@ * * Gareth McCaughan Peterhouse Cambridge 1998 */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" /* diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index b1de63d2a..c2c14212c 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -18,6 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" /* This file contains portable stdlib functions for SDL */ diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c index 84285865d..ce8b2fd26 100644 --- a/src/stdlib/SDL_string.c +++ b/src/stdlib/SDL_string.c @@ -18,6 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) +#define SDL_DISABLE_ANALYZE_MACROS 1 +#endif + #include "../SDL_internal.h" /* This file contains portable string manipulation functions for SDL */ diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index d05dda47b..9b1d2914c 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1105,8 +1105,8 @@ SDLTest_PrintEvent(SDL_Event * event) event->button.windowID); break; case SDL_MOUSEWHEEL: - SDL_Log("SDL EVENT: Mouse: wheel scrolled %d in x and %d in y in window %d", - event->wheel.x, event->wheel.y, event->wheel.windowID); + SDL_Log("SDL EVENT: Mouse: wheel scrolled %d in x and %d in y (reversed: %d) in window %d", + event->wheel.x, event->wheel.y, event->wheel.direction, event->wheel.windowID); break; case SDL_JOYDEVICEADDED: SDL_Log("SDL EVENT: Joystick index %d attached", @@ -1203,6 +1203,15 @@ SDLTest_PrintEvent(SDL_Event * event) event->tfinger.x, event->tfinger.y, event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure); break; + case SDL_DOLLARGESTURE: + 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, (Sint64) event->dgesture.gestureId); + break; + case SDL_MULTIGESTURE: + SDL_Log("SDL_EVENT: Multi gesture fingers: %d", event->mgesture.numFingers); + break; case SDL_RENDER_DEVICE_RESET: SDL_Log("SDL EVENT: render device reset"); @@ -1218,7 +1227,7 @@ SDLTest_PrintEvent(SDL_Event * event) SDL_Log("SDL EVENT: User event %d", event->user.code); break; default: - SDL_Log("Unknown event %d", event->type); + SDL_Log("Unknown event %04x", event->type); break; } } diff --git a/src/thread/psp/SDL_syscond.c b/src/thread/psp/SDL_syscond.c index 1abd9a3d9..3959a4c43 100644 --- a/src/thread/psp/SDL_syscond.c +++ b/src/thread/psp/SDL_syscond.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_THREAD_PSP + /* An implementation of condition variables using semaphores and mutexes */ /* This implementation borrows heavily from the BeOS condition variable @@ -217,4 +219,6 @@ SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT); } +#endif /* SDL_THREAD_PSP */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/psp/SDL_sysmutex.c b/src/thread/psp/SDL_sysmutex.c index 478575b32..e1cf413c3 100644 --- a/src/thread/psp/SDL_sysmutex.c +++ b/src/thread/psp/SDL_sysmutex.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_THREAD_PSP + /* An implementation of mutexes using semaphores */ #include "SDL_thread.h" @@ -129,4 +131,6 @@ SDL_mutexV(SDL_mutex * mutex) #endif /* SDL_THREADS_DISABLED */ } +#endif /* SDL_THREAD_PSP */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/psp/SDL_syssem.c b/src/thread/psp/SDL_syssem.c index 27d3251a2..609ba7375 100644 --- a/src/thread/psp/SDL_syssem.c +++ b/src/thread/psp/SDL_syssem.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_THREAD_PSP /* Semaphore functions for the PSP. */ @@ -152,5 +155,7 @@ int SDL_SemPost(SDL_sem *sem) return 0; } +#endif /* SDL_THREAD_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/thread/psp/SDL_systhread.c b/src/thread/psp/SDL_systhread.c index d2fbeeb2f..8cbd2f132 100644 --- a/src/thread/psp/SDL_systhread.c +++ b/src/thread/psp/SDL_systhread.c @@ -18,7 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" +#if SDL_THREAD_PSP /* PSP thread management routines for SDL */ @@ -104,5 +106,7 @@ int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) } +#endif /* SDL_THREAD_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/timer/psp/SDL_systimer.c b/src/timer/psp/SDL_systimer.c index b706f4495..8488b284d 100644 --- a/src/timer/psp/SDL_systimer.c +++ b/src/timer/psp/SDL_systimer.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#ifdef SDL_TIMERS_PSP #include "SDL_thread.h" #include "SDL_timer.h" @@ -82,5 +85,7 @@ void SDL_Delay(Uint32 ms) sceKernelDelayThreadCB(ms * 1000); } +#endif /* SDL_TIMERS_PSP */ + /* vim: ts=4 sw=4 */ diff --git a/src/video/SDL_bmp.c b/src/video/SDL_bmp.c index fcc48c6d5..3e6f5c938 100644 --- a/src/video/SDL_bmp.c +++ b/src/video/SDL_bmp.c @@ -306,16 +306,19 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) biClrUsed = 1 << biBitCount; } if ((int) biClrUsed > palette->ncolors) { - palette->ncolors = biClrUsed; - palette->colors = + SDL_Color *colors; + int ncolors = biClrUsed; + colors = (SDL_Color *) SDL_realloc(palette->colors, - palette->ncolors * + ncolors * sizeof(*palette->colors)); - if (!palette->colors) { + if (!colors) { SDL_OutOfMemory(); was_error = SDL_TRUE; goto done; } + palette->ncolors = ncolors; + palette->colors = colors; } else if ((int) biClrUsed < palette->ncolors) { palette->ncolors = biClrUsed; } @@ -528,6 +531,10 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) format.BitsPerPixel); } } + } else { + /* Set no error here because it may overwrite a more useful message from + SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */ + return -1; } if (surface && (SDL_LockSurface(surface) == 0)) { diff --git a/src/video/SDL_clipboard.c b/src/video/SDL_clipboard.c index a3b38e045..f2b450152 100644 --- a/src/video/SDL_clipboard.c +++ b/src/video/SDL_clipboard.c @@ -29,6 +29,10 @@ SDL_SetClipboardText(const char *text) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + return SDL_SetError("Video subsystem must be initialized to set clipboard text"); + } + if (!text) { text = ""; } @@ -46,6 +50,11 @@ SDL_GetClipboardText(void) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + SDL_SetError("Video subsystem must be initialized to get clipboard text"); + return SDL_strdup(""); + } + if (_this->GetClipboardText) { return _this->GetClipboardText(_this); } else { @@ -62,6 +71,11 @@ SDL_HasClipboardText(void) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (!_this) { + SDL_SetError("Video subsystem must be initialized to check clipboard text"); + return SDL_FALSE; + } + if (_this->HasClipboardText) { return _this->HasClipboardText(_this); } else { diff --git a/src/video/SDL_fillrect.c b/src/video/SDL_fillrect.c index 5f343eaf2..84707842e 100644 --- a/src/video/SDL_fillrect.c +++ b/src/video/SDL_fillrect.c @@ -251,6 +251,10 @@ SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color) rect = &clipped; } else { rect = &dst->clip_rect; + /* Don't attempt to fill if the surface's clip_rect is empty */ + if (SDL_RectEmpty(rect)) { + return 0; + } } /* Perform software fill */ diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index fcd78870e..abcdee8d0 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -741,15 +741,15 @@ SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect, dst_y0 += dst->clip_rect.y; dst_y1 += dst->clip_rect.y; - final_src.x = SDL_floor(src_x0 + 0.5); - final_src.y = SDL_floor(src_y0 + 0.5); - final_src.w = SDL_floor(src_x1 - src_x0 + 1.5); - final_src.h = SDL_floor(src_y1 - src_y0 + 1.5); + final_src.x = (int)SDL_floor(src_x0 + 0.5); + final_src.y = (int)SDL_floor(src_y0 + 0.5); + final_src.w = (int)SDL_floor(src_x1 - src_x0 + 1.5); + final_src.h = (int)SDL_floor(src_y1 - src_y0 + 1.5); - final_dst.x = SDL_floor(dst_x0 + 0.5); - final_dst.y = SDL_floor(dst_y0 + 0.5); - final_dst.w = SDL_floor(dst_x1 - dst_x0 + 1.5); - final_dst.h = SDL_floor(dst_y1 - dst_y0 + 1.5); + final_dst.x = (int)SDL_floor(dst_x0 + 0.5); + final_dst.y = (int)SDL_floor(dst_y0 + 0.5); + final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5); + final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5); if (final_dst.w < 0) final_dst.w = 0; diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index cdb21b5e4..9b2f7d170 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -274,6 +274,7 @@ struct SDL_VideoDevice int num_displays; SDL_VideoDisplay *displays; SDL_Window *windows; + SDL_Window *grabbed_window; Uint8 window_magic; Uint32 next_object_id; char * clipboard_text; @@ -303,6 +304,7 @@ struct SDL_VideoDevice int flags; int profile_mask; int share_with_current_context; + int release_behavior; int framebuffer_srgb_capable; int retained_backing; int driver_loaded; @@ -394,6 +396,9 @@ extern VideoBootStrap NACL_bootstrap; #if SDL_VIDEO_DRIVER_VIVANTE extern VideoBootStrap VIVANTE_bootstrap; #endif +#if SDL_VIDEO_DRIVER_EMSCRIPTEN +extern VideoBootStrap Emscripten_bootstrap; +#endif extern SDL_VideoDevice *SDL_GetVideoDevice(void); extern int SDL_AddBasicVideoDisplay(const SDL_DisplayMode * desktop_mode); diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 43d674fe0..cab98d9de 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -46,6 +46,10 @@ #include "SDL_opengles2.h" #endif /* SDL_VIDEO_OPENGL_ES2 && !SDL_VIDEO_OPENGL */ +#ifndef GL_CONTEXT_RELEASE_BEHAVIOR_KHR +#define GL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x82FB +#endif + /* On Windows, windows.h defines CreateWindow */ #ifdef CreateWindow #undef CreateWindow @@ -98,6 +102,9 @@ static VideoBootStrap *bootstrap[] = { #if SDL_VIDEO_DRIVER_NACL &NACL_bootstrap, #endif +#if SDL_VIDEO_DRIVER_EMSCRIPTEN + &Emscripten_bootstrap, +#endif #if SDL_VIDEO_DRIVER_DUMMY &DUMMY_bootstrap, #endif @@ -1100,22 +1107,22 @@ SDL_RestoreMousePosition(SDL_Window *window) } } -static void +static int SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) { SDL_VideoDisplay *display; SDL_Window *other; - CHECK_WINDOW_MAGIC(window,); + CHECK_WINDOW_MAGIC(window,-1); /* if we are in the process of hiding don't go back to fullscreen */ if ( window->is_hiding && fullscreen ) - return; + return 0; #ifdef __MACOSX__ if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) { window->last_fullscreen_flags = window->flags; - return; + return 0; } #endif @@ -1132,7 +1139,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) /* See if anything needs to be done now */ if ((display->fullscreen_window == window) == fullscreen) { if ((window->last_fullscreen_flags & FULLSCREEN_MASK) == (window->flags & FULLSCREEN_MASK)) { - return; + return 0; } } @@ -1161,9 +1168,13 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) /* only do the mode change if we want exclusive fullscreen */ if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { - SDL_SetDisplayModeForDisplay(display, &fullscreen_mode); + if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { + return -1; + } } else { - SDL_SetDisplayModeForDisplay(display, NULL); + if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { + return -1; + } } if (_this->SetWindowFullscreen) { @@ -1182,7 +1193,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) SDL_RestoreMousePosition(other); window->last_fullscreen_flags = window->flags; - return; + return 0; } } } @@ -1202,6 +1213,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) SDL_RestoreMousePosition(window); window->last_fullscreen_flags = window->flags; + return 0; } #define CREATE_FLAGS \ @@ -1253,6 +1265,12 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) h = 1; } + /* Some platforms blow up if the windows are too large. Raise it later? */ + if ((w > 16384) || (h > 16384)) { + SDL_SetError("Window is too large."); + return NULL; + } + /* Some platforms have OpenGL enabled by default */ #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__ flags |= SDL_WINDOW_OPENGL; @@ -1489,11 +1507,8 @@ SDL_SetWindowTitle(SDL_Window * window, const char *title) return; } SDL_free(window->title); - if (title && *title) { - window->title = SDL_strdup(title); - } else { - window->title = NULL; - } + + window->title = SDL_strdup(title ? title : ""); if (_this->SetWindowTitle) { _this->SetWindowTitle(_this, window); @@ -1604,13 +1619,14 @@ SDL_SetWindowPosition(SDL_Window * window, int x, int y) CHECK_WINDOW_MAGIC(window,); if (SDL_WINDOWPOS_ISCENTERED(x) || SDL_WINDOWPOS_ISCENTERED(y)) { - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - int displayIndex; + int displayIndex = (x & 0xFFFF); SDL_Rect bounds; + if (displayIndex > _this->num_displays) { + displayIndex = 0; + } SDL_zero(bounds); - displayIndex = SDL_GetIndexOfDisplay(display); SDL_GetDisplayBounds(displayIndex, &bounds); if (SDL_WINDOWPOS_ISCENTERED(x)) { x = bounds.x + (bounds.w - window->w) / 2; @@ -1927,9 +1943,7 @@ SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags) window->flags &= ~FULLSCREEN_MASK; window->flags |= flags; - SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); - - return 0; + return SDL_UpdateFullscreenMode(window, FULLSCREEN_VISIBLE(window)); } static SDL_Surface * @@ -2041,6 +2055,7 @@ SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red, if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) { return -1; } + SDL_assert(window->gamma != NULL); } if (red) { @@ -2108,6 +2123,7 @@ void SDL_UpdateWindowGrab(SDL_Window * window) { if (_this->SetWindowGrab) { + SDL_Window *grabbed_window; SDL_bool grabbed; if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { @@ -2115,6 +2131,19 @@ SDL_UpdateWindowGrab(SDL_Window * window) } else { grabbed = SDL_FALSE; } + + grabbed_window = _this->grabbed_window; + if (grabbed) { + if (grabbed_window && (grabbed_window != window)) { + /* stealing a grab from another window! */ + grabbed_window->flags &= ~SDL_WINDOW_INPUT_GRABBED; + _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE); + } + _this->grabbed_window = window; + } else if (grabbed_window == window) { + _this->grabbed_window = NULL; /* ungrabbing. */ + } + _this->SetWindowGrab(_this, window, grabbed); } } @@ -2139,8 +2168,15 @@ SDL_bool SDL_GetWindowGrab(SDL_Window * window) { CHECK_WINDOW_MAGIC(window, SDL_FALSE); + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return window == _this->grabbed_window; +} - return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0); +SDL_Window * +SDL_GetGrabbedWindow(void) +{ + SDL_assert(!_this->grabbed_window || ((_this->grabbed_window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)); + return _this->grabbed_window; } void @@ -2633,6 +2669,7 @@ SDL_GL_ResetAttributes() #endif _this->gl_config.flags = 0; _this->gl_config.framebuffer_srgb_capable = 0; + _this->gl_config.release_behavior = SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH; _this->gl_config.share_with_current_context = 0; } @@ -2739,6 +2776,9 @@ SDL_GL_SetAttribute(SDL_GLattr attr, int value) case SDL_GL_FRAMEBUFFER_SRGB_CAPABLE: _this->gl_config.framebuffer_srgb_capable = value; break; + case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: + _this->gl_config.release_behavior = value; + break; default: retval = SDL_SetError("Unknown OpenGL attribute"); break; @@ -2839,6 +2879,13 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) attrib = GL_SAMPLES_ARB; #else attrib = GL_SAMPLES; +#endif + break; + case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: +#if SDL_VIDEO_OPENGL + attrib = GL_CONTEXT_RELEASE_BEHAVIOR; +#else + attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR; #endif break; case SDL_GL_BUFFER_SIZE: diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 2662d1b3d..ef7d55648 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -32,8 +32,14 @@ void android_egl_context_backup(); void android_egl_context_restore(); + +#if SDL_AUDIO_DRIVER_ANDROID void AndroidAUD_ResumeDevices(void); void AndroidAUD_PauseDevices(void); +#else +static void AndroidAUD_ResumeDevices(void) {} +static void AndroidAUD_PauseDevices(void) {} +#endif void android_egl_context_restore() diff --git a/src/video/android/SDL_androidmessagebox.c b/src/video/android/SDL_androidmessagebox.c index a55afb376..11f856999 100644 --- a/src/video/android/SDL_androidmessagebox.c +++ b/src/video/android/SDL_androidmessagebox.c @@ -18,7 +18,7 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "SDL_config.h" +#include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_ANDROID diff --git a/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c new file mode 100644 index 000000000..af828af1f --- /dev/null +++ b/src/video/android/SDL_androidmouse.c @@ -0,0 +1,84 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_ANDROID + +#include "SDL_androidmouse.h" + +#include "SDL_events.h" +#include "../../events/SDL_mouse_c.h" + +#include "../../core/android/SDL_android.h" + +#define ACTION_DOWN 0 +#define ACTION_UP 1 +#define ACTION_HOVER_MOVE 7 +#define ACTION_SCROLL 8 +#define BUTTON_PRIMARY 1 +#define BUTTON_SECONDARY 2 +#define BUTTON_TERTIARY 4 + +void Android_OnMouse( int androidButton, int action, float x, float y) { + static Uint8 SDLButton; + + if (!Android_Window) { + return; + } + + switch(action) { + case ACTION_DOWN: + // Determine which button originated the event, and store it for ACTION_UP + SDLButton = SDL_BUTTON_LEFT; + if (androidButton == BUTTON_SECONDARY) { + SDLButton = SDL_BUTTON_RIGHT; + } else if (androidButton == BUTTON_TERTIARY) { + SDLButton = SDL_BUTTON_MIDDLE; + } + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_PRESSED, SDLButton); + break; + + case ACTION_UP: + // Android won't give us the button that originated the ACTION_DOWN event, so we'll + // assume it's the one we stored + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + SDL_SendMouseButton(Android_Window, 0, SDL_RELEASED, SDLButton); + break; + + case ACTION_HOVER_MOVE: + SDL_SendMouseMotion(Android_Window, 0, 0, x, y); + break; + + case ACTION_SCROLL: + SDL_SendMouseWheel(Android_Window, 0, x, y, SDL_MOUSEWHEEL_NORMAL); + break; + + default: + break; + } +} + +#endif /* SDL_VIDEO_DRIVER_ANDROID */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/android/SDL_androidmouse.h b/src/video/android/SDL_androidmouse.h new file mode 100644 index 000000000..ebc6a7a1c --- /dev/null +++ b/src/video/android/SDL_androidmouse.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef _SDL_androidmouse_h +#define _SDL_androidmouse_h + +#include "SDL_androidvideo.h" + +extern void Android_OnMouse( int button, int action, float x, float y); + +#endif /* _SDL_androidmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidtouch.c b/src/video/android/SDL_androidtouch.c index 5f33429b5..5bb17c8c0 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -24,13 +24,12 @@ #include +#include "SDL_hints.h" #include "SDL_events.h" +#include "SDL_log.h" +#include "SDL_androidtouch.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" -#include "SDL_log.h" - -#include "SDL_androidtouch.h" - #include "../../core/android/SDL_android.h" #define ACTION_DOWN 0 @@ -51,11 +50,29 @@ static void Android_GetWindowCoordinates(float x, float y, *window_y = (int)(y * window_h); } +static volatile SDL_bool separate_mouse_and_touch = SDL_FALSE; + +static void +SeparateEventsHintWatcher(void *userdata, const char *name, + const char *oldValue, const char *newValue) +{ + jclass mActivityClass = Android_JNI_GetActivityClass(); + JNIEnv *env = Android_JNI_GetEnv(); + jfieldID fid = (*env)->GetStaticFieldID(env, mActivityClass, "mSeparateMouseAndTouch", "Z"); + + separate_mouse_and_touch = (newValue && (SDL_strcmp(newValue, "1") == 0)); + (*env)->SetStaticBooleanField(env, mActivityClass, fid, separate_mouse_and_touch ? JNI_TRUE : JNI_FALSE); +} + void Android_InitTouch(void) { int i; int* ids; - int number = Android_JNI_GetTouchDeviceIds(&ids); + const int number = Android_JNI_GetTouchDeviceIds(&ids); + + SDL_AddHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, + SeparateEventsHintWatcher, NULL); + if (0 < number) { for (i = 0; i < number; ++i) { SDL_AddTouch((SDL_TouchID) ids[i], ""); /* no error handling */ @@ -64,6 +81,13 @@ void Android_InitTouch(void) } } +void Android_QuitTouch(void) +{ + SDL_DelHintCallback(SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH, + SeparateEventsHintWatcher, NULL); + separate_mouse_and_touch = SDL_FALSE; +} + void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p) { SDL_TouchID touchDeviceId = 0; @@ -84,37 +108,42 @@ void Android_OnTouch(int touch_device_id_in, int pointer_finger_id_in, int actio switch (action) { 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) { + 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); + } 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) { + Android_GetWindowCoordinates(x, y, &window_x, &window_y); + /* 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 */ + if (!separate_mouse_and_touch) { + /* send mouse up */ + SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + } pointerFingerID = (SDL_FingerID) 0; - SDL_SendMouseButton(Android_Window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); case ACTION_POINTER_UP: /* Non primary pointer up */ SDL_SendTouch(touchDeviceId, fingerId, SDL_FALSE, x, y, p); break; - + default: break; } diff --git a/src/video/android/SDL_androidtouch.h b/src/video/android/SDL_androidtouch.h index 81a0cb50e..904e0d2a6 100644 --- a/src/video/android/SDL_androidtouch.h +++ b/src/video/android/SDL_androidtouch.h @@ -23,6 +23,7 @@ #include "SDL_androidvideo.h" extern void Android_InitTouch(void); +extern void Android_QuitTouch(void); extern void Android_OnTouch( int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 05c07537d..66384b261 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -64,6 +64,8 @@ extern int Android_GLES_LoadLibrary(_THIS, const char *path); int Android_ScreenWidth = 0; int Android_ScreenHeight = 0; Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN; +int Android_ScreenRate = 0; + SDL_sem *Android_PauseSem = NULL, *Android_ResumeSem = NULL; /* Currently only one window */ @@ -84,6 +86,7 @@ Android_SuspendScreenSaver(_THIS) static void Android_DeleteDevice(SDL_VideoDevice * device) { + SDL_free(device->driverdata); SDL_free(device); } @@ -166,7 +169,7 @@ Android_VideoInit(_THIS) mode.format = Android_ScreenFormat; mode.w = Android_ScreenWidth; mode.h = Android_ScreenHeight; - mode.refresh_rate = 0; + mode.refresh_rate = Android_ScreenRate; mode.driverdata = NULL; if (SDL_AddBasicVideoDisplay(&mode) < 0) { return -1; @@ -185,15 +188,17 @@ Android_VideoInit(_THIS) void Android_VideoQuit(_THIS) { + Android_QuitTouch(); } /* This function gets called before VideoInit() */ void -Android_SetScreenResolution(int width, int height, Uint32 format) +Android_SetScreenResolution(int width, int height, Uint32 format, float rate) { Android_ScreenWidth = width; Android_ScreenHeight = height; Android_ScreenFormat = format; + Android_ScreenRate = rate; if (Android_Window) { SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESIZED, width, height); diff --git a/src/video/android/SDL_androidvideo.h b/src/video/android/SDL_androidvideo.h index ccd5d7a16..a403c81b5 100644 --- a/src/video/android/SDL_androidvideo.h +++ b/src/video/android/SDL_androidvideo.h @@ -28,7 +28,7 @@ #include "../SDL_sysvideo.h" /* Called by the JNI layer when the screen changes size or format */ -extern void Android_SetScreenResolution(int width, int height, Uint32 format); +extern void Android_SetScreenResolution(int width, int height, Uint32 format, float rate); /* Private display data */ diff --git a/src/video/cocoa/SDL_cocoaevents.h b/src/video/cocoa/SDL_cocoaevents.h index 687cf647e..1d27bbf99 100644 --- a/src/video/cocoa/SDL_cocoaevents.h +++ b/src/video/cocoa/SDL_cocoaevents.h @@ -25,6 +25,7 @@ extern void Cocoa_RegisterApp(void); extern void Cocoa_PumpEvents(_THIS); +extern void Cocoa_SuspendScreenSaver(_THIS); #endif /* _SDL_cocoaevents_h */ diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 13aeb4502..925f05b8e 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -27,6 +27,11 @@ #include "../../events/SDL_events_c.h" #include "SDL_assert.h" +/* This define was added in the 10.9 SDK. */ +#ifndef kIOPMAssertPreventUserIdleDisplaySleep +#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep +#endif + @interface SDLApplication : NSApplication - (void)terminate:(id)sender; @@ -61,11 +66,19 @@ { self = [super init]; if (self) { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + seenFirstActivate = NO; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(focusSomeWindow:) - name:NSApplicationDidBecomeActiveNotification - object:nil]; + + [center addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:nil]; + + [center addObserver:self + selector:@selector(focusSomeWindow:) + name:NSApplicationDidBecomeActiveNotification + object:nil]; } return self; @@ -73,16 +86,65 @@ - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + [center removeObserver:self name:NSWindowWillCloseNotification object:nil]; + [center removeObserver:self name:NSApplicationDidBecomeActiveNotification object:nil]; + [super dealloc]; } +- (void)windowWillClose:(NSNotification *)notification; +{ + NSWindow *win = (NSWindow*)[notification object]; + + if (![win isKeyWindow]) { + return; + } + + /* HACK: Make the next window in the z-order key when the key window is + * closed. The custom event loop and/or windowing code we have seems to + * prevent the normal behavior: https://bugzilla.libsdl.org/show_bug.cgi?id=1825 + */ + + /* +[NSApp orderedWindows] never includes the 'About' window, but we still + * want to try its list first since the behavior in other apps is to only + * make the 'About' window key if no other windows are on-screen. + */ + for (NSWindow *window in [NSApp orderedWindows]) { + if (window != win && [window canBecomeKeyWindow]) { + if ([window respondsToSelector:@selector(isOnActiveSpace)]) { + if (![window isOnActiveSpace]) { + continue; + } + } + [window makeKeyAndOrderFront:self]; + return; + } + } + + /* If a window wasn't found above, iterate through all visible windows + * (including the 'About' window, if it's shown) and make the first one key. + * Note that +[NSWindow windowNumbersWithOptions:] was added in 10.6. + */ + if ([NSWindow respondsToSelector:@selector(windowNumbersWithOptions:)]) { + /* Get all visible windows in the active Space, in z-order. */ + for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) { + NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]]; + if (window && window != win && [window canBecomeKeyWindow]) { + [window makeKeyAndOrderFront:self]; + return; + } + } + } +} + - (void)focusSomeWindow:(NSNotification *)aNotification { /* HACK: Ignore the first call. The application gets a * applicationDidBecomeActive: a little bit after the first window is * created, and if we don't ignore it, a window that has been created with - * SDL_WINDOW_MINIZED will ~immediately be restored. + * SDL_WINDOW_MINIMIZED will ~immediately be restored. */ if (!seenFirstActivate) { seenFirstActivate = YES; @@ -251,17 +313,24 @@ Cocoa_RegisterApp(void) { @autoreleasepool { /* This can get called more than once! Be careful what you initialize! */ - ProcessSerialNumber psn; - - if (!GetCurrentProcess(&psn)) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - } if (NSApp == nil) { [SDLApplication sharedApplication]; SDL_assert(NSApp != nil); +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 + if ([NSApp respondsToSelector:@selector(setActivationPolicy:)]) { +#endif + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 + } else { + ProcessSerialNumber psn = {0, kCurrentProcess}; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + } +#endif + + [NSApp activateIgnoringOtherApps:YES]; + if ([NSApp mainMenu] == nil) { CreateApplicationMenus(); } @@ -293,8 +362,8 @@ Cocoa_PumpEvents(_THIS) { @autoreleasepool { /* Update activity every 30 seconds to prevent screensaver */ - if (_this->suspend_screensaver) { - SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + if (_this->suspend_screensaver && !data->screensaver_use_iopm) { Uint32 now = SDL_GetTicks(); if (!data->screensaver_activity || SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { @@ -336,6 +405,35 @@ Cocoa_PumpEvents(_THIS) } }} +void +Cocoa_SuspendScreenSaver(_THIS) +{ @autoreleasepool +{ + SDL_VideoData *data = (SDL_VideoData *)_this->driverdata; + + if (!data->screensaver_use_iopm) { + return; + } + + if (data->screensaver_assertion) { + IOPMAssertionRelease(data->screensaver_assertion); + data->screensaver_assertion = 0; + } + + if (_this->suspend_screensaver) { + /* FIXME: this should ideally describe the real reason why the game + * called SDL_DisableScreenSaver. Note that the name is only meant to be + * seen by OS X power users. there's an additional optional human-readable + * (localized) reason parameter which we don't set. + */ + NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"]; + IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, + (CFStringRef) name, + NULL, NULL, NULL, 0, NULL, + &data->screensaver_assertion); + } +}} + #endif /* SDL_VIDEO_DRIVER_COCOA */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index b3025c4f2..bc485b457 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -193,6 +193,7 @@ GetDisplayMode(_THIS, const void *moderef, CVDisplayLinkRef link, SDL_DisplayMod break; case 8: /* We don't support palettized modes now */ default: /* Totally unrecognizable bit depth. */ + SDL_free(data); return SDL_FALSE; } mode->w = width; diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 8b933c27d..c5d60f78d 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -399,6 +399,13 @@ Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event) float x = -[event deltaX]; float y = [event deltaY]; + SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL; + + if ([event respondsToSelector:@selector(isDirectionInvertedFromDevice)]) { + if ([event isDirectionInvertedFromDevice] == YES) { + direction = SDL_MOUSEWHEEL_FLIPPED; + } + } if (x > 0) { x += 0.9f; @@ -410,7 +417,7 @@ Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event) } else if (y < 0) { y -= 0.9f; } - SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y); + SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y, direction); } void diff --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h index 288c41fca..cf254db1b 100644 --- a/src/video/cocoa/SDL_cocoavideo.h +++ b/src/video/cocoa/SDL_cocoavideo.h @@ -26,6 +26,7 @@ #include "SDL_opengl.h" #include +#include #include #include "SDL_keycode.h" @@ -51,6 +52,9 @@ typedef struct SDL_VideoData SDLTranslatorResponder *fieldEdit; NSInteger clipboard_count; Uint32 screensaver_activity; + BOOL screensaver_use_iopm; + IOPMAssertionID screensaver_assertion; + } SDL_VideoData; /* Utility functions */ diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index ad4f14c21..f31218b3a 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -76,6 +76,7 @@ Cocoa_CreateDevice(int devindex) device->GetDisplayModes = Cocoa_GetDisplayModes; device->SetDisplayMode = Cocoa_SetDisplayMode; device->PumpEvents = Cocoa_PumpEvents; + device->SuspendScreenSaver = Cocoa_SuspendScreenSaver; device->CreateWindow = Cocoa_CreateWindow; device->CreateWindowFrom = Cocoa_CreateWindowFrom; @@ -148,6 +149,9 @@ Cocoa_VideoInit(_THIS) const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES); data->allow_spaces = ( (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && (!hint || (*hint != '0')) ); + /* The IOPM assertion API can disable the screensaver as of 10.7. */ + data->screensaver_use_iopm = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; + return 0; } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index d5455290a..2d301e499 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -374,7 +374,6 @@ SetWindowStyle(SDL_Window * window, unsigned int style) NSNotificationCenter *center; NSWindow *window = _data->nswindow; NSView *view = [window contentView]; - NSArray *windows = nil; center = [NSNotificationCenter defaultCenter]; @@ -402,25 +401,6 @@ SetWindowStyle(SDL_Window * window, unsigned int style) if ([view nextResponder] == self) { [view setNextResponder:nil]; } - - /* Make the next window in the z-order Key. If we weren't the foreground - when closed, this is a no-op. - !!! FIXME: Note that this is a hack, and there are corner cases where - !!! FIXME: this fails (such as the About box). The typical nib+RunLoop - !!! FIXME: handles this for Cocoa apps, but we bypass all that in SDL. - !!! FIXME: We should remove this code when we find a better way to - !!! FIXME: have the system do this for us. See discussion in - !!! FIXME: http://bugzilla.libsdl.org/show_bug.cgi?id=1825 - */ - windows = [NSApp orderedWindows]; - for (NSWindow *win in windows) { - if (win == window) { - continue; - } - - [win makeKeyAndOrderFront:self]; - break; - } } - (BOOL)isMoving @@ -1209,16 +1189,9 @@ Cocoa_SetWindowTitle(_THIS, SDL_Window * window) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow; - NSString *string; - - if(window->title) { - string = [[NSString alloc] initWithUTF8String:window->title]; - } else { - string = [[NSString alloc] init]; - } + NSString *string = [[NSString alloc] initWithUTF8String:window->title]; [nswindow setTitle:string]; [string release]; - [pool release]; } diff --git a/src/video/directfb/SDL_DirectFB_WM.c b/src/video/directfb/SDL_DirectFB_WM.c index b48a10698..e85c8d12e 100644 --- a/src/video/directfb/SDL_DirectFB_WM.c +++ b/src/video/directfb/SDL_DirectFB_WM.c @@ -161,7 +161,7 @@ DirectFB_WM_RedrawLayout(_THIS, SDL_Window * window) y, w - 2 * d); /* Caption */ - if (window->title) { + if (*window->title) { s->SetColor(s, COLOR_EXPAND(t->font_color)); DrawCraption(_this, s, (x - w) / 2, t->top_size + d, window->title); } diff --git a/src/video/directfb/SDL_DirectFB_video.c b/src/video/directfb/SDL_DirectFB_video.c index 0d107dc98..35379cb95 100644 --- a/src/video/directfb/SDL_DirectFB_video.c +++ b/src/video/directfb/SDL_DirectFB_video.c @@ -156,7 +156,7 @@ DirectFB_CreateDevice(int devindex) return device; error: if (device) - free(device); + SDL_free(device); return (0); } diff --git a/src/video/dummy/SDL_nullvideo.c b/src/video/dummy/SDL_nullvideo.c index 28147bd18..79f831eee 100644 --- a/src/video/dummy/SDL_nullvideo.c +++ b/src/video/dummy/SDL_nullvideo.c @@ -82,7 +82,6 @@ DUMMY_CreateDevice(int devindex) device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); if (!device) { SDL_OutOfMemory(); - SDL_free(device); return (0); } diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c new file mode 100644 index 000000000..6a04d4cc8 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -0,0 +1,644 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN + +#include + +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_keyboard_c.h" +#include "../../events/SDL_touch_c.h" + +#include "SDL_emscriptenevents.h" +#include "SDL_emscriptenvideo.h" + +#include "SDL_hints.h" + +#define FULLSCREEN_MASK ( SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN ) + +/* +.which to scancode +https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Constants +*/ +static const SDL_Scancode emscripten_scancode_table[] = { + /* 0 */ SDL_SCANCODE_UNKNOWN, + /* 1 */ SDL_SCANCODE_UNKNOWN, + /* 2 */ SDL_SCANCODE_UNKNOWN, + /* 3 */ SDL_SCANCODE_CANCEL, + /* 4 */ SDL_SCANCODE_UNKNOWN, + /* 5 */ SDL_SCANCODE_UNKNOWN, + /* 6 */ SDL_SCANCODE_HELP, + /* 7 */ SDL_SCANCODE_UNKNOWN, + /* 8 */ SDL_SCANCODE_BACKSPACE, + /* 9 */ SDL_SCANCODE_TAB, + /* 10 */ SDL_SCANCODE_UNKNOWN, + /* 11 */ SDL_SCANCODE_UNKNOWN, + /* 12 */ SDL_SCANCODE_UNKNOWN, + /* 13 */ SDL_SCANCODE_RETURN, + /* 14 */ SDL_SCANCODE_UNKNOWN, + /* 15 */ SDL_SCANCODE_UNKNOWN, + /* 16 */ SDL_SCANCODE_LSHIFT, + /* 17 */ SDL_SCANCODE_LCTRL, + /* 18 */ SDL_SCANCODE_LALT, + /* 19 */ SDL_SCANCODE_PAUSE, + /* 20 */ SDL_SCANCODE_CAPSLOCK, + /* 21 */ SDL_SCANCODE_UNKNOWN, + /* 22 */ SDL_SCANCODE_UNKNOWN, + /* 23 */ SDL_SCANCODE_UNKNOWN, + /* 24 */ SDL_SCANCODE_UNKNOWN, + /* 25 */ SDL_SCANCODE_UNKNOWN, + /* 26 */ SDL_SCANCODE_UNKNOWN, + /* 27 */ SDL_SCANCODE_ESCAPE, + /* 28 */ SDL_SCANCODE_UNKNOWN, + /* 29 */ SDL_SCANCODE_UNKNOWN, + /* 30 */ SDL_SCANCODE_UNKNOWN, + /* 31 */ SDL_SCANCODE_UNKNOWN, + /* 32 */ SDL_SCANCODE_SPACE, + /* 33 */ SDL_SCANCODE_PAGEUP, + /* 34 */ SDL_SCANCODE_PAGEDOWN, + /* 35 */ SDL_SCANCODE_END, + /* 36 */ SDL_SCANCODE_HOME, + /* 37 */ SDL_SCANCODE_LEFT, + /* 38 */ SDL_SCANCODE_UP, + /* 39 */ SDL_SCANCODE_RIGHT, + /* 40 */ SDL_SCANCODE_DOWN, + /* 41 */ SDL_SCANCODE_UNKNOWN, + /* 42 */ SDL_SCANCODE_UNKNOWN, + /* 43 */ SDL_SCANCODE_UNKNOWN, + /* 44 */ SDL_SCANCODE_UNKNOWN, + /* 45 */ SDL_SCANCODE_INSERT, + /* 46 */ SDL_SCANCODE_DELETE, + /* 47 */ SDL_SCANCODE_UNKNOWN, + /* 48 */ SDL_SCANCODE_0, + /* 49 */ SDL_SCANCODE_1, + /* 50 */ SDL_SCANCODE_2, + /* 51 */ SDL_SCANCODE_3, + /* 52 */ SDL_SCANCODE_4, + /* 53 */ SDL_SCANCODE_5, + /* 54 */ SDL_SCANCODE_6, + /* 55 */ SDL_SCANCODE_7, + /* 56 */ SDL_SCANCODE_8, + /* 57 */ SDL_SCANCODE_9, + /* 58 */ SDL_SCANCODE_UNKNOWN, + /* 59 */ SDL_SCANCODE_SEMICOLON, + /* 60 */ SDL_SCANCODE_UNKNOWN, + /* 61 */ SDL_SCANCODE_EQUALS, + /* 62 */ SDL_SCANCODE_UNKNOWN, + /* 63 */ SDL_SCANCODE_UNKNOWN, + /* 64 */ SDL_SCANCODE_UNKNOWN, + /* 65 */ SDL_SCANCODE_A, + /* 66 */ SDL_SCANCODE_B, + /* 67 */ SDL_SCANCODE_C, + /* 68 */ SDL_SCANCODE_D, + /* 69 */ SDL_SCANCODE_E, + /* 70 */ SDL_SCANCODE_F, + /* 71 */ SDL_SCANCODE_G, + /* 72 */ SDL_SCANCODE_H, + /* 73 */ SDL_SCANCODE_I, + /* 74 */ SDL_SCANCODE_J, + /* 75 */ SDL_SCANCODE_K, + /* 76 */ SDL_SCANCODE_L, + /* 77 */ SDL_SCANCODE_M, + /* 78 */ SDL_SCANCODE_N, + /* 79 */ SDL_SCANCODE_O, + /* 80 */ SDL_SCANCODE_P, + /* 81 */ SDL_SCANCODE_Q, + /* 82 */ SDL_SCANCODE_R, + /* 83 */ SDL_SCANCODE_S, + /* 84 */ SDL_SCANCODE_T, + /* 85 */ SDL_SCANCODE_U, + /* 86 */ SDL_SCANCODE_V, + /* 87 */ SDL_SCANCODE_W, + /* 88 */ SDL_SCANCODE_X, + /* 89 */ SDL_SCANCODE_Y, + /* 90 */ SDL_SCANCODE_Z, + /* 91 */ SDL_SCANCODE_LGUI, + /* 92 */ SDL_SCANCODE_UNKNOWN, + /* 93 */ SDL_SCANCODE_APPLICATION, + /* 94 */ SDL_SCANCODE_UNKNOWN, + /* 95 */ SDL_SCANCODE_UNKNOWN, + /* 96 */ SDL_SCANCODE_KP_0, + /* 97 */ SDL_SCANCODE_KP_1, + /* 98 */ SDL_SCANCODE_KP_2, + /* 99 */ SDL_SCANCODE_KP_3, + /* 100 */ SDL_SCANCODE_KP_4, + /* 101 */ SDL_SCANCODE_KP_5, + /* 102 */ SDL_SCANCODE_KP_6, + /* 103 */ SDL_SCANCODE_KP_7, + /* 104 */ SDL_SCANCODE_KP_8, + /* 105 */ SDL_SCANCODE_KP_9, + /* 106 */ SDL_SCANCODE_KP_MULTIPLY, + /* 107 */ SDL_SCANCODE_KP_PLUS, + /* 108 */ SDL_SCANCODE_UNKNOWN, + /* 109 */ SDL_SCANCODE_KP_MINUS, + /* 110 */ SDL_SCANCODE_KP_PERIOD, + /* 111 */ SDL_SCANCODE_KP_DIVIDE, + /* 112 */ SDL_SCANCODE_F1, + /* 113 */ SDL_SCANCODE_F2, + /* 114 */ SDL_SCANCODE_F3, + /* 115 */ SDL_SCANCODE_F4, + /* 116 */ SDL_SCANCODE_F5, + /* 117 */ SDL_SCANCODE_F6, + /* 118 */ SDL_SCANCODE_F7, + /* 119 */ SDL_SCANCODE_F8, + /* 120 */ SDL_SCANCODE_F9, + /* 121 */ SDL_SCANCODE_F10, + /* 122 */ SDL_SCANCODE_F11, + /* 123 */ SDL_SCANCODE_F12, + /* 124 */ SDL_SCANCODE_F13, + /* 125 */ SDL_SCANCODE_F14, + /* 126 */ SDL_SCANCODE_F15, + /* 127 */ SDL_SCANCODE_F16, + /* 128 */ SDL_SCANCODE_F17, + /* 129 */ SDL_SCANCODE_F18, + /* 130 */ SDL_SCANCODE_F19, + /* 131 */ SDL_SCANCODE_F20, + /* 132 */ SDL_SCANCODE_F21, + /* 133 */ SDL_SCANCODE_F22, + /* 134 */ SDL_SCANCODE_F23, + /* 135 */ SDL_SCANCODE_F24, + /* 136 */ SDL_SCANCODE_UNKNOWN, + /* 137 */ SDL_SCANCODE_UNKNOWN, + /* 138 */ SDL_SCANCODE_UNKNOWN, + /* 139 */ SDL_SCANCODE_UNKNOWN, + /* 140 */ SDL_SCANCODE_UNKNOWN, + /* 141 */ SDL_SCANCODE_UNKNOWN, + /* 142 */ SDL_SCANCODE_UNKNOWN, + /* 143 */ SDL_SCANCODE_UNKNOWN, + /* 144 */ SDL_SCANCODE_NUMLOCKCLEAR, + /* 145 */ SDL_SCANCODE_SCROLLLOCK, + /* 146 */ SDL_SCANCODE_UNKNOWN, + /* 147 */ SDL_SCANCODE_UNKNOWN, + /* 148 */ SDL_SCANCODE_UNKNOWN, + /* 149 */ SDL_SCANCODE_UNKNOWN, + /* 150 */ SDL_SCANCODE_UNKNOWN, + /* 151 */ SDL_SCANCODE_UNKNOWN, + /* 152 */ SDL_SCANCODE_UNKNOWN, + /* 153 */ SDL_SCANCODE_UNKNOWN, + /* 154 */ SDL_SCANCODE_UNKNOWN, + /* 155 */ SDL_SCANCODE_UNKNOWN, + /* 156 */ SDL_SCANCODE_UNKNOWN, + /* 157 */ SDL_SCANCODE_UNKNOWN, + /* 158 */ SDL_SCANCODE_UNKNOWN, + /* 159 */ SDL_SCANCODE_UNKNOWN, + /* 160 */ SDL_SCANCODE_UNKNOWN, + /* 161 */ SDL_SCANCODE_UNKNOWN, + /* 162 */ SDL_SCANCODE_UNKNOWN, + /* 163 */ SDL_SCANCODE_UNKNOWN, + /* 164 */ SDL_SCANCODE_UNKNOWN, + /* 165 */ SDL_SCANCODE_UNKNOWN, + /* 166 */ SDL_SCANCODE_UNKNOWN, + /* 167 */ SDL_SCANCODE_UNKNOWN, + /* 168 */ SDL_SCANCODE_UNKNOWN, + /* 169 */ SDL_SCANCODE_UNKNOWN, + /* 170 */ SDL_SCANCODE_UNKNOWN, + /* 171 */ SDL_SCANCODE_UNKNOWN, + /* 172 */ SDL_SCANCODE_UNKNOWN, + /* 173 */ SDL_SCANCODE_MINUS, /*FX*/ + /* 174 */ SDL_SCANCODE_UNKNOWN, + /* 175 */ SDL_SCANCODE_UNKNOWN, + /* 176 */ SDL_SCANCODE_UNKNOWN, + /* 177 */ SDL_SCANCODE_UNKNOWN, + /* 178 */ SDL_SCANCODE_UNKNOWN, + /* 179 */ SDL_SCANCODE_UNKNOWN, + /* 180 */ SDL_SCANCODE_UNKNOWN, + /* 181 */ SDL_SCANCODE_UNKNOWN, + /* 182 */ SDL_SCANCODE_UNKNOWN, + /* 183 */ SDL_SCANCODE_UNKNOWN, + /* 184 */ SDL_SCANCODE_UNKNOWN, + /* 185 */ SDL_SCANCODE_UNKNOWN, + /* 186 */ SDL_SCANCODE_SEMICOLON, /*IE, Chrome, D3E legacy*/ + /* 187 */ SDL_SCANCODE_EQUALS, /*IE, Chrome, D3E legacy*/ + /* 188 */ SDL_SCANCODE_COMMA, + /* 189 */ SDL_SCANCODE_MINUS, /*IE, Chrome, D3E legacy*/ + /* 190 */ SDL_SCANCODE_PERIOD, + /* 191 */ SDL_SCANCODE_SLASH, + /* 192 */ SDL_SCANCODE_GRAVE, /*FX, D3E legacy (SDL_SCANCODE_APOSTROPHE in IE/Chrome)*/ + /* 193 */ SDL_SCANCODE_UNKNOWN, + /* 194 */ SDL_SCANCODE_UNKNOWN, + /* 195 */ SDL_SCANCODE_UNKNOWN, + /* 196 */ SDL_SCANCODE_UNKNOWN, + /* 197 */ SDL_SCANCODE_UNKNOWN, + /* 198 */ SDL_SCANCODE_UNKNOWN, + /* 199 */ SDL_SCANCODE_UNKNOWN, + /* 200 */ SDL_SCANCODE_UNKNOWN, + /* 201 */ SDL_SCANCODE_UNKNOWN, + /* 202 */ SDL_SCANCODE_UNKNOWN, + /* 203 */ SDL_SCANCODE_UNKNOWN, + /* 204 */ SDL_SCANCODE_UNKNOWN, + /* 205 */ SDL_SCANCODE_UNKNOWN, + /* 206 */ SDL_SCANCODE_UNKNOWN, + /* 207 */ SDL_SCANCODE_UNKNOWN, + /* 208 */ SDL_SCANCODE_UNKNOWN, + /* 209 */ SDL_SCANCODE_UNKNOWN, + /* 210 */ SDL_SCANCODE_UNKNOWN, + /* 211 */ SDL_SCANCODE_UNKNOWN, + /* 212 */ SDL_SCANCODE_UNKNOWN, + /* 213 */ SDL_SCANCODE_UNKNOWN, + /* 214 */ SDL_SCANCODE_UNKNOWN, + /* 215 */ SDL_SCANCODE_UNKNOWN, + /* 216 */ SDL_SCANCODE_UNKNOWN, + /* 217 */ SDL_SCANCODE_UNKNOWN, + /* 218 */ SDL_SCANCODE_UNKNOWN, + /* 219 */ SDL_SCANCODE_LEFTBRACKET, + /* 220 */ SDL_SCANCODE_BACKSLASH, + /* 221 */ SDL_SCANCODE_RIGHTBRACKET, + /* 222 */ SDL_SCANCODE_APOSTROPHE, /*FX, D3E legacy*/ +}; + + +/* "borrowed" from SDL_windowsevents.c */ +int +Emscripten_ConvertUTF32toUTF8(Uint32 codepoint, char * text) +{ + if (codepoint <= 0x7F) { + text[0] = (char) codepoint; + text[1] = '\0'; + } else if (codepoint <= 0x7FF) { + text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F); + text[1] = 0x80 | (char) (codepoint & 0x3F); + text[2] = '\0'; + } else if (codepoint <= 0xFFFF) { + text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F); + text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F); + text[2] = 0x80 | (char) (codepoint & 0x3F); + text[3] = '\0'; + } else if (codepoint <= 0x10FFFF) { + text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F); + text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F); + text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F); + text[3] = 0x80 | (char) (codepoint & 0x3F); + text[4] = '\0'; + } else { + return SDL_FALSE; + } + return SDL_TRUE; +} + +EM_BOOL +Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + int mx = mouseEvent->canvasX, my = mouseEvent->canvasY; + EmscriptenPointerlockChangeEvent pointerlock_status; + + /* check for pointer lock */ + emscripten_get_pointerlock_status(&pointerlock_status); + + if (pointerlock_status.isActive) { + mx = mouseEvent->movementX; + my = mouseEvent->movementY; + } + + /* rescale (in case canvas is being scaled)*/ + double client_w, client_h; + emscripten_get_element_css_size(NULL, &client_w, &client_h); + + mx = mx * (window_data->window->w / (client_w * window_data->pixel_ratio)); + my = my * (window_data->window->h / (client_h * window_data->pixel_ratio)); + + SDL_SendMouseMotion(window_data->window, 0, pointerlock_status.isActive, mx, my); + return 0; +} + +EM_BOOL +Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + uint32_t sdl_button; + switch (mouseEvent->button) { + case 0: + sdl_button = SDL_BUTTON_LEFT; + break; + case 1: + sdl_button = SDL_BUTTON_MIDDLE; + break; + case 2: + sdl_button = SDL_BUTTON_RIGHT; + break; + default: + return 0; + } + SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button); + return 1; +} + +EM_BOOL +Emscripten_HandleMouseFocus(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? SDL_WINDOWEVENT_ENTER : SDL_WINDOWEVENT_LEAVE, 0, 0); + return 1; +} + +EM_BOOL +Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL); + return 1; +} + +EM_BOOL +Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); + return 1; +} + +EM_BOOL +Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) +{ + /*SDL_WindowData *window_data = userData;*/ + int i; + + SDL_TouchID deviceId = 0; + if (!SDL_GetTouch(deviceId)) { + if (SDL_AddTouch(deviceId, "") < 0) { + return 0; + } + } + + for (i = 0; i < touchEvent->numTouches; i++) { + long x, y, id; + + if (!touchEvent->touches[i].isChanged) + continue; + + id = touchEvent->touches[i].identifier; + x = touchEvent->touches[i].canvasX; + y = touchEvent->touches[i].canvasY; + + if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { + SDL_SendTouchMotion(deviceId, id, x, y, 1.0f); + } else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { + SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f); + } else { + SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f); + } + } + + + return 1; +} + +EM_BOOL +Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +{ + Uint32 scancode; + + /* .keyCode is deprecated, but still the most reliable way to get keys */ + if (keyEvent->keyCode < SDL_arraysize(emscripten_scancode_table)) { + scancode = emscripten_scancode_table[keyEvent->keyCode]; + + if (scancode != SDL_SCANCODE_UNKNOWN) { + + if (keyEvent->location == DOM_KEY_LOCATION_RIGHT) { + switch (scancode) { + case SDL_SCANCODE_LSHIFT: + scancode = SDL_SCANCODE_RSHIFT; + break; + case SDL_SCANCODE_LCTRL: + scancode = SDL_SCANCODE_RCTRL; + break; + case SDL_SCANCODE_LALT: + scancode = SDL_SCANCODE_RALT; + break; + case SDL_SCANCODE_LGUI: + scancode = SDL_SCANCODE_RGUI; + break; + } + } + SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? + SDL_PRESSED : SDL_RELEASED, scancode); + } + } + + /* if we prevent keydown, we won't get keypress + * also we need to ALWAYS prevent backspace and tab otherwise chrome takes action and does bad navigation UX + */ + return SDL_GetEventState(SDL_TEXTINPUT) != SDL_ENABLE || eventType != EMSCRIPTEN_EVENT_KEYDOWN + || keyEvent->keyCode == 8 /* backspace */ || keyEvent->keyCode == 9 /* tab */; +} + +EM_BOOL +Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) +{ + char text[5]; + if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) { + SDL_SendKeyboardText(text); + } + return 1; +} + +EM_BOOL +Emscripten_HandleFullscreenChange(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData) +{ + /*make sure this is actually our element going fullscreen*/ + if(SDL_strcmp(fullscreenChangeEvent->id, "SDLFullscreenElement") != 0) + return 0; + + SDL_WindowData *window_data = userData; + if(fullscreenChangeEvent->isFullscreen) + { + SDL_bool is_desktop_fullscreen; + window_data->window->flags |= window_data->requested_fullscreen_mode; + + if(!window_data->requested_fullscreen_mode) + window_data->window->flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; /*we didn't reqest fullscreen*/ + + window_data->requested_fullscreen_mode = 0; + + is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP; + + /*update size*/ + if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen) + { + emscripten_set_canvas_size(fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight); + SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, fullscreenChangeEvent->screenWidth, fullscreenChangeEvent->screenHeight); + } + else + { + /*preserve ratio*/ + double w = window_data->window->w; + double h = window_data->window->h; + double factor = SDL_min(fullscreenChangeEvent->screenWidth / w, fullscreenChangeEvent->screenHeight / h); + emscripten_set_element_css_size(NULL, w * factor, h * factor); + } + } + else + { + EM_ASM({ + //un-reparent canvas (similar to Module.requestFullscreen) + var canvas = Module['canvas']; + if(canvas.parentNode.id == "SDLFullscreenElement") { + var canvasContainer = canvas.parentNode; + canvasContainer.parentNode.insertBefore(canvas, canvasContainer); + canvasContainer.parentNode.removeChild(canvasContainer); + } + }); + double unscaled_w = window_data->windowed_width / window_data->pixel_ratio; + double unscaled_h = window_data->windowed_height / window_data->pixel_ratio; + emscripten_set_canvas_size(window_data->windowed_width, window_data->windowed_height); + + if (!window_data->external_size && window_data->pixel_ratio != 1.0f) { + emscripten_set_element_css_size(NULL, unscaled_w, unscaled_h); + } + + SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, unscaled_w, unscaled_h); + + window_data->window->flags &= ~FULLSCREEN_MASK; + } + + return 0; +} + +EM_BOOL +Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + if(window_data->window->flags & FULLSCREEN_MASK) + { + SDL_bool is_desktop_fullscreen = (window_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP; + + if(window_data->window->flags & SDL_WINDOW_RESIZABLE || is_desktop_fullscreen) + { + emscripten_set_canvas_size(uiEvent->windowInnerWidth * window_data->pixel_ratio, uiEvent->windowInnerHeight * window_data->pixel_ratio); + SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, uiEvent->windowInnerWidth, uiEvent->windowInnerHeight); + } + } + else + { + /* this will only work if the canvas size is set through css */ + if(window_data->window->flags & SDL_WINDOW_RESIZABLE) + { + double w = window_data->window->w; + double h = window_data->window->h; + + if(window_data->external_size) { + emscripten_get_element_css_size(NULL, &w, &h); + } + + emscripten_set_canvas_size(w * window_data->pixel_ratio, h * window_data->pixel_ratio); + + /* set_canvas_size unsets this */ + if (!window_data->external_size && window_data->pixel_ratio != 1.0f) { + emscripten_set_element_css_size(NULL, w, h); + } + + SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, w, h); + } + } + + return 0; +} + +EM_BOOL +Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData) +{ + SDL_WindowData *window_data = userData; + SDL_SendWindowEvent(window_data->window, visEvent->hidden ? SDL_WINDOWEVENT_HIDDEN : SDL_WINDOWEVENT_SHOWN, 0, 0); + return 0; +} + +void +Emscripten_RegisterEventHandlers(SDL_WindowData *data) +{ + /* There is only one window and that window is the canvas */ + emscripten_set_mousemove_callback("#canvas", data, 0, Emscripten_HandleMouseMove); + + emscripten_set_mousedown_callback("#canvas", data, 0, Emscripten_HandleMouseButton); + emscripten_set_mouseup_callback("#canvas", data, 0, Emscripten_HandleMouseButton); + + emscripten_set_mouseenter_callback("#canvas", data, 0, Emscripten_HandleMouseFocus); + emscripten_set_mouseleave_callback("#canvas", data, 0, Emscripten_HandleMouseFocus); + + emscripten_set_wheel_callback("#canvas", data, 0, Emscripten_HandleWheel); + + emscripten_set_focus_callback("#canvas", data, 0, Emscripten_HandleFocus); + emscripten_set_blur_callback("#canvas", data, 0, Emscripten_HandleFocus); + + emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch); + emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); + emscripten_set_touchmove_callback("#canvas", data, 0, Emscripten_HandleTouch); + emscripten_set_touchcancel_callback("#canvas", data, 0, Emscripten_HandleTouch); + + /* Keyboard events are awkward */ + const char *keyElement = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); + if (!keyElement) keyElement = "#window"; + + emscripten_set_keydown_callback(keyElement, data, 0, Emscripten_HandleKey); + emscripten_set_keyup_callback(keyElement, data, 0, Emscripten_HandleKey); + emscripten_set_keypress_callback(keyElement, data, 0, Emscripten_HandleKeyPress); + + emscripten_set_fullscreenchange_callback("#document", data, 0, Emscripten_HandleFullscreenChange); + + emscripten_set_resize_callback("#window", data, 0, Emscripten_HandleResize); + + emscripten_set_visibilitychange_callback(data, 0, Emscripten_HandleVisibilityChange); +} + +void +Emscripten_UnregisterEventHandlers(SDL_WindowData *data) +{ + /* only works due to having one window */ + emscripten_set_mousemove_callback("#canvas", NULL, 0, NULL); + + emscripten_set_mousedown_callback("#canvas", NULL, 0, NULL); + emscripten_set_mouseup_callback("#canvas", NULL, 0, NULL); + + emscripten_set_mouseenter_callback("#canvas", NULL, 0, NULL); + emscripten_set_mouseleave_callback("#canvas", NULL, 0, NULL); + + emscripten_set_wheel_callback("#canvas", NULL, 0, NULL); + + emscripten_set_focus_callback("#canvas", NULL, 0, NULL); + emscripten_set_blur_callback("#canvas", NULL, 0, NULL); + + emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL); + emscripten_set_touchend_callback("#canvas", NULL, 0, NULL); + emscripten_set_touchmove_callback("#canvas", NULL, 0, NULL); + emscripten_set_touchcancel_callback("#canvas", NULL, 0, NULL); + + const char *target = SDL_GetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT); + if (!target) { + target = "#window"; + } + + 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); + + emscripten_set_resize_callback("#window", NULL, 0, NULL); + + emscripten_set_visibilitychange_callback(NULL, 0, NULL); +} + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenevents.h b/src/video/emscripten/SDL_emscriptenevents.h new file mode 100644 index 000000000..01dc6a5e6 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenevents.h @@ -0,0 +1,36 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef _SDL_emscriptenevents_h +#define _SDL_emscriptenevents_h + +#include "SDL_emscriptenvideo.h" + +extern void +Emscripten_RegisterEventHandlers(SDL_WindowData *data); + +extern void +Emscripten_UnregisterEventHandlers(SDL_WindowData *data); +#endif /* _SDL_emscriptenevents_h */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c new file mode 100644 index 000000000..453865abb --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -0,0 +1,136 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN + +#include "SDL_emscriptenvideo.h" +#include "SDL_emscriptenframebuffer.h" + + +int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) +{ + SDL_Surface *surface; + const Uint32 surface_format = SDL_PIXELFORMAT_BGR888; + int w, h; + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + /* Free the old framebuffer surface */ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + surface = data->surface; + SDL_FreeSurface(surface); + + /* Create a new one */ + SDL_PixelFormatEnumToMasks(surface_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); + SDL_GetWindowSize(window, &w, &h); + + surface = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask); + if (!surface) { + return -1; + } + + /* Save the info and return! */ + data->surface = surface; + *format = surface_format; + *pixels = surface->pixels; + *pitch = surface->pitch; + return 0; +} + +int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +{ + SDL_Surface *surface; + + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + surface = data->surface; + if (!surface) { + return SDL_SetError("Couldn't find framebuffer surface for window"); + } + + /* Send the data to the display */ + + EM_ASM_INT({ + //TODO: don't create context every update + var ctx = Module['canvas'].getContext('2d'); + + //library_sdl.js SDL_UnlockSurface + var image = ctx.createImageData($0, $1); + var data = image.data; + var src = $2 >> 2; + var dst = 0; + var isScreen = true; + var num; + if (typeof CanvasPixelArray !== 'undefined' && data instanceof CanvasPixelArray) { + // IE10/IE11: ImageData objects are backed by the deprecated CanvasPixelArray, + // not UInt8ClampedArray. These don't have buffers, so we need to revert + // to copying a byte at a time. We do the undefined check because modern + // browsers do not define CanvasPixelArray anymore. + num = data.length; + while (dst < num) { + var val = HEAP32[src]; // This is optimized. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; + data[dst ] = val & 0xff; + data[dst+1] = (val >> 8) & 0xff; + data[dst+2] = (val >> 16) & 0xff; + data[dst+3] = isScreen ? 0xff : ((val >> 24) & 0xff); + src++; + dst += 4; + } + } else { + var data32 = new Uint32Array(data.buffer); + num = data32.length; + if (isScreen) { + while (dst < num) { + // HEAP32[src++] is an optimization. Instead, we could do {{{ makeGetValue('buffer', 'dst', 'i32') }}}; + data32[dst++] = HEAP32[src++] | 0xff000000; + } + } else { + while (dst < num) { + data32[dst++] = HEAP32[src++]; + } + } + } + + ctx.putImageData(image, 0, 0); + return 0; + }, surface->w, surface->h, surface->pixels); + + /*if (SDL_getenv("SDL_VIDEO_Emscripten_SAVE_FRAMES")) { + static int frame_number = 0; + char file[128]; + SDL_snprintf(file, sizeof(file), "SDL_window%d-%8.8d.bmp", + SDL_GetWindowID(window), ++frame_number); + SDL_SaveBMP(surface, file); + }*/ + return 0; +} + +void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + SDL_FreeSurface(data->surface); + data->surface = NULL; +} + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.h b/src/video/emscripten/SDL_emscriptenframebuffer.h new file mode 100644 index 000000000..e7373b515 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenframebuffer.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef _SDL_emscriptenframebuffer_h +#define _SDL_emscriptenframebuffer_h + +extern int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch); +extern int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects); +extern void Emscripten_DestroyWindowFramebuffer(_THIS, SDL_Window * window); + +#endif /* _SDL_emsctiptenframebuffer_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenmouse.c b/src/video/emscripten/SDL_emscriptenmouse.c new file mode 100644 index 000000000..2e46a0a2e --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenmouse.c @@ -0,0 +1,232 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN + +#include +#include + +#include "SDL_emscriptenmouse.h" + +#include "../../events/SDL_mouse_c.h" +#include "SDL_assert.h" + + +static SDL_Cursor* +Emscripten_CreateDefaultCursor() +{ + SDL_Cursor* cursor; + Emscripten_CursorData *curdata; + + cursor = SDL_calloc(1, sizeof(SDL_Cursor)); + if (cursor) { + curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata)); + if (!curdata) { + SDL_OutOfMemory(); + SDL_free(cursor); + return NULL; + } + + curdata->system_cursor = "default"; + cursor->driverdata = curdata; + } + else { + SDL_OutOfMemory(); + } + + return cursor; +} + +static SDL_Cursor* +Emscripten_CreateCursor(SDL_Surface* sruface, int hot_x, int hot_y) +{ + return Emscripten_CreateDefaultCursor(); +} + +static SDL_Cursor* +Emscripten_CreateSystemCursor(SDL_SystemCursor id) +{ + SDL_Cursor *cursor; + Emscripten_CursorData *curdata; + const char *cursor_name = NULL; + + switch(id) { + case SDL_SYSTEM_CURSOR_ARROW: + cursor_name = "default"; + break; + case SDL_SYSTEM_CURSOR_IBEAM: + cursor_name = "text"; + break; + case SDL_SYSTEM_CURSOR_WAIT: + cursor_name = "wait"; + break; + case SDL_SYSTEM_CURSOR_CROSSHAIR: + cursor_name = "crosshair"; + break; + case SDL_SYSTEM_CURSOR_WAITARROW: + cursor_name = "progress"; + break; + case SDL_SYSTEM_CURSOR_SIZENWSE: + cursor_name = "nwse-resize"; + break; + case SDL_SYSTEM_CURSOR_SIZENESW: + cursor_name = "nesw-resize"; + break; + case SDL_SYSTEM_CURSOR_SIZEWE: + cursor_name = "ew-resize"; + break; + case SDL_SYSTEM_CURSOR_SIZENS: + cursor_name = "ns-resize"; + break; + case SDL_SYSTEM_CURSOR_SIZEALL: + break; + case SDL_SYSTEM_CURSOR_NO: + cursor_name = "not-allowed"; + break; + case SDL_SYSTEM_CURSOR_HAND: + cursor_name = "pointer"; + break; + default: + SDL_assert(0); + return NULL; + } + + cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); + if (!cursor) { + SDL_OutOfMemory(); + return NULL; + } + curdata = (Emscripten_CursorData *) SDL_calloc(1, sizeof(*curdata)); + if (!curdata) { + SDL_OutOfMemory(); + SDL_free(cursor); + return NULL; + } + + curdata->system_cursor = cursor_name; + cursor->driverdata = curdata; + + return cursor; +} + +static void +Emscripten_FreeCursor(SDL_Cursor* cursor) +{ + Emscripten_CursorData *curdata; + if (cursor) { + curdata = (Emscripten_CursorData *) cursor->driverdata; + + if (curdata != NULL) { + SDL_free(cursor->driverdata); + } + + SDL_free(cursor); + } +} + +static int +Emscripten_ShowCursor(SDL_Cursor* cursor) +{ + Emscripten_CursorData *curdata; + if (SDL_GetMouseFocus() != NULL) { + if(cursor && cursor->driverdata) { + curdata = (Emscripten_CursorData *) cursor->driverdata; + + if(curdata->system_cursor) { + EM_ASM_INT({ + if (Module['canvas']) { + Module['canvas'].style['cursor'] = Module['Pointer_stringify']($0); + } + return 0; + }, curdata->system_cursor); + } + } + else { + EM_ASM( + if (Module['canvas']) { + Module['canvas'].style['cursor'] = 'none'; + } + ); + } + } + return 0; +} + +static void +Emscripten_WarpMouse(SDL_Window* window, int x, int y) +{ + SDL_Unsupported(); +} + +static int +Emscripten_SetRelativeMouseMode(SDL_bool enabled) +{ + /* TODO: pointer lock isn't actually enabled yet */ + if(enabled) { + if(emscripten_request_pointerlock(NULL, 1) >= EMSCRIPTEN_RESULT_SUCCESS) { + return 0; + } + } else { + if(emscripten_exit_pointerlock() >= EMSCRIPTEN_RESULT_SUCCESS) { + return 0; + } + } + return -1; +} + +void +Emscripten_InitMouse() +{ + SDL_Mouse* mouse = SDL_GetMouse(); + + mouse->CreateCursor = Emscripten_CreateCursor; + mouse->ShowCursor = Emscripten_ShowCursor; + mouse->FreeCursor = Emscripten_FreeCursor; + mouse->WarpMouse = Emscripten_WarpMouse; + mouse->CreateSystemCursor = Emscripten_CreateSystemCursor; + mouse->SetRelativeMouseMode = Emscripten_SetRelativeMouseMode; + + SDL_SetDefaultCursor(Emscripten_CreateDefaultCursor()); +} + +void +Emscripten_FiniMouse() +{ + SDL_Mouse* mouse = SDL_GetMouse(); + + Emscripten_FreeCursor(mouse->def_cursor); + mouse->def_cursor = NULL; + + mouse->CreateCursor = NULL; + mouse->ShowCursor = NULL; + mouse->FreeCursor = NULL; + mouse->WarpMouse = NULL; + mouse->CreateSystemCursor = NULL; + mouse->SetRelativeMouseMode = NULL; +} + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/emscripten/SDL_emscriptenmouse.h b/src/video/emscripten/SDL_emscriptenmouse.h new file mode 100644 index 000000000..7b3d50e82 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenmouse.h @@ -0,0 +1,39 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef _SDL_emscriptenmouse_h +#define _SDL_emscriptenmouse_h + +typedef struct _Emscripten_CursorData +{ + const char *system_cursor; +} Emscripten_CursorData; + +extern void +Emscripten_InitMouse(); + +extern void +Emscripten_FiniMouse(); + +#endif /* _SDL_emscriptenmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenopengles.c b/src/video/emscripten/SDL_emscriptenopengles.c new file mode 100644 index 000000000..61198be71 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenopengles.c @@ -0,0 +1,117 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL + +#include +#include + +#include "SDL_emscriptenvideo.h" +#include "SDL_emscriptenopengles.h" + +#define LOAD_FUNC(NAME) _this->egl_data->NAME = NAME; + +/* EGL implementation of SDL OpenGL support */ + +int +Emscripten_GLES_LoadLibrary(_THIS, const char *path) { + /*we can't load EGL dynamically*/ + _this->egl_data = (struct SDL_EGL_VideoData *) SDL_calloc(1, sizeof(SDL_EGL_VideoData)); + if (!_this->egl_data) { + return SDL_OutOfMemory(); + } + + LOAD_FUNC(eglGetDisplay); + LOAD_FUNC(eglInitialize); + LOAD_FUNC(eglTerminate); + LOAD_FUNC(eglGetProcAddress); + LOAD_FUNC(eglChooseConfig); + LOAD_FUNC(eglGetConfigAttrib); + LOAD_FUNC(eglCreateContext); + LOAD_FUNC(eglDestroyContext); + LOAD_FUNC(eglCreateWindowSurface); + LOAD_FUNC(eglDestroySurface); + LOAD_FUNC(eglMakeCurrent); + LOAD_FUNC(eglSwapBuffers); + LOAD_FUNC(eglSwapInterval); + LOAD_FUNC(eglWaitNative); + LOAD_FUNC(eglWaitGL); + LOAD_FUNC(eglBindAPI); + + _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + return SDL_SetError("Could not initialize EGL"); + } + + _this->gl_config.driver_loaded = 1; + + if (path) { + SDL_strlcpy(_this->gl_config.driver_path, path, sizeof(_this->gl_config.driver_path) - 1); + } else { + *_this->gl_config.driver_path = '\0'; + } + + return 0; +} + +void +Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context) +{ + /* + WebGL contexts can't actually be deleted, so we need to reset it. + ES2 renderer resets state on init anyway, clearing the canvas should be enough + */ + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + SDL_EGL_DeleteContext(_this, context); +} + +SDL_EGL_CreateContext_impl(Emscripten) +SDL_EGL_SwapWindow_impl(Emscripten) +SDL_EGL_MakeCurrent_impl(Emscripten) + +void +Emscripten_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) +{ + SDL_WindowData *data; + if (window->driverdata) { + data = (SDL_WindowData *) window->driverdata; + + if (w) { + *w = window->w * data->pixel_ratio; + } + + if (h) { + *h = window->h * data->pixel_ratio; + } + } +} + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/emscripten/SDL_emscriptenopengles.h b/src/video/emscripten/SDL_emscriptenopengles.h new file mode 100644 index 000000000..2d37eb05c --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenopengles.h @@ -0,0 +1,49 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef _SDL_emscriptenopengles_h +#define _SDL_emscriptenopengles_h + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL + +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" + +/* OpenGLES functions */ +#define Emscripten_GLES_GetAttribute SDL_EGL_GetAttribute +#define Emscripten_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define Emscripten_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define Emscripten_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define Emscripten_GLES_GetSwapInterval SDL_EGL_GetSwapInterval + +extern int Emscripten_GLES_LoadLibrary(_THIS, const char *path); +extern void Emscripten_GLES_DeleteContext(_THIS, SDL_GLContext context); +extern SDL_GLContext Emscripten_GLES_CreateContext(_THIS, SDL_Window * window); +extern void Emscripten_GLES_SwapWindow(_THIS, SDL_Window * window); +extern int Emscripten_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); +extern void Emscripten_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h); + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN && SDL_VIDEO_OPENGL_EGL */ + +#endif /* _SDL_emscriptenopengles_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c new file mode 100644 index 000000000..5da429271 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenvideo.c @@ -0,0 +1,319 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_EMSCRIPTEN + +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../SDL_egl_c.h" +#include "../../events/SDL_events_c.h" + +#include "SDL_emscriptenvideo.h" +#include "SDL_emscriptenopengles.h" +#include "SDL_emscriptenframebuffer.h" +#include "SDL_emscriptenevents.h" +#include "SDL_emscriptenmouse.h" + +#define EMSCRIPTENVID_DRIVER_NAME "emscripten" + +/* Initialization/Query functions */ +static int Emscripten_VideoInit(_THIS); +static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); +static void Emscripten_VideoQuit(_THIS); + +static int Emscripten_CreateWindow(_THIS, SDL_Window * window); +static void Emscripten_SetWindowSize(_THIS, SDL_Window * window); +static void Emscripten_DestroyWindow(_THIS, SDL_Window * window); +static void Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); +static void Emscripten_PumpEvents(_THIS); + + +/* Emscripten driver bootstrap functions */ + +static int +Emscripten_Available(void) +{ + return (1); +} + +static void +Emscripten_DeleteDevice(SDL_VideoDevice * device) +{ + SDL_free(device); +} + +static SDL_VideoDevice * +Emscripten_CreateDevice(int devindex) +{ + SDL_VideoDevice *device; + + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + SDL_OutOfMemory(); + return (0); + } + + /* Set the function pointers */ + device->VideoInit = Emscripten_VideoInit; + device->VideoQuit = Emscripten_VideoQuit; + device->SetDisplayMode = Emscripten_SetDisplayMode; + + + device->PumpEvents = Emscripten_PumpEvents; + + device->CreateWindow = Emscripten_CreateWindow; + /*device->CreateWindowFrom = Emscripten_CreateWindowFrom; + device->SetWindowTitle = Emscripten_SetWindowTitle; + device->SetWindowIcon = Emscripten_SetWindowIcon; + device->SetWindowPosition = Emscripten_SetWindowPosition;*/ + device->SetWindowSize = Emscripten_SetWindowSize; + /*device->ShowWindow = Emscripten_ShowWindow; + device->HideWindow = Emscripten_HideWindow; + device->RaiseWindow = Emscripten_RaiseWindow; + device->MaximizeWindow = Emscripten_MaximizeWindow; + device->MinimizeWindow = Emscripten_MinimizeWindow; + device->RestoreWindow = Emscripten_RestoreWindow; + device->SetWindowGrab = Emscripten_SetWindowGrab;*/ + device->DestroyWindow = Emscripten_DestroyWindow; + device->SetWindowFullscreen = Emscripten_SetWindowFullscreen; + + device->CreateWindowFramebuffer = Emscripten_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = Emscripten_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = Emscripten_DestroyWindowFramebuffer; + + device->GL_LoadLibrary = Emscripten_GLES_LoadLibrary; + device->GL_GetProcAddress = Emscripten_GLES_GetProcAddress; + device->GL_UnloadLibrary = Emscripten_GLES_UnloadLibrary; + device->GL_CreateContext = Emscripten_GLES_CreateContext; + device->GL_MakeCurrent = Emscripten_GLES_MakeCurrent; + device->GL_SetSwapInterval = Emscripten_GLES_SetSwapInterval; + device->GL_GetSwapInterval = Emscripten_GLES_GetSwapInterval; + device->GL_SwapWindow = Emscripten_GLES_SwapWindow; + device->GL_DeleteContext = Emscripten_GLES_DeleteContext; + device->GL_GetDrawableSize = Emscripten_GLES_GetDrawableSize; + + device->free = Emscripten_DeleteDevice; + + return device; +} + +VideoBootStrap Emscripten_bootstrap = { + EMSCRIPTENVID_DRIVER_NAME, "SDL emscripten video driver", + Emscripten_Available, Emscripten_CreateDevice +}; + + +int +Emscripten_VideoInit(_THIS) +{ + SDL_DisplayMode mode; + double css_w, css_h; + + /* Use a fake 32-bpp desktop mode */ + mode.format = SDL_PIXELFORMAT_RGB888; + + emscripten_get_element_css_size(NULL, &css_w, &css_h); + + mode.w = css_w; + mode.h = css_h; + + mode.refresh_rate = 0; + mode.driverdata = NULL; + if (SDL_AddBasicVideoDisplay(&mode) < 0) { + return -1; + } + + SDL_zero(mode); + SDL_AddDisplayMode(&_this->displays[0], &mode); + + Emscripten_InitMouse(); + + /* We're done! */ + return 0; +} + +static int +Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) +{ + /* can't do this */ + return 0; +} + +static void +Emscripten_VideoQuit(_THIS) +{ + Emscripten_FiniMouse(); +} + +static void +Emscripten_PumpEvents(_THIS) +{ + /* do nothing. */ +} + +static int +Emscripten_CreateWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *wdata; + double scaled_w, scaled_h; + double css_w, css_h; + + /* Allocate window internal data */ + wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); + if (wdata == NULL) { + return SDL_OutOfMemory(); + } + + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + wdata->pixel_ratio = emscripten_get_device_pixel_ratio(); + } else { + wdata->pixel_ratio = 1.0f; + } + + scaled_w = SDL_floor(window->w * wdata->pixel_ratio); + scaled_h = SDL_floor(window->h * wdata->pixel_ratio); + + emscripten_set_canvas_size(scaled_w, scaled_h); + + emscripten_get_element_css_size(NULL, &css_w, &css_h); + + wdata->external_size = css_w != scaled_w || css_h != scaled_h; + + if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) { + /* external css has resized us */ + scaled_w = css_w * wdata->pixel_ratio; + scaled_h = css_h * wdata->pixel_ratio; + + emscripten_set_canvas_size(scaled_w, scaled_h); + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, css_w, css_h); + } + + /* if the size is not being controlled by css, we need to scale down for hidpi */ + if (!wdata->external_size) { + if (wdata->pixel_ratio != 1.0f) { + /*scale canvas down*/ + emscripten_set_element_css_size(NULL, window->w, window->h); + } + } + + wdata->windowed_width = scaled_w; + wdata->windowed_height = scaled_h; + + if (window->flags & SDL_WINDOW_OPENGL) { + if (!_this->egl_data) { + if (SDL_GL_LoadLibrary(NULL) < 0) { + return -1; + } + } + wdata->egl_surface = SDL_EGL_CreateSurface(_this, 0); + + if (wdata->egl_surface == EGL_NO_SURFACE) { + return SDL_SetError("Could not create GLES window surface"); + } + } + + wdata->window = window; + + /* Setup driver data for this window */ + window->driverdata = wdata; + + /* One window, it always has focus */ + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + + Emscripten_RegisterEventHandlers(wdata); + + /* Window has been successfully created */ + return 0; +} + +static void Emscripten_SetWindowSize(_THIS, SDL_Window * window) +{ + SDL_WindowData *data; + + if (window->driverdata) { + data = (SDL_WindowData *) window->driverdata; + emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio); + + /*scale canvas down*/ + if (!data->external_size && data->pixel_ratio != 1.0f) { + emscripten_set_element_css_size(NULL, window->w, window->h); + } + } +} + +static void +Emscripten_DestroyWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *data; + + if(window->driverdata) { + data = (SDL_WindowData *) window->driverdata; + + Emscripten_UnregisterEventHandlers(data); + if (data->egl_surface != EGL_NO_SURFACE) { + SDL_EGL_DestroySurface(_this, data->egl_surface); + data->egl_surface = EGL_NO_SURFACE; + } + SDL_free(window->driverdata); + window->driverdata = NULL; + } +} + +static void +Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) +{ + SDL_WindowData *data; + if(window->driverdata) { + data = (SDL_WindowData *) window->driverdata; + + if(fullscreen) { + data->requested_fullscreen_mode = window->flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN); + /*unset the fullscreen flags as we're not actually fullscreen yet*/ + window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN); + + EM_ASM({ + //reparent canvas (similar to Module.requestFullscreen) + var canvas = Module['canvas']; + if(canvas.parentNode.id != "SDLFullscreenElement") { + var canvasContainer = document.createElement("div"); + canvasContainer.id = "SDLFullscreenElement"; + canvas.parentNode.insertBefore(canvasContainer, canvas); + canvasContainer.appendChild(canvas); + } + }); + + int is_fullscreen; + emscripten_get_canvas_size(&data->windowed_width, &data->windowed_height, &is_fullscreen); + emscripten_request_fullscreen("SDLFullscreenElement", 1); + } + else + emscripten_exit_fullscreen(); + } +} + +#endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/emscripten/SDL_emscriptenvideo.h b/src/video/emscripten/SDL_emscriptenvideo.h new file mode 100644 index 000000000..16ad3854b --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenvideo.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef _SDL_emscriptenvideo_h +#define _SDL_emscriptenvideo_h + +#include "../SDL_sysvideo.h" +#include +#include + +#include + +typedef struct SDL_WindowData +{ +#if SDL_VIDEO_OPENGL_EGL + EGLSurface egl_surface; +#endif + SDL_Window *window; + SDL_Surface *surface; + + int windowed_width; + int windowed_height; + + float pixel_ratio; + + SDL_bool external_size; + + int requested_fullscreen_mode; +} SDL_WindowData; + +#endif /* _SDL_emscriptenvideo_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/mir/SDL_mirevents.c b/src/video/mir/SDL_mirevents.c index b5829c7c7..76870d5a4 100644 --- a/src/video/mir/SDL_mirevents.c +++ b/src/video/mir/SDL_mirevents.c @@ -137,7 +137,7 @@ HandleTouchMotion(int device_id, int source_id, float x, float y, float pressure static void HandleMouseScroll(SDL_Window* sdl_window, int hscroll, int vscroll) { - SDL_SendMouseWheel(sdl_window, 0, hscroll, vscroll); + SDL_SendMouseWheel(sdl_window, 0, hscroll, vscroll, SDL_MOUSEWHEEL_NORMAL); } static void diff --git a/src/video/nacl/SDL_naclevents.c b/src/video/nacl/SDL_naclevents.c index 5a4449a49..ebdbbfa22 100644 --- a/src/video/nacl/SDL_naclevents.c +++ b/src/video/nacl/SDL_naclevents.c @@ -20,6 +20,8 @@ */ #include "../../SDL_internal.h" +#if SDL_VIDEO_DRIVER_NACL + #include "SDL.h" #include "../../events/SDL_sysevents.h" #include "../../events/SDL_events_c.h" @@ -357,7 +359,7 @@ void NACL_PumpEvents(_THIS) { case PP_INPUTEVENT_TYPE_WHEEL: /* FIXME: GetTicks provides high resolution scroll events */ fp = driverdata->ppb_wheel_input_event->GetDelta(event); - SDL_SendMouseWheel(mouse->focus, mouse->mouseID, (int) fp.x, (int) fp.y); + SDL_SendMouseWheel(mouse->focus, mouse->mouseID, (int) fp.x, (int) fp.y, SDL_MOUSEWHEEL_NORMAL); break; case PP_INPUTEVENT_TYPE_MOUSEENTER: @@ -430,3 +432,7 @@ void NACL_PumpEvents(_THIS) { } } } + +#endif /* SDL_VIDEO_DRIVER_NACL */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspevents.c b/src/video/psp/SDL_pspevents.c index d096c0616..399566bf6 100644 --- a/src/video/psp/SDL_pspevents.c +++ b/src/video/psp/SDL_pspevents.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_PSP /* Being a null driver, there's no event stream. We just define stubs for most of the API. */ @@ -282,3 +285,6 @@ void PSP_EventQuit(_THIS) /* end of SDL_pspevents.c ... */ +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspgl.c b/src/video/psp/SDL_pspgl.c index d24e72292..61620de38 100644 --- a/src/video/psp/SDL_pspgl.c +++ b/src/video/psp/SDL_pspgl.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_PSP #include #include @@ -203,3 +206,6 @@ PSP_GL_DeleteContext(_THIS, SDL_GLContext context) return; } +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspmouse.c b/src/video/psp/SDL_pspmouse.c index 8df3d614e..0c8f5a428 100644 --- a/src/video/psp/SDL_pspmouse.c +++ b/src/video/psp/SDL_pspmouse.c @@ -18,7 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ +#include "../../SDL_internal.h" +#if SDL_VIDEO_DRIVER_PSP #include @@ -33,3 +35,7 @@ struct WMcursor { int unused; }; + +#endif /* SDL_VIDEO_DRIVER_PSP */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/psp/SDL_pspvideo.c b/src/video/psp/SDL_pspvideo.c index b3787239c..61244093c 100644 --- a/src/video/psp/SDL_pspvideo.c +++ b/src/video/psp/SDL_pspvideo.c @@ -66,7 +66,7 @@ PSP_Create() SDL_GLDriverData *gldata; int status; - /* Check if pandora could be initialized */ + /* Check if PSP could be initialized */ status = PSP_Available(); if (status == 0) { /* PSP could not be used */ @@ -80,7 +80,7 @@ PSP_Create() return NULL; } - /* Initialize internal Pandora specific data */ + /* Initialize internal PSP specific data */ phdata = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); if (phdata == NULL) { SDL_OutOfMemory(); diff --git a/src/video/psp/SDL_pspvideo.h b/src/video/psp/SDL_pspvideo.h index 2e1bb241b..cb25b57d0 100644 --- a/src/video/psp/SDL_pspvideo.h +++ b/src/video/psp/SDL_pspvideo.h @@ -19,8 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef __SDL_PANDORA_H__ -#define __SDL_PANDORA_H__ +#ifndef _SDL_pspvideo_h +#define _SDL_pspvideo_h #include @@ -97,6 +97,6 @@ void PSP_ShowScreenKeyboard(_THIS, SDL_Window *window); void PSP_HideScreenKeyboard(_THIS, SDL_Window *window); SDL_bool PSP_IsScreenKeyboardShown(_THIS, SDL_Window *window); -#endif /* __SDL_PANDORA_H__ */ +#endif /* _SDL_pspvideo_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitappdelegate.h b/src/video/uikit/SDL_uikitappdelegate.h index d5430beb1..45dd91e40 100644 --- a/src/video/uikit/SDL_uikitappdelegate.h +++ b/src/video/uikit/SDL_uikitappdelegate.h @@ -21,12 +21,21 @@ #import -@interface SDLUIKitDelegate : NSObject { -} +@interface SDLLaunchScreenController : UIViewController -+ (id) sharedAppDelegate; +- (instancetype)init; +- (void)loadView; +- (NSUInteger)supportedInterfaceOrientations; + +@end + +@interface SDLUIKitDelegate : NSObject + ++ (id)sharedAppDelegate; + (NSString *)getAppDelegateClassName; +- (void)hideLaunchScreen; + @end /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitappdelegate.m b/src/video/uikit/SDL_uikitappdelegate.m index f112672ab..19f510e0b 100644 --- a/src/video/uikit/SDL_uikitappdelegate.m +++ b/src/video/uikit/SDL_uikitappdelegate.m @@ -28,8 +28,10 @@ #include "SDL_system.h" #include "SDL_main.h" -#include "SDL_uikitappdelegate.h" -#include "SDL_uikitmodes.h" +#import "SDL_uikitappdelegate.h" +#import "SDL_uikitmodes.h" +#import "SDL_uikitwindow.h" + #include "../../events/SDL_events_c.h" #ifdef main @@ -39,12 +41,10 @@ static int forward_argc; static char **forward_argv; static int exit_status; -static UIWindow *launch_window; int main(int argc, char **argv) { int i; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; /* store arguments */ forward_argc = argc; @@ -56,7 +56,9 @@ int main(int argc, char **argv) forward_argv[i] = NULL; /* Give over control to run loop, SDLUIKitDelegate will handle most things from here */ - UIApplicationMain(argc, argv, NULL, [SDLUIKitDelegate getAppDelegateClassName]); + @autoreleasepool { + UIApplicationMain(argc, argv, nil, [SDLUIKitDelegate getAppDelegateClassName]); + } /* free the memory we used to hold copies of argc and argv */ for (i = 0; i < forward_argc; i++) { @@ -64,7 +66,6 @@ int main(int argc, char **argv) } free(forward_argv); - [pool release]; return exit_status; } @@ -75,224 +76,291 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa [UIApplication sharedApplication].idleTimerDisabled = disable; } +/* Load a launch image using the old UILaunchImageFile-era naming rules. */ +static UIImage * +SDL_LoadLaunchImageNamed(NSString *name, int screenh) +{ + UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; + UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom; + UIImage *image = nil; -@interface SDL_launchscreenviewcontroller : UIViewController { - + if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) { + /* The image name for the iPhone 5 uses its height as a suffix. */ + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]]; + } else if (idiom == UIUserInterfaceIdiomPad) { + /* iPad apps can launch in any orientation. */ + if (UIInterfaceOrientationIsLandscape(curorient)) { + if (curorient == UIInterfaceOrientationLandscapeLeft) { + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]]; + } else { + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]]; + } + if (!image) { + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]]; + } + } else { + if (curorient == UIInterfaceOrientationPortraitUpsideDown) { + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]]; + } + if (!image) { + image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]]; + } + } + } + + if (!image) { + image = [UIImage imageNamed:name]; + } + + return image; } -@end +@implementation SDLLaunchScreenController -@implementation SDL_launchscreenviewcontroller - -- (id)init +- (instancetype)init { - self = [super init]; - if (self == nil) { + if (!(self = [super initWithNibName:nil bundle:nil])) { return nil; } - NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; + NSBundle *bundle = [NSBundle mainBundle]; + NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; + BOOL atleastiOS8 = UIKit_IsSystemVersionAtLeast(8.0); - if(launch_screen_name) { - // TODO: If the NIB is not in the bundle, this will throw an exception. We might consider a pre-emptive check, but returning a useless viewcontroller isn't helpful and the check should be outside. - UIView* launch_screen = [[[NSBundle mainBundle] loadNibNamed:launch_screen_name owner:self options:nil] objectAtIndex:0]; - CGSize size = [UIScreen mainScreen].bounds.size; - - CGRect bounds = CGRectMake(0, 0, size.width, size.height); - - [launch_screen setFrame:bounds]; - [self setView:launch_screen]; - [launch_screen release]; + /* Launch screens were added in iOS 8. Otherwise we use launch images. */ + if (screenname && atleastiOS8) { + @try { + self.view = [bundle loadNibNamed:screenname owner:self options:nil][0]; + } + @catch (NSException *exception) { + /* If a launch screen name is specified but it fails to load, iOS + * displays a blank screen rather than falling back to an image. */ + return nil; + } } - + if (!self.view) { + NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; + UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; + NSString *imagename = nil; + UIImage *image = nil; + int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); + int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); + + /* We always want portrait-oriented size, to match UILaunchImageSize. */ + if (screenw > screenh) { + int width = screenw; + screenw = screenh; + screenh = width; + } + + /* Xcode 5 introduced a dictionary of launch images in Info.plist. */ + if (launchimages) { + for (NSDictionary *dict in launchimages) { + UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; + NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"]; + NSString *sizestring = dict[@"UILaunchImageSize"]; + NSString *orientstring = dict[@"UILaunchImageOrientation"]; + + /* Ignore this image if the current version is too low. */ + if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) { + continue; + } + + /* Ignore this image if the size doesn't match. */ + if (sizestring) { + CGSize size = CGSizeFromString(sizestring); + if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) { + continue; + } + } + + if (orientstring) { + if ([orientstring isEqualToString:@"PortraitUpsideDown"]) { + orientmask = UIInterfaceOrientationMaskPortraitUpsideDown; + } else if ([orientstring isEqualToString:@"Landscape"]) { + orientmask = UIInterfaceOrientationMaskLandscape; + } else if ([orientstring isEqualToString:@"LandscapeLeft"]) { + orientmask = UIInterfaceOrientationMaskLandscapeLeft; + } else if ([orientstring isEqualToString:@"LandscapeRight"]) { + orientmask = UIInterfaceOrientationMaskLandscapeRight; + } + } + + /* Ignore this image if the orientation doesn't match. */ + if ((orientmask & (1 << curorient)) == 0) { + continue; + } + + imagename = dict[@"UILaunchImageName"]; + } + + if (imagename) { + image = [UIImage imageNamed:imagename]; + } + } else { + imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; + + if (imagename) { + image = SDL_LoadLaunchImageNamed(imagename, screenh); + } + + if (!image) { + image = SDL_LoadLaunchImageNamed(@"Default", screenh); + } + } + + if (image) { + UIImageView *view = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIImageOrientation imageorient = UIImageOrientationUp; + + /* Bugs observed / workaround tested in iOS 8.3, 7.1, and 6.1. */ + if (UIInterfaceOrientationIsLandscape(curorient)) { + if (atleastiOS8 && image.size.width < image.size.height) { + /* On iOS 8, portrait launch images displayed in forced- + * landscape mode (e.g. a standard Default.png on an iPhone + * when Info.plist only supports landscape orientations) need + * to be rotated to display in the expected orientation. */ + if (curorient == UIInterfaceOrientationLandscapeLeft) { + imageorient = UIImageOrientationRight; + } else if (curorient == UIInterfaceOrientationLandscapeRight) { + imageorient = UIImageOrientationLeft; + } + } else if (!atleastiOS8 && image.size.width > image.size.height) { + /* On iOS 7 and below, landscape launch images displayed in + * landscape mode (e.g. landscape iPad launch images) need + * to be rotated to display in the expected orientation. */ + if (curorient == UIInterfaceOrientationLandscapeLeft) { + imageorient = UIImageOrientationLeft; + } else if (curorient == UIInterfaceOrientationLandscapeRight) { + imageorient = UIImageOrientationRight; + } + } + } + + /* Create the properly oriented image. */ + view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient]; + + self.view = view; + } + } return self; } -- (NSUInteger)supportedInterfaceOrientations +- (void)loadView { - NSUInteger orientationMask = UIInterfaceOrientationMaskAll; - - /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { - orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; - } - return orientationMask; + /* Do nothing. */ } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient +- (BOOL)shouldAutorotate { - NSUInteger orientationMask = [self supportedInterfaceOrientations]; - return (orientationMask & (1 << orient)); -} - -@end - - -@interface SDL_splashviewcontroller : UIViewController { - UIImageView *splash; - UIImage *splashPortrait; - UIImage *splashLandscape; -} - -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation; -@end - -@implementation SDL_splashviewcontroller - -- (id)init -{ - self = [super init]; - if (self == nil) { - return nil; - } - - self->splash = [[UIImageView alloc] init]; - [self setView:self->splash]; - - CGSize size = [UIScreen mainScreen].bounds.size; - float height = SDL_max(size.width, size.height); - /* FIXME: Some where around iOS 7, UILaunchImages in the Info.plist was introduced which explicitly maps image names to devices and orientations. - This gets rid of the hardcoded magic file names and allows more control for OS version, orientation, retina, and device. - But this existing code needs to be modified to look in the Info.plist for each key and act appropriately for the correct iOS version. - But iOS 8 superscedes this process and introduces the LaunchScreen NIB which uses autolayout to handle all orientations and devices. - Since we now have a LaunchScreen solution, this may never get fixed, - but this note is here for anybody trying to debug their program on iOS 7 and doesn't understand why their Info.plist isn't working. - */ - self->splashPortrait = [UIImage imageNamed:[NSString stringWithFormat:@"Default-%dh.png", (int)height]]; - if (!self->splashPortrait) { - self->splashPortrait = [UIImage imageNamed:@"Default.png"]; - } - self->splashLandscape = [UIImage imageNamed:@"Default-Landscape.png"]; - if (!self->splashLandscape && self->splashPortrait) { - self->splashLandscape = [[UIImage alloc] initWithCGImage: self->splashPortrait.CGImage - scale: 1.0 - orientation: UIImageOrientationRight]; - } - if (self->splashPortrait) { - [self->splashPortrait retain]; - } - if (self->splashLandscape) { - [self->splashLandscape retain]; - } - - [self updateSplashImage:[[UIApplication sharedApplication] statusBarOrientation]]; - - return self; + /* If YES, the launch image will be incorrectly rotated in some cases. */ + return NO; } - (NSUInteger)supportedInterfaceOrientations { - NSUInteger orientationMask = UIInterfaceOrientationMaskAll; - - /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { - orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; - } - return orientationMask; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient -{ - NSUInteger orientationMask = [self supportedInterfaceOrientations]; - return (orientationMask & (1 << orient)); -} - -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration -{ - [self updateSplashImage:interfaceOrientation]; -} - -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation -{ - UIImage *image; - - if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) { - image = self->splashLandscape; - } else { - image = self->splashPortrait; - } - if (image) - { - splash.image = image; - } + /* We keep the supported orientations unrestricted to avoid the case where + * there are no common orientations between the ones set in Info.plist and + * the ones set here (it will cause an exception in that case.) */ + return UIInterfaceOrientationMaskAll; } @end - -@implementation SDLUIKitDelegate +@implementation SDLUIKitDelegate { + UIWindow *launchWindow; +} /* convenience method */ -+ (id) sharedAppDelegate ++ (id)sharedAppDelegate { - /* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */ - return [[UIApplication sharedApplication] delegate]; + /* the delegate is set in UIApplicationMain(), which is guaranteed to be + * called before this method */ + return [UIApplication sharedApplication].delegate; } + (NSString *)getAppDelegateClassName { - /* subclassing notice: when you subclass this appdelegate, make sure to add a category to override - this method and return the actual name of the delegate */ + /* subclassing notice: when you subclass this appdelegate, make sure to add + * a category to override this method and return the actual name of the + * delegate */ return @"SDLUIKitDelegate"; } -- (id)init +- (void)hideLaunchScreen { - self = [super init]; - return self; + UIWindow *window = launchWindow; + + if (!window || window.hidden) { + return; + } + + launchWindow = nil; + + /* Do a nice animated fade-out (roughly matches the real launch behavior.) */ + [UIView animateWithDuration:0.2 animations:^{ + window.alpha = 0.0; + } completion:^(BOOL finished) { + window.hidden = YES; + }]; } - (void)postFinishLaunch { + /* Hide the launch screen the next time the run loop is run. SDL apps will + * have a chance to load resources while the launch screen is still up. */ + [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; + /* run the user's application, passing argc and argv */ SDL_iPhoneSetEventPump(SDL_TRUE); exit_status = SDL_main(forward_argc, forward_argv); SDL_iPhoneSetEventPump(SDL_FALSE); - /* If we showed a splash image, clean it up */ - if (launch_window) { - [launch_window release]; - launch_window = NULL; + if (launchWindow) { + launchWindow.hidden = YES; + launchWindow = nil; } /* exit, passing the return status from the user's application */ - /* We don't actually exit to support applications that do setup in - * their main function and then allow the Cocoa event loop to run. - */ + /* We don't actually exit to support applications that do setup in their + * main function and then allow the Cocoa event loop to run. */ /* exit(exit_status); */ } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - /* Keep the launch image up until we set a video mode */ - launch_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + NSBundle *bundle = [NSBundle mainBundle]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - /* iOS 8 introduces LaunchScreen NIBs which use autolayout to handle all devices and orientations with a single NIB instead of multiple launch images. - This is also the only way to get the App Store badge "Optimized for iPhone 6 and iPhone 6 Plus". - So if the application is running on iOS 8 or greater AND has specified a LaunchScreen in their Info.plist, we should use the LaunchScreen NIB. - Otherwise, we should fallback to the legacy behavior of launch screen images. - */ - NSString* launch_screen_name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; - if( ([[UIDevice currentDevice].systemVersion intValue] >= 8) && (nil != launch_screen_name) ) { - // iOS 8.0 and above uses LaunchScreen.xib - SDL_launchscreenviewcontroller* launch_screen_view_controller = [[SDL_launchscreenviewcontroller alloc] init]; - launch_window.rootViewController = launch_screen_view_controller; - [launch_window addSubview:launch_screen_view_controller.view]; - [launch_window makeKeyAndVisible]; - } else { - // Anything less than iOS 8.0 +#if SDL_IPHONE_LAUNCHSCREEN + /* The normal launch screen is displayed until didFinishLaunching returns, + * but SDL_main is called after that happens and there may be a noticeable + * delay between the start of SDL_main and when the first real frame is + * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is + * called), so we show the launch screen programmatically until the first + * time events are pumped. */ + UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init]; - UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init]; - launch_window.rootViewController = splashViewController; - [launch_window addSubview:splashViewController.view]; - [launch_window makeKeyAndVisible]; + if (viewcontroller.view) { + launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + + /* We don't want the launch window immediately hidden when a real SDL + * window is shown - we fade it out ourselves when we're ready. */ + launchWindow.windowLevel = UIWindowLevelNormal + 1.0; + + /* Show the window but don't make it key. Events should always go to + * other windows when possible. */ + launchWindow.hidden = NO; + + launchWindow.rootViewController = viewcontroller; } +#endif /* Set working directory to resource path */ - [[NSFileManager defaultManager] changeCurrentDirectoryPath: [[NSBundle mainBundle] resourcePath]]; + [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]]; /* register a callback for the idletimer hint */ SDL_AddHintCallback(SDL_HINT_IDLE_TIMER_DISABLED, @@ -314,7 +382,35 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa SDL_SendAppEvent(SDL_APP_LOWMEMORY); } -- (void) applicationWillResignActive:(UIApplication*)application +- (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation +{ + BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation); + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + + if (_this && _this->num_displays > 0) { + SDL_DisplayMode *desktopmode = &_this->displays[0].desktop_mode; + SDL_DisplayMode *currentmode = &_this->displays[0].current_mode; + + /* The desktop display mode should be kept in sync with the screen + * orientation so that updating a window's fullscreen state to + * SDL_WINDOW_FULLSCREEN_DESKTOP keeps the window dimensions in the + * correct orientation. */ + if (isLandscape != (desktopmode->w > desktopmode->h)) { + int height = desktopmode->w; + desktopmode->w = desktopmode->h; + desktopmode->h = height; + } + + /* Same deal with the current mode + SDL_GetCurrentDisplayMode. */ + if (isLandscape != (currentmode->w > currentmode->h)) { + int height = currentmode->w; + currentmode->w = currentmode->h; + currentmode->h = height; + } + } +} + +- (void)applicationWillResignActive:(UIApplication*)application { SDL_VideoDevice *_this = SDL_GetVideoDevice(); if (_this) { @@ -327,17 +423,17 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); } -- (void) applicationDidEnterBackground:(UIApplication*)application +- (void)applicationDidEnterBackground:(UIApplication*)application { SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); } -- (void) applicationWillEnterForeground:(UIApplication*)application +- (void)applicationWillEnterForeground:(UIApplication*)application { SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); } -- (void) applicationDidBecomeActive:(UIApplication*)application +- (void)applicationDidBecomeActive:(UIApplication*)application { SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); @@ -353,11 +449,11 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { - NSURL *fileURL = [url filePathURL]; + NSURL *fileURL = url.filePathURL; if (fileURL != nil) { - SDL_SendDropFile([[fileURL path] UTF8String]); + SDL_SendDropFile([fileURL.path UTF8String]); } else { - SDL_SendDropFile([[url absoluteString] UTF8String]); + SDL_SendDropFile([url.absoluteString UTF8String]); } return YES; } diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 94fba878b..48bb1bd56 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -40,8 +40,9 @@ SDL_iPhoneSetEventPump(SDL_bool enabled) void UIKit_PumpEvents(_THIS) { - if (!UIKit_EventPumpEnabled) + if (!UIKit_EventPumpEnabled) { return; + } /* Let the run loop run for a short amount of time: long enough for touch events to get processed (which is important to get certain diff --git a/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index c24f3ff8b..f540f0c5c 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -30,35 +30,20 @@ static SDL_bool s_showingMessageBox = SDL_FALSE; -@interface UIKit_UIAlertViewDelegate : NSObject { -@private - int *clickedButtonIndex; -} +@interface SDLAlertViewDelegate : NSObject -- (id)initWithButtonIndex:(int *)_buttonIndex; -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex; +@property (nonatomic, assign) int clickedIndex; @end -@implementation UIKit_UIAlertViewDelegate +@implementation SDLAlertViewDelegate -- (id)initWithButtonIndex:(int *)buttonIndex +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - self = [self init]; - if (self == nil) { - return nil; - } - self->clickedButtonIndex = buttonIndex; - - return self; + _clickedIndex = (int)buttonIndex; } -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex; -{ - *clickedButtonIndex = (int)buttonIndex; -} - -@end /* UIKit_UIAlertViewDelegate */ +@end SDL_bool @@ -70,42 +55,39 @@ UIKit_ShowingMessageBox() int UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) { - int clicked; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - UIAlertView* alert = [[UIAlertView alloc] init]; - - alert.title = [NSString stringWithUTF8String:messageboxdata->title]; - alert.message = [NSString stringWithUTF8String:messageboxdata->message]; - alert.delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked]; - - const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; int i; - for (i = 0; i < messageboxdata->numbuttons; ++i) { - [alert addButtonWithTitle:[[NSString alloc] initWithUTF8String:buttons[i].text]]; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + + @autoreleasepool { + UIAlertView *alert = [[UIAlertView alloc] init]; + SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; + + alert.delegate = delegate; + alert.title = @(messageboxdata->title); + alert.message = @(messageboxdata->message); + + for (i = 0; i < messageboxdata->numbuttons; ++i) { + [alert addButtonWithTitle:@(buttons[i].text)]; + } + + /* Set up for showing the alert */ + delegate.clickedIndex = messageboxdata->numbuttons; + + [alert show]; + + /* Run the main event loop until the alert has finished */ + /* Note that this needs to be done on the main thread */ + s_showingMessageBox = SDL_TRUE; + while (delegate.clickedIndex == messageboxdata->numbuttons) { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } + s_showingMessageBox = SDL_FALSE; + + *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid; + + alert.delegate = nil; } - /* Set up for showing the alert */ - clicked = messageboxdata->numbuttons; - - [alert show]; - - /* Run the main event loop until the alert has finished */ - /* Note that this needs to be done on the main thread */ - s_showingMessageBox = SDL_TRUE; - while (clicked == messageboxdata->numbuttons) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; - } - s_showingMessageBox = SDL_FALSE; - - *buttonid = messageboxdata->buttons[clicked].buttonid; - - [alert.delegate release]; - [alert release]; - - [pool release]; - return 0; } diff --git a/src/video/uikit/SDL_uikitmodes.h b/src/video/uikit/SDL_uikitmodes.h index 9f2e9dd34..65c185ff8 100644 --- a/src/video/uikit/SDL_uikitmodes.h +++ b/src/video/uikit/SDL_uikitmodes.h @@ -25,17 +25,17 @@ #include "SDL_uikitvideo.h" -typedef struct -{ - UIScreen *uiscreen; - CGFloat scale; -} SDL_DisplayData; +@interface SDL_DisplayData : NSObject -typedef struct -{ - UIScreenMode *uiscreenmode; - CGFloat scale; -} SDL_DisplayModeData; +@property (nonatomic, strong) UIScreen *uiscreen; + +@end + +@interface SDL_DisplayModeData : NSObject + +@property (nonatomic, strong) UIScreenMode *uiscreenmode; + +@end extern SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen); diff --git a/src/video/uikit/SDL_uikitmodes.m b/src/video/uikit/SDL_uikitmodes.m index 05e33d9c9..1fb9a03c7 100644 --- a/src/video/uikit/SDL_uikitmodes.m +++ b/src/video/uikit/SDL_uikitmodes.m @@ -25,27 +25,36 @@ #include "SDL_assert.h" #include "SDL_uikitmodes.h" +@implementation SDL_DisplayData + +@synthesize uiscreen; + +@end + +@implementation SDL_DisplayModeData + +@synthesize uiscreenmode; + +@end + static int UIKit_AllocateDisplayModeData(SDL_DisplayMode * mode, - UIScreenMode * uiscreenmode, CGFloat scale) + UIScreenMode * uiscreenmode) { - SDL_DisplayModeData *data = NULL; + SDL_DisplayModeData *data = nil; if (uiscreenmode != nil) { /* Allocate the display mode data */ - data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); + data = [[SDL_DisplayModeData alloc] init]; if (!data) { return SDL_OutOfMemory(); } - data->uiscreenmode = uiscreenmode; - [data->uiscreenmode retain]; - - data->scale = scale; + data.uiscreenmode = uiscreenmode; } - mode->driverdata = data; + mode->driverdata = (void *) CFBridgingRetain(data); return 0; } @@ -54,23 +63,21 @@ static void UIKit_FreeDisplayModeData(SDL_DisplayMode * mode) { if (mode->driverdata != NULL) { - SDL_DisplayModeData *data = (SDL_DisplayModeData *)mode->driverdata; - [data->uiscreenmode release]; - SDL_free(data); + CFRelease(mode->driverdata); mode->driverdata = NULL; } } static int UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h, - UIScreenMode * uiscreenmode, CGFloat scale) + UIScreenMode * uiscreenmode) { SDL_DisplayMode mode; SDL_zero(mode); mode.format = SDL_PIXELFORMAT_ABGR8888; mode.refresh_rate = 0; - if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) { + if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) { return -1; } @@ -85,16 +92,16 @@ UIKit_AddSingleDisplayMode(SDL_VideoDisplay * display, int w, int h, } static int -UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale, +UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, UIScreenMode * uiscreenmode, SDL_bool addRotation) { - if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode, scale) < 0) { + if (UIKit_AddSingleDisplayMode(display, w, h, uiscreenmode) < 0) { return -1; } if (addRotation) { /* Add the rotated version */ - if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode, scale) < 0) { + if (UIKit_AddSingleDisplayMode(display, h, w, uiscreenmode) < 0) { return -1; } } @@ -105,7 +112,7 @@ UIKit_AddDisplayMode(SDL_VideoDisplay * display, int w, int h, CGFloat scale, static int UIKit_AddDisplay(UIScreen *uiscreen) { - CGSize size = [uiscreen bounds].size; + CGSize size = uiscreen.bounds.size; /* Make sure the width/height are oriented correctly */ if (UIKit_IsDisplayLandscape(uiscreen) != (size.width > size.height)) { @@ -114,24 +121,16 @@ UIKit_AddDisplay(UIScreen *uiscreen) size.height = height; } - /* When dealing with UIKit all coordinates are specified in terms of - * what Apple refers to as points. [UIScreen scale] indicates the - * relationship between points and pixels. Since SDL has no notion - * of points, we must compensate in all cases where dealing with such - * units. - */ - CGFloat scale = [uiscreen scale]; - SDL_VideoDisplay display; SDL_DisplayMode mode; SDL_zero(mode); mode.format = SDL_PIXELFORMAT_ABGR8888; - mode.w = (int)(size.width * scale); - mode.h = (int)(size.height * scale); + mode.w = (int) size.width; + mode.h = (int) size.height; - UIScreenMode * uiscreenmode = [uiscreen currentMode]; + UIScreenMode *uiscreenmode = uiscreen.currentMode; - if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode, scale) < 0) { + if (UIKit_AllocateDisplayModeData(&mode, uiscreenmode) < 0) { return -1; } @@ -140,17 +139,15 @@ UIKit_AddDisplay(UIScreen *uiscreen) display.current_mode = mode; /* Allocate the display data */ - SDL_DisplayData *data = (SDL_DisplayData *) SDL_malloc(sizeof(*data)); + SDL_DisplayData *data = [[SDL_DisplayData alloc] init]; if (!data) { UIKit_FreeDisplayModeData(&display.desktop_mode); return SDL_OutOfMemory(); } - [uiscreen retain]; - data->uiscreen = uiscreen; - data->scale = scale; + data.uiscreen = uiscreen; - display.driverdata = data; + display.driverdata = (void *) CFBridgingRetain(data); SDL_AddVideoDisplay(&display); return 0; @@ -160,9 +157,9 @@ SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen) { if (uiscreen == [UIScreen mainScreen]) { - return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]); + return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); } else { - CGSize size = [uiscreen bounds].size; + CGSize size = uiscreen.bounds.size; return (size.width > size.height); } } @@ -170,9 +167,11 @@ UIKit_IsDisplayLandscape(UIScreen *uiscreen) int UIKit_InitModes(_THIS) { - for (UIScreen *uiscreen in [UIScreen screens]) { - if (UIKit_AddDisplay(uiscreen) < 0) { - return -1; + @autoreleasepool { + for (UIScreen *uiscreen in [UIScreen screens]) { + if (UIKit_AddDisplay(uiscreen) < 0) { + return -1; + } } } @@ -182,34 +181,35 @@ UIKit_InitModes(_THIS) void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; + @autoreleasepool { + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; - SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen); - SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]); + SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen); + SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]); + CGFloat scale = data.uiscreen.scale; - for (UIScreenMode *uimode in [data->uiscreen availableModes]) { - CGSize size = [uimode size]; - int w = (int)size.width; - int h = (int)size.height; - - /* Make sure the width/height are oriented correctly */ - if (isLandscape != (w > h)) { - int tmp = w; - w = h; - h = tmp; +#ifdef __IPHONE_8_0 + /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than + * 1242x2208 (414x736@3x), so we should use the native scale. */ + if ([data.uiscreen respondsToSelector:@selector(nativeScale)]) { + scale = data.uiscreen.nativeScale; } +#endif - /* Add the native screen resolution. */ - UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation); + for (UIScreenMode *uimode in data.uiscreen.availableModes) { + /* The size of a UIScreenMode is in pixels, but we deal exclusively + * in points (except in SDL_GL_GetDrawableSize.) */ + int w = (int)(uimode.size.width / scale); + int h = (int)(uimode.size.height / scale); - if (data->scale != 1.0f) { - /* Add the native screen resolution divided by its scale. - * This is so devices capable of e.g. 640x960 also advertise 320x480. - */ - UIKit_AddDisplayMode(display, - (int)(size.width / data->scale), - (int)(size.height / data->scale), - 1.0f, uimode, addRotation); + /* Make sure the width/height are oriented correctly */ + if (isLandscape != (w > h)) { + int tmp = w; + w = h; + h = tmp; + } + + UIKit_AddDisplayMode(display, w, h, uimode, addRotation); } } } @@ -217,19 +217,24 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; + @autoreleasepool { + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata; - [data->uiscreen setCurrentMode:modedata->uiscreenmode]; + [data.uiscreen setCurrentMode:modedata.uiscreenmode]; - if (data->uiscreen == [UIScreen mainScreen]) { - if (mode->w > mode->h) { - if (!UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO]; - } - } else if (mode->w < mode->h) { - if (UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO]; + if (data.uiscreen == [UIScreen mainScreen]) { + /* [UIApplication setStatusBarOrientation:] no longer works reliably + * in recent iOS versions, so we can't rotate the screen when setting + * the display mode. */ + if (mode->w > mode->h) { + if (!UIKit_IsDisplayLandscape(data.uiscreen)) { + return SDL_SetError("Screen orientation does not match display mode size"); + } + } else if (mode->w < mode->h) { + if (UIKit_IsDisplayLandscape(data.uiscreen)) { + return SDL_SetError("Screen orientation does not match display mode size"); + } } } } @@ -242,19 +247,21 @@ UIKit_QuitModes(_THIS) { /* Release Objective-C objects, so higher level doesn't free() them. */ int i, j; - for (i = 0; i < _this->num_displays; i++) { - SDL_VideoDisplay *display = &_this->displays[i]; + @autoreleasepool { + for (i = 0; i < _this->num_displays; i++) { + SDL_VideoDisplay *display = &_this->displays[i]; - UIKit_FreeDisplayModeData(&display->desktop_mode); - for (j = 0; j < display->num_display_modes; j++) { - SDL_DisplayMode *mode = &display->display_modes[j]; - UIKit_FreeDisplayModeData(mode); + UIKit_FreeDisplayModeData(&display->desktop_mode); + for (j = 0; j < display->num_display_modes; j++) { + SDL_DisplayMode *mode = &display->display_modes[j]; + UIKit_FreeDisplayModeData(mode); + } + + if (display->driverdata != NULL) { + CFRelease(display->driverdata); + display->driverdata = NULL; + } } - - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - [data->uiscreen release]; - SDL_free(data); - display->driverdata = NULL; } } diff --git a/src/video/uikit/SDL_uikitopengles.h b/src/video/uikit/SDL_uikitopengles.h index 947678cae..f16918935 100644 --- a/src/video/uikit/SDL_uikitopengles.h +++ b/src/video/uikit/SDL_uikitopengles.h @@ -25,6 +25,8 @@ extern int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); +extern void UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window, + int * w, int * h); extern void UIKit_GL_SwapWindow(_THIS, SDL_Window * window); extern SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window); extern void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context); diff --git a/src/video/uikit/SDL_uikitopengles.m b/src/video/uikit/SDL_uikitopengles.m index 8d71ee818..0184cf758 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -23,10 +23,10 @@ #if SDL_VIDEO_DRIVER_UIKIT #include "SDL_uikitopengles.h" -#include "SDL_uikitopenglview.h" -#include "SDL_uikitappdelegate.h" +#import "SDL_uikitopenglview.h" #include "SDL_uikitmodes.h" #include "SDL_uikitwindow.h" +#include "SDL_uikitevents.h" #include "../SDL_sysvideo.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" @@ -40,148 +40,147 @@ void * UIKit_GL_GetProcAddress(_THIS, const char *proc) { /* Look through all SO's for the proc symbol. Here's why: - -Looking for the path to the OpenGL Library seems not to work in the iPhone Simulator. - -We don't know that the path won't change in the future. - */ + * -Looking for the path to the OpenGL Library seems not to work in the iOS Simulator. + * -We don't know that the path won't change in the future. */ return dlsym(RTLD_DEFAULT, proc); } /* - note that SDL_GL_Delete context makes it current without passing the window + note that SDL_GL_DeleteContext makes it current without passing the window */ -int UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +int +UIKit_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) { - [EAGLContext setCurrentContext: context]; + @autoreleasepool { + SDLEAGLContext *eaglcontext = (__bridge SDLEAGLContext *) context; + + if (![EAGLContext setCurrentContext:eaglcontext]) { + return SDL_SetError("Could not make EAGL context current"); + } + + if (eaglcontext) { + [eaglcontext.sdlView setSDLWindow:window]; + } + } + return 0; } +void +UIKit_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) +{ + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + UIView *view = data.viewcontroller.view; + if ([view isKindOfClass:[SDL_uikitopenglview class]]) { + SDL_uikitopenglview *glview = (SDL_uikitopenglview *) view; + if (w) { + *w = glview.backingWidth; + } + if (h) { + *h = glview.backingHeight; + } + } + } +} + int UIKit_GL_LoadLibrary(_THIS, const char *path) { - /* - shouldn't be passing a path into this function - why? Because we've already loaded the library - and because the SDK forbids loading an external SO - */ + /* We shouldn't pass a path to this function, since we've already loaded the + * library. */ if (path != NULL) { - return SDL_SetError("iPhone GL Load Library just here for compatibility"); + return SDL_SetError("iOS GL Load Library just here for compatibility"); } return 0; } void UIKit_GL_SwapWindow(_THIS, SDL_Window * window) { + @autoreleasepool { + SDLEAGLContext *context = (__bridge SDLEAGLContext *) SDL_GL_GetCurrentContext(); + #if SDL_POWER_UIKIT - /* Check once a frame to see if we should turn off the battery monitor. */ - SDL_UIKit_UpdateBatteryMonitoring(); + /* Check once a frame to see if we should turn off the battery monitor. */ + SDL_UIKit_UpdateBatteryMonitoring(); #endif - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + [context.sdlView swapBuffers]; - if (nil == data->view) { - return; + /* You need to pump events in order for the OS to make changes visible. + * We don't pump events here because we don't want iOS application events + * (low memory, terminate, etc.) to happen inside low level rendering. */ } - [data->view swapBuffers]; - - /* You need to pump events in order for the OS to make changes visible. - We don't pump events here because we don't want iOS application events - (low memory, terminate, etc.) to happen inside low level rendering. - */ } -SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window) +SDL_GLContext +UIKit_GL_CreateContext(_THIS, SDL_Window * window) { - SDL_uikitopenglview *view; - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - SDL_DisplayData *displaydata = display->driverdata; - SDL_DisplayModeData *displaymodedata = display->current_mode.driverdata; - UIWindow *uiwindow = data->uiwindow; - EAGLSharegroup *share_group = nil; + @autoreleasepool { + SDL_uikitopenglview *view; + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + CGRect frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen); + EAGLSharegroup *sharegroup = nil; + CGFloat scale = 1.0; - if (_this->gl_config.share_with_current_context) { - SDL_uikitopenglview *view = (SDL_uikitopenglview *) SDL_GL_GetCurrentContext(); - share_group = [view.context sharegroup]; - } - - /* construct our view, passing in SDL's OpenGL configuration data */ - CGRect frame; - if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - frame = [displaydata->uiscreen bounds]; - } else { - frame = [displaydata->uiscreen applicationFrame]; - } - view = [[SDL_uikitopenglview alloc] initWithFrame: frame - scale: displaymodedata->scale - retainBacking: _this->gl_config.retained_backing - rBits: _this->gl_config.red_size - gBits: _this->gl_config.green_size - bBits: _this->gl_config.blue_size - aBits: _this->gl_config.alpha_size - depthBits: _this->gl_config.depth_size - stencilBits: _this->gl_config.stencil_size - majorVersion: _this->gl_config.major_version - shareGroup: share_group]; - if (!view) { - return NULL; - } - - data->view = view; - view->viewcontroller = data->viewcontroller; - if (view->viewcontroller != nil) { - [view->viewcontroller setView:view]; - [view->viewcontroller retain]; - } - [uiwindow addSubview: view]; - - /* The view controller needs to be the root in order to control rotation on iOS 6.0 */ - if (uiwindow.rootViewController == nil) { - uiwindow.rootViewController = view->viewcontroller; - } - - EAGLContext *context = view.context; - if (UIKit_GL_MakeCurrent(_this, window, context) < 0) { - UIKit_GL_DeleteContext(_this, context); - return NULL; - } - - /* Make this window the current mouse focus for touch input */ - if (displaydata->uiscreen == [UIScreen mainScreen]) { - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); - } - - return context; -} - -void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context) -{ - SDL_Window *window; - - /* Find the view associated with this context */ - for (window = _this->windows; window; window = window->next) { - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - SDL_uikitopenglview *view = data->view; - if (view.context == context) { - /* the delegate has retained the view, this will release him */ - if (view->viewcontroller) { - UIWindow *uiwindow = (UIWindow *)view.superview; - if (uiwindow.rootViewController == view->viewcontroller) { - uiwindow.rootViewController = nil; - } - [view->viewcontroller setView:nil]; - [view->viewcontroller release]; - } - [view removeFromSuperview]; - - /* FIXME: This doesn't actually call view dealloc - what is holding a reference to it? */ - [view release]; - return; + if (_this->gl_config.share_with_current_context) { + EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); + sharegroup = context.sharegroup; } - } - /* View not found... delete the context anyway? */ - [(EAGLContext *)context release]; + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + /* Set the scale to the natural scale factor of the screen - the + * backing dimensions of the OpenGL view will match the pixel + * dimensions of the screen rather than the dimensions in points. */ +#ifdef __IPHONE_8_0 + if ([data.uiwindow.screen respondsToSelector:@selector(nativeScale)]) { + scale = data.uiwindow.screen.nativeScale; + } else +#endif + { + scale = data.uiwindow.screen.scale; + } + } + + /* construct our view, passing in SDL's OpenGL configuration data */ + view = [[SDL_uikitopenglview alloc] initWithFrame:frame + scale:scale + retainBacking:_this->gl_config.retained_backing + rBits:_this->gl_config.red_size + gBits:_this->gl_config.green_size + bBits:_this->gl_config.blue_size + aBits:_this->gl_config.alpha_size + depthBits:_this->gl_config.depth_size + stencilBits:_this->gl_config.stencil_size + sRGB:_this->gl_config.framebuffer_srgb_capable + majorVersion:_this->gl_config.major_version + shareGroup:sharegroup]; + if (!view) { + return NULL; + } + + SDLEAGLContext *context = view.context; + if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) { + UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context)); + return NULL; + } + + /* We return a +1'd context. The window's driverdata owns the view (via + * MakeCurrent.) */ + return (SDL_GLContext) CFBridgingRetain(context); + } +} + +void +UIKit_GL_DeleteContext(_THIS, SDL_GLContext context) +{ + @autoreleasepool { + /* Transfer ownership the +1'd context to ARC. */ + SDLEAGLContext *eaglcontext = (SDLEAGLContext *) CFBridgingRelease(context); + + /* Detach the context's view from its window. */ + [eaglcontext.sdlView setSDLWindow:NULL]; + } } #endif /* SDL_VIDEO_DRIVER_UIKIT */ diff --git a/src/video/uikit/SDL_uikitopenglview.h b/src/video/uikit/SDL_uikitopenglview.h index eed2e5b70..1dcac28b7 100644 --- a/src/video/uikit/SDL_uikitopenglview.h +++ b/src/video/uikit/SDL_uikitopenglview.h @@ -21,66 +21,48 @@ #import #import -#import -#import +#import + #import "SDL_uikitview.h" -/* - This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. - The view content is basically an EAGL surface you render your OpenGL scene into. - Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. - */ -@interface SDL_uikitopenglview : SDL_uikitview { +#include "SDL_uikitvideo.h" -@private - /* The pixel dimensions of the backbuffer */ - GLint backingWidth; - GLint backingHeight; +@class SDL_uikitopenglview; - EAGLContext *context; +@interface SDLEAGLContext : EAGLContext - /* OpenGL names for the renderbuffer and framebuffers used to render to this view */ - GLuint viewRenderbuffer, viewFramebuffer; +@property (nonatomic, weak) SDL_uikitopenglview *sdlView; - /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ - GLuint depthRenderbuffer; +@end - /* format of depthRenderbuffer */ - GLenum depthBufferFormat; +@interface SDL_uikitopenglview : SDL_uikitview - id displayLink; - int animationInterval; - void (*animationCallback)(void*); - void *animationCallbackParam; -} +- (instancetype)initWithFrame:(CGRect)frame + scale:(CGFloat)scale + retainBacking:(BOOL)retained + rBits:(int)rBits + gBits:(int)gBits + bBits:(int)bBits + aBits:(int)aBits + depthBits:(int)depthBits + stencilBits:(int)stencilBits + sRGB:(BOOL)sRGB + majorVersion:(int)majorVersion + shareGroup:(EAGLSharegroup*)shareGroup; -@property (nonatomic, retain, readonly) EAGLContext *context; +@property (nonatomic, readonly, strong) SDLEAGLContext *context; + +/* The width and height of the drawable in pixels (as opposed to points.) */ +@property (nonatomic, readonly) int backingWidth; +@property (nonatomic, readonly) int backingHeight; + +@property (nonatomic, readonly) GLuint drawableRenderbuffer; +@property (nonatomic, readonly) GLuint drawableFramebuffer; - (void)swapBuffers; - (void)setCurrentContext; -- (id)initWithFrame:(CGRect)frame - scale:(CGFloat)scale - retainBacking:(BOOL)retained - rBits:(int)rBits - gBits:(int)gBits - bBits:(int)bBits - aBits:(int)aBits - depthBits:(int)depthBits - stencilBits:(int)stencilBits - majorVersion:(int)majorVersion - shareGroup:(EAGLSharegroup*)shareGroup; - - (void)updateFrame; -- (void)setAnimationCallback:(int)interval - callback:(void (*)(void*))callback - callbackParam:(void*)callbackParam; - -- (void)startAnimation; -- (void)stopAnimation; - -- (void)doLoop:(CADisplayLink*)sender; - @end /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitopenglview.m b/src/video/uikit/SDL_uikitopenglview.m index 144100bf7..df848f3d5 100644 --- a/src/video/uikit/SDL_uikitopenglview.m +++ b/src/video/uikit/SDL_uikitopenglview.m @@ -22,170 +22,190 @@ #if SDL_VIDEO_DRIVER_UIKIT -#include #include -#include "SDL_uikitopenglview.h" -#include "SDL_uikitmessagebox.h" +#include +#import "SDL_uikitopenglview.h" +#include "SDL_uikitwindow.h" +@implementation SDLEAGLContext -@implementation SDL_uikitopenglview +@end + +@implementation SDL_uikitopenglview { + /* The renderbuffer and framebuffer used to render to this layer. */ + GLuint viewRenderbuffer, viewFramebuffer; + + /* The depth buffer that is attached to viewFramebuffer, if it exists. */ + GLuint depthRenderbuffer; + + /* format of depthRenderbuffer */ + GLenum depthBufferFormat; +} @synthesize context; +@synthesize backingWidth; +@synthesize backingHeight; + (Class)layerClass { return [CAEAGLLayer class]; } -- (id)initWithFrame:(CGRect)frame - scale:(CGFloat)scale - retainBacking:(BOOL)retained - rBits:(int)rBits - gBits:(int)gBits - bBits:(int)bBits - aBits:(int)aBits - depthBits:(int)depthBits - stencilBits:(int)stencilBits - majorVersion:(int)majorVersion - shareGroup:(EAGLSharegroup*)shareGroup +- (instancetype)initWithFrame:(CGRect)frame + scale:(CGFloat)scale + retainBacking:(BOOL)retained + rBits:(int)rBits + gBits:(int)gBits + bBits:(int)bBits + aBits:(int)aBits + depthBits:(int)depthBits + stencilBits:(int)stencilBits + sRGB:(BOOL)sRGB + majorVersion:(int)majorVersion + shareGroup:(EAGLSharegroup*)shareGroup { - depthBufferFormat = 0; - if ((self = [super initWithFrame:frame])) { const BOOL useStencilBuffer = (stencilBits != 0); const BOOL useDepthBuffer = (depthBits != 0); NSString *colorFormat = nil; /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES - versions, and this allows us to handle future OpenGL ES versions. - */ + * versions, and this allows us to handle future OpenGL ES versions. */ EAGLRenderingAPI api = majorVersion; - if (rBits == 8 && gBits == 8 && bBits == 8) { - /* if user specifically requests rbg888 or some color format higher than 16bpp */ - colorFormat = kEAGLColorFormatRGBA8; - } else { - /* default case (faster) */ - colorFormat = kEAGLColorFormatRGB565; - } - - /* Get the layer */ - CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; - - eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil]; - - context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup]; + context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:shareGroup]; if (!context || ![EAGLContext setCurrentContext:context]) { - [self release]; SDL_SetError("OpenGL ES %d not supported", majorVersion); return nil; } + context.sdlView = self; + + if (sRGB) { + /* sRGB EAGL drawable support was added in iOS 7. */ + if (UIKit_IsSystemVersionAtLeast(7.0)) { + colorFormat = kEAGLColorFormatSRGBA8; + } else { + SDL_SetError("sRGB drawables are not supported."); + return nil; + } + } else if (rBits >= 8 || gBits >= 8 || bBits >= 8) { + /* if user specifically requests rbg888 or some color format higher than 16bpp */ + colorFormat = kEAGLColorFormatRGBA8; + } else { + /* default case (potentially faster) */ + colorFormat = kEAGLColorFormatRGB565; + } + + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = YES; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking:@(retained), + kEAGLDrawablePropertyColorFormat:colorFormat + }; + /* Set the appropriate scale (for retina display support) */ self.contentScaleFactor = scale; - /* create the buffers */ - glGenFramebuffersOES(1, &viewFramebuffer); - glGenRenderbuffersOES(1, &viewRenderbuffer); + /* Create the color Renderbuffer Object */ + glGenRenderbuffers(1, &viewRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); + if (![context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]) { + SDL_SetError("Failed to create OpenGL ES drawable"); + return nil; + } - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + /* Create the Framebuffer Object */ + glGenFramebuffers(1, &viewFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, viewFramebuffer); + + /* attach the color renderbuffer to the FBO */ + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, viewRenderbuffer); + + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); if ((useDepthBuffer) || (useStencilBuffer)) { if (useStencilBuffer) { /* Apparently you need to pack stencil and depth into one buffer. */ depthBufferFormat = GL_DEPTH24_STENCIL8_OES; } else if (useDepthBuffer) { - /* iOS only has 24-bit depth buffers, even with GL_DEPTH_COMPONENT16_OES */ + /* iOS only uses 32-bit float (exposed as fixed point 24-bit) + * depth buffers. */ depthBufferFormat = GL_DEPTH_COMPONENT24_OES; } - glGenRenderbuffersOES(1, &depthRenderbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); + glGenRenderbuffers(1, &depthRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight); if (useDepthBuffer) { - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); } if (useStencilBuffer) { - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); } } - if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { - return NO; + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SDL_SetError("Failed creating OpenGL ES framebuffer"); + return nil; } - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - /* end create buffers */ + glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); - self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - self.autoresizesSubviews = YES; + [self setDebugLabels]; } + return self; } +- (GLuint)drawableRenderbuffer +{ + return viewRenderbuffer; +} + +- (GLuint)drawableFramebuffer +{ + return viewFramebuffer; +} + - (void)updateFrame { - glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &viewRenderbuffer); + GLint prevRenderbuffer = 0; + glGetIntegerv(GL_RENDERBUFFER_BINDING, &prevRenderbuffer); - glGenRenderbuffersOES(1, &viewRenderbuffer); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); - [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer]; - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); + [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); if (depthRenderbuffer != 0) { - glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); + glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); + glRenderbufferStorage(GL_RENDERBUFFER, depthBufferFormat, backingWidth, backingHeight); } - glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, prevRenderbuffer); } -- (void)setAnimationCallback:(int)interval - callback:(void (*)(void*))callback - callbackParam:(void*)callbackParam +- (void)setDebugLabels { - [self stopAnimation]; + if (viewFramebuffer != 0) { + glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO"); + } - animationInterval = interval; - animationCallback = callback; - animationCallbackParam = callbackParam; + if (viewRenderbuffer != 0) { + glLabelObjectEXT(GL_RENDERBUFFER, viewRenderbuffer, 0, "context color buffer"); + } - if (animationCallback) - [self startAnimation]; -} - -- (void)startAnimation -{ - displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; - [displayLink setFrameInterval:animationInterval]; - [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; -} - -- (void)stopAnimation -{ - [displayLink invalidate]; - displayLink = nil; -} - -- (void)doLoop:(CADisplayLink*)sender -{ - /* Don't run the game loop while a messagebox is up */ - if (!UIKit_ShowingMessageBox()) { - animationCallback(animationCallbackParam); + if (depthRenderbuffer != 0) { + if (depthBufferFormat == GL_DEPTH24_STENCIL8_OES) { + glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth-stencil buffer"); + } else { + glLabelObjectEXT(GL_RENDERBUFFER, depthRenderbuffer, 0, "context depth buffer"); + } } } @@ -194,44 +214,60 @@ [EAGLContext setCurrentContext:context]; } - - (void)swapBuffers { /* viewRenderbuffer should always be bound here. Code that binds something - else is responsible for rebinding viewRenderbuffer, to reduce - duplicate state changes. */ - [context presentRenderbuffer:GL_RENDERBUFFER_OES]; + * else is responsible for rebinding viewRenderbuffer, to reduce duplicate + * state changes. */ + [context presentRenderbuffer:GL_RENDERBUFFER]; } - - (void)layoutSubviews { - [EAGLContext setCurrentContext:context]; - [self updateFrame]; + [super layoutSubviews]; + + int width = (int) (self.bounds.size.width * self.contentScaleFactor); + int height = (int) (self.bounds.size.height * self.contentScaleFactor); + + /* Update the color and depth buffer storage if the layer size has changed. */ + if (width != backingWidth || height != backingHeight) { + EAGLContext *prevContext = [EAGLContext currentContext]; + if (prevContext != context) { + [EAGLContext setCurrentContext:context]; + } + + [self updateFrame]; + + if (prevContext != context) { + [EAGLContext setCurrentContext:prevContext]; + } + } } - (void)destroyFramebuffer { - glDeleteFramebuffersOES(1, &viewFramebuffer); - viewFramebuffer = 0; - glDeleteRenderbuffersOES(1, &viewRenderbuffer); - viewRenderbuffer = 0; + if (viewFramebuffer != 0) { + glDeleteFramebuffers(1, &viewFramebuffer); + viewFramebuffer = 0; + } - if (depthRenderbuffer) { - glDeleteRenderbuffersOES(1, &depthRenderbuffer); + if (viewRenderbuffer != 0) { + glDeleteRenderbuffers(1, &viewRenderbuffer); + viewRenderbuffer = 0; + } + + if (depthRenderbuffer != 0) { + glDeleteRenderbuffers(1, &depthRenderbuffer); depthRenderbuffer = 0; } } - - (void)dealloc { - [self destroyFramebuffer]; if ([EAGLContext currentContext] == context) { + [self destroyFramebuffer]; [EAGLContext setCurrentContext:nil]; } - [context release]; - [super dealloc]; } @end diff --git a/src/video/uikit/SDL_uikitvideo.h b/src/video/uikit/SDL_uikitvideo.h index ef6298257..dac80a2b3 100644 --- a/src/video/uikit/SDL_uikitvideo.h +++ b/src/video/uikit/SDL_uikitvideo.h @@ -25,20 +25,8 @@ #include "../SDL_sysvideo.h" -#ifndef __IPHONE_6_0 -/* This enum isn't available in older SDKs, but we use it for our own purposes on iOS 5.1 and for the system on iOS 6.0 */ -enum UIInterfaceOrientationMask -{ - UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait), - UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft), - UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight), - UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown), - UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), - UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown), - UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), -}; -#endif /* !__IPHONE_6_0 */ - +BOOL UIKit_IsSystemVersionAtLeast(double version); +CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); #endif /* _SDL_uikitvideo_h */ diff --git a/src/video/uikit/SDL_uikitvideo.m b/src/video/uikit/SDL_uikitvideo.m index 4893bc163..c3448efc7 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -75,15 +75,15 @@ UIKit_CreateDevice(int devindex) device->SetDisplayMode = UIKit_SetDisplayMode; device->PumpEvents = UIKit_PumpEvents; device->CreateWindow = UIKit_CreateWindow; + device->SetWindowTitle = UIKit_SetWindowTitle; device->ShowWindow = UIKit_ShowWindow; device->HideWindow = UIKit_HideWindow; device->RaiseWindow = UIKit_RaiseWindow; + device->SetWindowBordered = UIKit_SetWindowBordered; device->SetWindowFullscreen = UIKit_SetWindowFullscreen; device->DestroyWindow = UIKit_DestroyWindow; device->GetWindowWMInfo = UIKit_GetWindowWMInfo; - /* !!! FIXME: implement SetWindowBordered */ - #if SDL_IPHONE_KEYBOARD device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport; device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard; @@ -93,12 +93,13 @@ UIKit_CreateDevice(int devindex) #endif /* OpenGL (ES) functions */ - device->GL_MakeCurrent = UIKit_GL_MakeCurrent; - device->GL_SwapWindow = UIKit_GL_SwapWindow; + device->GL_MakeCurrent = UIKit_GL_MakeCurrent; + device->GL_GetDrawableSize = UIKit_GL_GetDrawableSize; + device->GL_SwapWindow = UIKit_GL_SwapWindow; device->GL_CreateContext = UIKit_GL_CreateContext; device->GL_DeleteContext = UIKit_GL_DeleteContext; device->GL_GetProcAddress = UIKit_GL_GetProcAddress; - device->GL_LoadLibrary = UIKit_GL_LoadLibrary; + device->GL_LoadLibrary = UIKit_GL_LoadLibrary; device->free = UIKit_DeleteDevice; device->gl_config.accelerated = 1; @@ -129,6 +130,25 @@ UIKit_VideoQuit(_THIS) UIKit_QuitModes(_this); } +BOOL +UIKit_IsSystemVersionAtLeast(double version) +{ + return [[UIDevice currentDevice].systemVersion doubleValue] >= version; +} + +CGRect +UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) +{ + BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0); + + if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) { + /* The view should always show behind the status bar in iOS 7+. */ + return screen.bounds; + } else { + return screen.applicationFrame; + } +} + /* * iOS log support. * diff --git a/src/video/uikit/SDL_uikitview.h b/src/video/uikit/SDL_uikitview.h index ce616c07e..dda94b32e 100644 --- a/src/video/uikit/SDL_uikitview.h +++ b/src/video/uikit/SDL_uikitview.h @@ -20,59 +20,22 @@ */ #import -#import "SDL_uikitviewcontroller.h" + +#include "../SDL_sysvideo.h" #include "SDL_touch.h" -#define IPHONE_TOUCH_EFFICIENT_DANGEROUS +@interface SDL_uikitview : UIView -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS -#define MAX_SIMULTANEOUS_TOUCHES 5 -#endif +- (instancetype)initWithFrame:(CGRect)frame; -#if SDL_IPHONE_KEYBOARD -@interface SDL_uikitview : UIView { -#else -@interface SDL_uikitview : UIView { -#endif +- (void)setSDLWindow:(SDL_Window *)window; - SDL_TouchID touchId; - UITouch *leftFingerDown; -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS - UITouch *finger[MAX_SIMULTANEOUS_TOUCHES]; -#endif - -#if SDL_IPHONE_KEYBOARD - UITextField *textField; - BOOL keyboardVisible; - SDL_Rect textInputRect; - int keyboardHeight; -#endif - -@public - SDL_uikitviewcontroller *viewcontroller; -} - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -#if SDL_IPHONE_KEYBOARD -- (void)showKeyboard; -- (void)hideKeyboard; -- (void)initializeKeyboard; -@property (readonly) BOOL keyboardVisible; -@property (nonatomic,assign) SDL_Rect textInputRect; -@property (nonatomic,assign) int keyboardHeight; - -SDL_bool UIKit_HasScreenKeyboardSupport(_THIS); -void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window); -void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window); -SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window); -void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect); - -#endif - @end /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitview.m b/src/video/uikit/SDL_uikitview.m index c51a3ba71..84d98fe71 100644 --- a/src/video/uikit/SDL_uikitview.m +++ b/src/video/uikit/SDL_uikitview.m @@ -24,438 +24,164 @@ #include "SDL_uikitview.h" -#include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" +#include "../../events/SDL_events_c.h" -#if SDL_IPHONE_KEYBOARD -#include "keyinfotable.h" -#endif -#include "SDL_uikitappdelegate.h" -#include "SDL_uikitmodes.h" -#include "SDL_uikitwindow.h" +#import "SDL_uikitappdelegate.h" +#import "SDL_uikitmodes.h" +#import "SDL_uikitwindow.h" -void _uikit_keyboard_init() ; +@implementation SDL_uikitview { + SDL_Window *sdlwindow; -@implementation SDL_uikitview - -- (void)dealloc -{ - [super dealloc]; + SDL_TouchID touchId; + UITouch * __weak firstFingerDown; } -- (id)initWithFrame:(CGRect)frame +- (instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame: frame]; + if ((self = [super initWithFrame:frame])) { + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.autoresizesSubviews = YES; -#if SDL_IPHONE_KEYBOARD - [self initializeKeyboard]; -#endif + self.multipleTouchEnabled = YES; - self.multipleTouchEnabled = YES; - - touchId = 1; - SDL_AddTouch(touchId, ""); + touchId = 1; + SDL_AddTouch(touchId, ""); + } return self; +} +- (void)setSDLWindow:(SDL_Window *)window +{ + SDL_WindowData *data = nil; + + if (window == sdlwindow) { + return; + } + + if (sdlwindow) { + SDL_uikitview *view = nil; + data = (__bridge SDL_WindowData *) sdlwindow->driverdata; + + [data.views removeObject:self]; + + [self removeFromSuperview]; + + /* Restore the next-oldest view in the old window. */ + if (data.views.count > 0) { + view = data.views[data.views.count - 1]; + } + + data.viewcontroller.view = view; + + data.uiwindow.rootViewController = nil; + data.uiwindow.rootViewController = data.viewcontroller; + + [data.uiwindow layoutIfNeeded]; + } + + if (window) { + data = (__bridge SDL_WindowData *) window->driverdata; + + /* Make sure the SDL window has a strong reference to this view. */ + [data.views addObject:self]; + + /* Replace the view controller's old view with this one. */ + [data.viewcontroller.view removeFromSuperview]; + data.viewcontroller.view = self; + + /* The root view controller handles rotation and the status bar. + * Assigning it also adds the controller's view to the window. We + * explicitly re-set it to make sure the view is properly attached to + * the window. Just adding the sub-view if the root view controller is + * already correct causes orientation issues on iOS 7 and below. */ + data.uiwindow.rootViewController = nil; + data.uiwindow.rootViewController = data.viewcontroller; + + /* The view's bounds may not be correct until the next event cycle. That + * might happen after the current dimensions are queried, so we force a + * layout now to immediately update the bounds. */ + [data.uiwindow layoutIfNeeded]; + } + + sdlwindow = window; } - (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize { - CGPoint point = [touch locationInView: self]; - - /* Get the display scale and apply that to the input coordinates */ - SDL_Window *window = self->viewcontroller.window; - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata; + CGPoint point = [touch locationInView:self]; if (normalize) { - CGRect bounds = [self bounds]; + CGRect bounds = self.bounds; point.x /= bounds.size.width; point.y /= bounds.size.height; - } else { - point.x *= displaymodedata->scale; - point.y *= displaymodedata->scale; } + return point; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - NSEnumerator *enumerator = [touches objectEnumerator]; - UITouch *touch = (UITouch*)[enumerator nextObject]; - - while (touch) { - if (!leftFingerDown) { + for (UITouch *touch in touches) { + if (!firstFingerDown) { CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO]; - /* send moved event */ - SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); + /* send mouse moved event */ + SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); /* send mouse down event */ - SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); - leftFingerDown = touch; + firstFingerDown = touch; } CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS - /* FIXME: TODO: Using touch as the fingerId is potentially dangerous - * It is also much more efficient than storing the UITouch pointer - * and comparing it to the incoming event. - */ SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), SDL_TRUE, locationInView.x, locationInView.y, 1.0f); -#else - int i; - for(i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) { - if (finger[i] == NULL) { - finger[i] = touch; - SDL_SendTouch(touchId, i, - SDL_TRUE, locationInView.x, locationInView.y, 1.0f); - break; - } - } -#endif - touch = (UITouch*)[enumerator nextObject]; } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - NSEnumerator *enumerator = [touches objectEnumerator]; - UITouch *touch = (UITouch*)[enumerator nextObject]; - - while(touch) { - if (touch == leftFingerDown) { + for (UITouch *touch in touches) { + if (touch == firstFingerDown) { /* send mouse up */ - SDL_SendMouseButton(self->viewcontroller.window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); - leftFingerDown = nil; + SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + firstFingerDown = nil; } CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS - SDL_SendTouch(touchId, (long)touch, + SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), SDL_FALSE, locationInView.x, locationInView.y, 1.0f); -#else - int i; - for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) { - if (finger[i] == touch) { - SDL_SendTouch(touchId, i, - SDL_FALSE, locationInView.x, locationInView.y, 1.0f); - finger[i] = NULL; - break; - } - } -#endif - touch = (UITouch*)[enumerator nextObject]; } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - /* - this can happen if the user puts more than 5 touches on the screen - at once, or perhaps in other circumstances. Usually (it seems) - all active touches are canceled. - */ - [self touchesEnded: touches withEvent: event]; + [self touchesEnded:touches withEvent:event]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - NSEnumerator *enumerator = [touches objectEnumerator]; - UITouch *touch = (UITouch*)[enumerator nextObject]; - - while (touch) { - if (touch == leftFingerDown) { + for (UITouch *touch in touches) { + if (touch == firstFingerDown) { CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO]; /* send moved event */ - SDL_SendMouseMotion(self->viewcontroller.window, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); + SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); } CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; -#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS - SDL_SendTouchMotion(touchId, (long)touch, + SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch), locationInView.x, locationInView.y, 1.0f); -#else - int i; - for (i = 0; i < MAX_SIMULTANEOUS_TOUCHES; i++) { - if (finger[i] == touch) { - SDL_SendTouchMotion(touchId, i, - locationInView.x, locationInView.y, 1.0f); - break; - } - } -#endif - touch = (UITouch*)[enumerator nextObject]; } } -/* - ---- Keyboard related functionality below this line ---- -*/ -#if SDL_IPHONE_KEYBOARD - -@synthesize textInputRect = textInputRect; -@synthesize keyboardHeight = keyboardHeight; - -/* Is the iPhone virtual keyboard visible onscreen? */ -- (BOOL)keyboardVisible -{ - return keyboardVisible; -} - -/* Set ourselves up as a UITextFieldDelegate */ -- (void)initializeKeyboard -{ - textField = [[UITextField alloc] initWithFrame: CGRectZero]; - textField.delegate = self; - /* placeholder so there is something to delete! */ - textField.text = @" "; - - /* set UITextInputTrait properties, mostly to defaults */ - textField.autocapitalizationType = UITextAutocapitalizationTypeNone; - textField.autocorrectionType = UITextAutocorrectionTypeNo; - textField.enablesReturnKeyAutomatically = NO; - textField.keyboardAppearance = UIKeyboardAppearanceDefault; - textField.keyboardType = UIKeyboardTypeDefault; - textField.returnKeyType = UIReturnKeyDefault; - textField.secureTextEntry = NO; - - textField.hidden = YES; - keyboardVisible = NO; - /* add the UITextField (hidden) to our view */ - [self addSubview: textField]; - [textField release]; - - _uikit_keyboard_init(); -} - -/* reveal onscreen virtual keyboard */ -- (void)showKeyboard -{ - keyboardVisible = YES; - [textField becomeFirstResponder]; -} - -/* hide onscreen virtual keyboard */ -- (void)hideKeyboard -{ - keyboardVisible = NO; - [textField resignFirstResponder]; -} - -/* UITextFieldDelegate method. Invoked when user types something. */ -- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string -{ - if ([string length] == 0) { - /* it wants to replace text with nothing, ie a delete */ - SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE); - SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE); - } - else { - /* go through all the characters in the string we've been sent - and convert them to key presses */ - int i; - for (i = 0; i < [string length]; i++) { - - unichar c = [string characterAtIndex: i]; - - Uint16 mod = 0; - SDL_Scancode code; - - if (c < 127) { - /* figure out the SDL_Scancode and SDL_keymod for this unichar */ - code = unicharToUIKeyInfoTable[c].code; - mod = unicharToUIKeyInfoTable[c].mod; - } - else { - /* we only deal with ASCII right now */ - code = SDL_SCANCODE_UNKNOWN; - mod = 0; - } - - if (mod & KMOD_SHIFT) { - /* If character uses shift, press shift down */ - SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT); - } - /* send a keydown and keyup even for the character */ - SDL_SendKeyboardKey(SDL_PRESSED, code); - SDL_SendKeyboardKey(SDL_RELEASED, code); - if (mod & KMOD_SHIFT) { - /* If character uses shift, press shift back up */ - SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT); - } - } - SDL_SendKeyboardText([string UTF8String]); - } - return NO; /* don't allow the edit! (keep placeholder text there) */ -} - -/* Terminates the editing session */ -- (BOOL)textFieldShouldReturn:(UITextField*)_textField -{ - SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN); - SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN); - SDL_StopTextInput(); - return YES; -} - -#endif - @end -/* iPhone keyboard addition functions */ -#if SDL_IPHONE_KEYBOARD - -static SDL_uikitview * getWindowView(SDL_Window * window) -{ - if (window == NULL) { - SDL_SetError("Window does not exist"); - return nil; - } - - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; - SDL_uikitview *view = data != NULL ? data->view : nil; - - if (view == nil) { - SDL_SetError("Window has no view"); - } - - return view; -} - -SDL_bool UIKit_HasScreenKeyboardSupport(_THIS) -{ - return SDL_TRUE; -} - -void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window) -{ - SDL_uikitview *view = getWindowView(window); - if (view != nil) { - [view showKeyboard]; - } -} - -void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window) -{ - SDL_uikitview *view = getWindowView(window); - if (view != nil) { - [view hideKeyboard]; - } -} - -SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window) -{ - SDL_uikitview *view = getWindowView(window); - if (view == nil) { - return 0; - } - - return view.keyboardVisible; -} - - -void _uikit_keyboard_update() { - SDL_Window *window = SDL_GetFocusWindow(); - if (!window) { return; } - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; - if (!data) { return; } - SDL_uikitview *view = data->view; - if (!view) { return; } - - SDL_Rect r = view.textInputRect; - int height = view.keyboardHeight; - int offsetx = 0; - int offsety = 0; - float scale = [UIScreen mainScreen].scale; - if (height) { - int sw,sh; - SDL_GetWindowSize(window,&sw,&sh); - int bottom = (r.y + r.h); - int kbottom = sh - height; - if (kbottom < bottom) { - offsety = kbottom-bottom; - } - } - UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation]; - if (ui_orient == UIInterfaceOrientationLandscapeLeft) { - int tmp = offsetx; offsetx = offsety; offsety = tmp; - } - if (ui_orient == UIInterfaceOrientationLandscapeRight) { - offsety = -offsety; - int tmp = offsetx; offsetx = offsety; offsety = tmp; - } - if (ui_orient == UIInterfaceOrientationPortraitUpsideDown) { - offsety = -offsety; - } - - offsetx /= scale; - offsety /= scale; - - view.frame = CGRectMake(offsetx,offsety,view.frame.size.width,view.frame.size.height); -} - -void _uikit_keyboard_set_height(int height) { - SDL_uikitview *view = getWindowView(SDL_GetFocusWindow()); - if (view == nil) { - return ; - } - - view.keyboardHeight = height; - _uikit_keyboard_update(); -} - -void _uikit_keyboard_init() { - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - NSOperationQueue *queue = [NSOperationQueue mainQueue]; - [center addObserverForName:UIKeyboardWillShowNotification - object:nil - queue:queue - usingBlock:^(NSNotification *notification) { - int height = 0; - CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; - height = keyboardSize.height; - UIInterfaceOrientation ui_orient = [[UIApplication sharedApplication] statusBarOrientation]; - if (ui_orient == UIInterfaceOrientationLandscapeRight || ui_orient == UIInterfaceOrientationLandscapeLeft) { - height = keyboardSize.width; - } - height *= [UIScreen mainScreen].scale; - _uikit_keyboard_set_height(height); - } - ]; - [center addObserverForName:UIKeyboardDidHideNotification - object:nil - queue:queue - usingBlock:^(NSNotification *notification) { - _uikit_keyboard_set_height(0); - } - ]; -} - -void -UIKit_SetTextInputRect(_THIS, SDL_Rect *rect) -{ - if (!rect) { - SDL_InvalidParamError("rect"); - return; - } - - SDL_uikitview *view = getWindowView(SDL_GetFocusWindow()); - if (view == nil) { - return ; - } - - view.textInputRect = *rect; -} - - -#endif /* SDL_IPHONE_KEYBOARD */ - #endif /* SDL_VIDEO_DRIVER_UIKIT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitviewcontroller.h b/src/video/uikit/SDL_uikitviewcontroller.h index e8d595d9b..b8cf3dc55 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.h +++ b/src/video/uikit/SDL_uikitviewcontroller.h @@ -23,18 +23,56 @@ #include "../SDL_sysvideo.h" -@interface SDL_uikitviewcontroller : UIViewController { -@private - SDL_Window *window; -} +#include "SDL_touch.h" -@property (readwrite) SDL_Window *window; +#if SDL_IPHONE_KEYBOARD +@interface SDL_uikitviewcontroller : UIViewController +#else +@interface SDL_uikitviewcontroller : UIViewController +#endif + +@property (nonatomic, assign) SDL_Window *window; + +- (instancetype)initWithSDLWindow:(SDL_Window *)_window; + +- (void)setAnimationCallback:(int)interval + callback:(void (*)(void*))callback + callbackParam:(void*)callbackParam; + +- (void)startAnimation; +- (void)stopAnimation; + +- (void)doLoop:(CADisplayLink*)sender; -- (id)initWithSDLWindow:(SDL_Window *)_window; - (void)loadView; - (void)viewDidLayoutSubviews; - (NSUInteger)supportedInterfaceOrientations; - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient; - (BOOL)prefersStatusBarHidden; +- (UIStatusBarStyle)preferredStatusBarStyle; + +#if SDL_IPHONE_KEYBOARD +- (void)showKeyboard; +- (void)hideKeyboard; +- (void)initKeyboard; +- (void)deinitKeyboard; + +- (void)keyboardWillShow:(NSNotification *)notification; +- (void)keyboardWillHide:(NSNotification *)notification; + +- (void)updateKeyboard; + +@property (nonatomic, assign, getter=isKeyboardVisible) BOOL keyboardVisible; +@property (nonatomic, assign) SDL_Rect textInputRect; +@property (nonatomic, assign) int keyboardHeight; +#endif @end + +#if SDL_IPHONE_KEYBOARD +SDL_bool UIKit_HasScreenKeyboardSupport(_THIS); +void UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window); +void UIKit_HideScreenKeyboard(_THIS, SDL_Window *window); +SDL_bool UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window); +void UIKit_SetTextInputRect(_THIS, SDL_Rect *rect); +#endif diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index 447b80b80..af1f68dc1 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -28,108 +28,389 @@ #include "../SDL_sysvideo.h" #include "../../events/SDL_events_c.h" -#include "SDL_uikitviewcontroller.h" +#import "SDL_uikitviewcontroller.h" +#import "SDL_uikitmessagebox.h" #include "SDL_uikitvideo.h" #include "SDL_uikitmodes.h" #include "SDL_uikitwindow.h" +#if SDL_IPHONE_KEYBOARD +#include "keyinfotable.h" +#endif -@implementation SDL_uikitviewcontroller +@implementation SDL_uikitviewcontroller { + CADisplayLink *displayLink; + int animationInterval; + void (*animationCallback)(void*); + void *animationCallbackParam; + +#if SDL_IPHONE_KEYBOARD + UITextField *textField; +#endif +} @synthesize window; -- (id)initWithSDLWindow:(SDL_Window *)_window +- (instancetype)initWithSDLWindow:(SDL_Window *)_window { - self = [self init]; - if (self == nil) { - return nil; - } - self.window = _window; + if (self = [super initWithNibName:nil bundle:nil]) { + self.window = _window; +#if SDL_IPHONE_KEYBOARD + [self initKeyboard]; +#endif + } return self; } +- (void)dealloc +{ +#if SDL_IPHONE_KEYBOARD + [self deinitKeyboard]; +#endif +} + +- (void)setAnimationCallback:(int)interval + callback:(void (*)(void*))callback + callbackParam:(void*)callbackParam +{ + [self stopAnimation]; + + animationInterval = interval; + animationCallback = callback; + animationCallbackParam = callbackParam; + + if (animationCallback) { + [self startAnimation]; + } +} + +- (void)startAnimation +{ + displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; + [displayLink setFrameInterval:animationInterval]; + [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; +} + +- (void)stopAnimation +{ + [displayLink invalidate]; + displayLink = nil; +} + +- (void)doLoop:(CADisplayLink*)sender +{ + /* Don't run the game loop while a messagebox is up */ + if (!UIKit_ShowingMessageBox()) { + animationCallback(animationCallbackParam); + } +} + - (void)loadView { - /* do nothing. */ + /* Do nothing. */ } - (void)viewDidLayoutSubviews { - if (self->window->flags & SDL_WINDOW_RESIZABLE) { - SDL_WindowData *data = self->window->driverdata; - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(self->window); - SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata; - const CGSize size = data->view.bounds.size; - int w, h; + const CGSize size = self.view.bounds.size; + int w = (int) size.width; + int h = (int) size.height; - w = (int)(size.width * displaymodedata->scale); - h = (int)(size.height * displaymodedata->scale); - - SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h); - } + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); } - (NSUInteger)supportedInterfaceOrientations { - NSUInteger orientationMask = 0; - - const char *orientationsCString; - if ((orientationsCString = SDL_GetHint(SDL_HINT_ORIENTATIONS)) != NULL) { - BOOL rotate = NO; - NSString *orientationsNSString = [NSString stringWithCString:orientationsCString - encoding:NSUTF8StringEncoding]; - NSArray *orientations = [orientationsNSString componentsSeparatedByCharactersInSet: - [NSCharacterSet characterSetWithCharactersInString:@" "]]; - - if ([orientations containsObject:@"LandscapeLeft"]) { - orientationMask |= UIInterfaceOrientationMaskLandscapeLeft; - } - if ([orientations containsObject:@"LandscapeRight"]) { - orientationMask |= UIInterfaceOrientationMaskLandscapeRight; - } - if ([orientations containsObject:@"Portrait"]) { - orientationMask |= UIInterfaceOrientationMaskPortrait; - } - if ([orientations containsObject:@"PortraitUpsideDown"]) { - orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown; - } - - } else if (self->window->flags & SDL_WINDOW_RESIZABLE) { - orientationMask = UIInterfaceOrientationMaskAll; /* any orientation is okay. */ - } else { - if (self->window->w >= self->window->h) { - orientationMask |= UIInterfaceOrientationMaskLandscape; - } - if (self->window->h >= self->window->w) { - orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown); - } - } - - /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { - orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; - } - return orientationMask; + return UIKit_GetSupportedOrientations(window); } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient { - NSUInteger orientationMask = [self supportedInterfaceOrientations]; - return (orientationMask & (1 << orient)); + return ([self supportedInterfaceOrientations] & (1 << orient)) != 0; } - (BOOL)prefersStatusBarHidden { - if (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - return YES; - } else { - return NO; + return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0; +} + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + /* We assume most SDL apps don't have a bright white background. */ + return UIStatusBarStyleLightContent; +} + +/* + ---- Keyboard related functionality below this line ---- + */ +#if SDL_IPHONE_KEYBOARD + +@synthesize textInputRect; +@synthesize keyboardHeight; +@synthesize keyboardVisible; + +/* Set ourselves up as a UITextFieldDelegate */ +- (void)initKeyboard +{ + textField = [[UITextField alloc] initWithFrame:CGRectZero]; + textField.delegate = self; + /* placeholder so there is something to delete! */ + textField.text = @" "; + + /* set UITextInputTrait properties, mostly to defaults */ + textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.autocorrectionType = UITextAutocorrectionTypeNo; + textField.enablesReturnKeyAutomatically = NO; + textField.keyboardAppearance = UIKeyboardAppearanceDefault; + textField.keyboardType = UIKeyboardTypeDefault; + textField.returnKeyType = UIReturnKeyDefault; + textField.secureTextEntry = NO; + + textField.hidden = YES; + keyboardVisible = NO; + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; +} + +- (void)setView:(UIView *)view +{ + [super setView:view]; + + [view addSubview:textField]; + + if (keyboardVisible) { + [self showKeyboard]; } } +- (void)deinitKeyboard +{ + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [center removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +} + +/* reveal onscreen virtual keyboard */ +- (void)showKeyboard +{ + keyboardVisible = YES; + if (textField.window) { + [textField becomeFirstResponder]; + } +} + +/* hide onscreen virtual keyboard */ +- (void)hideKeyboard +{ + keyboardVisible = NO; + [textField resignFirstResponder]; +} + +- (void)keyboardWillShow:(NSNotification *)notification +{ + CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue]; + UIView *view = self.view; + int height = 0; + + /* The keyboard rect is in the coordinate space of the screen, but we want + * its height in the view's coordinate space. */ +#ifdef __IPHONE_8_0 + if ([view respondsToSelector:@selector(convertRect:fromCoordinateSpace:)]) { + UIScreen *screen = view.window.screen; + kbrect = [view convertRect:kbrect fromCoordinateSpace:screen.coordinateSpace]; + height = kbrect.size.height; + } else +#endif + { + /* In iOS 7 and below, the screen's coordinate space is never rotated. */ + if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) { + height = kbrect.size.width; + } else { + height = kbrect.size.height; + } + } + + [self setKeyboardHeight:height]; +} + +- (void)keyboardWillHide:(NSNotification *)notification +{ + [self setKeyboardHeight:0]; +} + +- (void)updateKeyboard +{ + SDL_Rect textrect = self.textInputRect; + CGAffineTransform t = self.view.transform; + CGPoint offset = CGPointMake(0.0, 0.0); + + if (self.keyboardHeight) { + int rectbottom = textrect.y + textrect.h; + int kbottom = self.view.bounds.size.height - self.keyboardHeight; + if (kbottom < rectbottom) { + offset.y = kbottom - rectbottom; + } + } + + /* Put the offset into the this view transform's coordinate space. */ + t.tx = 0.0; + t.ty = 0.0; + offset = CGPointApplyAffineTransform(offset, t); + + t.tx = offset.x; + t.ty = offset.y; + + /* Move the view by applying the updated transform. */ + self.view.transform = t; +} + +- (void)setKeyboardHeight:(int)height +{ + keyboardVisible = height > 0; + keyboardHeight = height; + [self updateKeyboard]; +} + +/* UITextFieldDelegate method. Invoked when user types something. */ +- (BOOL)textField:(UITextField *)_textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string +{ + NSUInteger len = string.length; + + if (len == 0) { + /* it wants to replace text with nothing, ie a delete */ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_BACKSPACE); + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_BACKSPACE); + } else { + /* go through all the characters in the string we've been sent and + * convert them to key presses */ + int i; + for (i = 0; i < len; i++) { + unichar c = [string characterAtIndex:i]; + Uint16 mod = 0; + SDL_Scancode code; + + if (c < 127) { + /* figure out the SDL_Scancode and SDL_keymod for this unichar */ + code = unicharToUIKeyInfoTable[c].code; + mod = unicharToUIKeyInfoTable[c].mod; + } else { + /* we only deal with ASCII right now */ + code = SDL_SCANCODE_UNKNOWN; + mod = 0; + } + + if (mod & KMOD_SHIFT) { + /* If character uses shift, press shift down */ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LSHIFT); + } + + /* send a keydown and keyup even for the character */ + SDL_SendKeyboardKey(SDL_PRESSED, code); + SDL_SendKeyboardKey(SDL_RELEASED, code); + + if (mod & KMOD_SHIFT) { + /* If character uses shift, press shift back up */ + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT); + } + } + + SDL_SendKeyboardText([string UTF8String]); + } + + return NO; /* don't allow the edit! (keep placeholder text there) */ +} + +/* Terminates the editing session */ +- (BOOL)textFieldShouldReturn:(UITextField*)_textField +{ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RETURN); + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RETURN); + SDL_StopTextInput(); + return YES; +} + +#endif + @end +/* iPhone keyboard addition functions */ +#if SDL_IPHONE_KEYBOARD + +static SDL_uikitviewcontroller * +GetWindowViewController(SDL_Window * window) +{ + if (!window || !window->driverdata) { + SDL_SetError("Invalid window"); + return nil; + } + + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + + return data.viewcontroller; +} + +SDL_bool +UIKit_HasScreenKeyboardSupport(_THIS) +{ + return SDL_TRUE; +} + +void +UIKit_ShowScreenKeyboard(_THIS, SDL_Window *window) +{ + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(window); + [vc showKeyboard]; + } +} + +void +UIKit_HideScreenKeyboard(_THIS, SDL_Window *window) +{ + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(window); + [vc hideKeyboard]; + } +} + +SDL_bool +UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window) +{ + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(window); + if (vc != nil) { + return vc.isKeyboardVisible; + } + return SDL_FALSE; + } +} + +void +UIKit_SetTextInputRect(_THIS, SDL_Rect *rect) +{ + if (!rect) { + SDL_InvalidParamError("rect"); + return; + } + + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(SDL_GetFocusWindow()); + if (vc != nil) { + vc.textInputRect = *rect; + + if (vc.keyboardVisible) { + [vc updateKeyboard]; + } + } + } +} + + +#endif /* SDL_IPHONE_KEYBOARD */ + #endif /* SDL_VIDEO_DRIVER_UIKIT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitwindow.h b/src/video/uikit/SDL_uikitwindow.h index 494b028f3..73203d189 100644 --- a/src/video/uikit/SDL_uikitwindow.h +++ b/src/video/uikit/SDL_uikitwindow.h @@ -23,28 +23,33 @@ #include "../SDL_sysvideo.h" #import "SDL_uikitvideo.h" -#import "SDL_uikitopenglview.h" +#import "SDL_uikitview.h" #import "SDL_uikitviewcontroller.h" -typedef struct SDL_WindowData SDL_WindowData; - extern int UIKit_CreateWindow(_THIS, SDL_Window * window); +extern void UIKit_SetWindowTitle(_THIS, SDL_Window * window); extern void UIKit_ShowWindow(_THIS, SDL_Window * window); extern void UIKit_HideWindow(_THIS, SDL_Window * window); extern void UIKit_RaiseWindow(_THIS, SDL_Window * window); +extern void UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); extern void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern void UIKit_DestroyWindow(_THIS, SDL_Window * window); extern SDL_bool UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo * info); +extern NSUInteger UIKit_GetSupportedOrientations(SDL_Window * window); + @class UIWindow; -struct SDL_WindowData -{ - UIWindow *uiwindow; - SDL_uikitopenglview *view; - SDL_uikitviewcontroller *viewcontroller; -}; +@interface SDL_WindowData : NSObject + +@property (nonatomic, strong) UIWindow *uiwindow; +@property (nonatomic, strong) SDL_uikitviewcontroller *viewcontroller; + +/* Array of SDL_uikitviews owned by this window. */ +@property (nonatomic, copy) NSMutableArray *views; + +@end #endif /* _SDL_uikitwindow_h */ diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m index 2b1567778..e65732cf6 100644 --- a/src/video/uikit/SDL_uikitwindow.m +++ b/src/video/uikit/SDL_uikitwindow.m @@ -37,89 +37,111 @@ #include "SDL_uikitwindow.h" #import "SDL_uikitappdelegate.h" +#import "SDL_uikitview.h" #import "SDL_uikitopenglview.h" #include +@implementation SDL_WindowData +@synthesize uiwindow; +@synthesize viewcontroller; +@synthesize views; + +- (instancetype)init +{ + if ((self = [super init])) { + views = [NSMutableArray new]; + } + + return self; +} + +@end + +@interface SDL_uikitwindow : UIWindow + +- (void)layoutSubviews; + +@end + +@implementation SDL_uikitwindow + +- (void)layoutSubviews +{ + /* Workaround to fix window orientation issues in iOS 8+. */ + self.frame = self.screen.bounds; + [super layoutSubviews]; +} + +@end static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created) { SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata; - SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; - SDL_WindowData *data; + SDL_DisplayData *displaydata = (__bridge SDL_DisplayData *) display->driverdata; + SDL_uikitview *view; - /* Allocate the window data */ - data = (SDL_WindowData *)SDL_malloc(sizeof(*data)); + CGRect frame = UIKit_ComputeViewFrame(window, displaydata.uiscreen); + int width = (int) frame.size.width; + int height = (int) frame.size.height; + + SDL_WindowData *data = [[SDL_WindowData alloc] init]; if (!data) { return SDL_OutOfMemory(); } - data->uiwindow = uiwindow; - data->viewcontroller = nil; - data->view = nil; - /* Fill in the SDL window with the window data */ - { - window->x = 0; - window->y = 0; + window->driverdata = (void *) CFBridgingRetain(data); - CGRect bounds; - if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - bounds = [displaydata->uiscreen bounds]; - } else { - bounds = [displaydata->uiscreen applicationFrame]; - } - - /* Get frame dimensions in pixels */ - int width = (int)(bounds.size.width * displaymodedata->scale); - int height = (int)(bounds.size.height * displaymodedata->scale); - - /* Make sure the width/height are oriented correctly */ - if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) { - int temp = width; - width = height; - height = temp; - } - - window->w = width; - window->h = height; - } - - window->driverdata = data; + data.uiwindow = uiwindow; /* only one window on iOS, always shown */ window->flags &= ~SDL_WINDOW_HIDDEN; - /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden. - * This is only set if the window is on the main screen. Other screens - * just force the window to have the borderless flag. - */ - if (displaydata->uiscreen == [UIScreen mainScreen]) { + if (displaydata.uiscreen == [UIScreen mainScreen]) { window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */ - - /* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application - if ([UIApplication sharedApplication].statusBarHidden) { - window->flags |= SDL_WINDOW_BORDERLESS; - } else { - window->flags &= ~SDL_WINDOW_BORDERLESS; - } - */ } else { - window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizeable */ + window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizable */ window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */ window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */ } - /* The View Controller will handle rotating the view when the - * device orientation changes. This will trigger resize events, if - * appropriate. - */ - SDL_uikitviewcontroller *controller; - controller = [SDL_uikitviewcontroller alloc]; - data->viewcontroller = [controller initWithSDLWindow:window]; - [data->viewcontroller setTitle:@"SDL App"]; /* !!! FIXME: hook up SDL_SetWindowTitle() */ + if (displaydata.uiscreen == [UIScreen mainScreen]) { + NSUInteger orients = UIKit_GetSupportedOrientations(window); + BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0; + BOOL supportsPortrait = (orients & (UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown)) != 0; + + /* Make sure the width/height are oriented correctly */ + if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) { + int temp = width; + width = height; + height = temp; + } + } + + window->x = 0; + window->y = 0; + window->w = width; + window->h = height; + + /* The View Controller will handle rotating the view when the device + * orientation changes. This will trigger resize events, if appropriate. */ + data.viewcontroller = [[SDL_uikitviewcontroller alloc] initWithSDLWindow:window]; + + /* The window will initially contain a generic view so resizes, touch events, + * etc. can be handled without an active OpenGL view/context. */ + view = [[SDL_uikitview alloc] initWithFrame:frame]; + + /* Sets this view as the controller's view, and adds the view to the window + * heirarchy. */ + [view setSDLWindow:window]; + + /* Make this window the current mouse focus for touch input */ + if (displaydata.uiscreen == [UIScreen mainScreen]) { + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + } return 0; } @@ -127,173 +149,161 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo int UIKit_CreateWindow(_THIS, SDL_Window *window) { - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - const BOOL external = ([UIScreen mainScreen] != data->uiscreen); - const CGSize origsize = [[data->uiscreen currentMode] size]; + @autoreleasepool { + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + const CGSize origsize = data.uiscreen.currentMode.size; - /* SDL currently puts this window at the start of display's linked list. We rely on this. */ - SDL_assert(_this->windows == window); + /* SDL currently puts this window at the start of display's linked list. We rely on this. */ + SDL_assert(_this->windows == window); - /* We currently only handle a single window per display on iOS */ - if (window->next != NULL) { - return SDL_SetError("Only one window allowed per display."); - } - - /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the - * user, so it's in standby), try to force the display to a resolution - * that most closely matches the desired window size. - */ - if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { - if (display->num_display_modes == 0) { - _this->GetDisplayModes(_this, display); + /* We currently only handle a single window per display on iOS */ + if (window->next != NULL) { + return SDL_SetError("Only one window allowed per display."); } - int i; - const SDL_DisplayMode *bestmode = NULL; - for (i = display->num_display_modes; i >= 0; i--) { - const SDL_DisplayMode *mode = &display->display_modes[i]; - if ((mode->w >= window->w) && (mode->h >= window->h)) - bestmode = mode; - } - - if (bestmode) { - SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata; - [data->uiscreen setCurrentMode:modedata->uiscreenmode]; - - /* desktop_mode doesn't change here (the higher level will - * use it to set all the screens back to their defaults - * upon window destruction, SDL_Quit(), etc. - */ - display->current_mode = *bestmode; - } - } - - if (data->uiscreen == [UIScreen mainScreen]) { - if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - [UIApplication sharedApplication].statusBarHidden = YES; - } else { - [UIApplication sharedApplication].statusBarHidden = NO; - } - } - - if (!(window->flags & SDL_WINDOW_RESIZABLE)) { - if (window->w > window->h) { - if (!UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO]; + /* If monitor has a resolution of 0x0 (hasn't been explicitly set by the + * user, so it's in standby), try to force the display to a resolution + * that most closely matches the desired window size. */ + if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { + if (display->num_display_modes == 0) { + _this->GetDisplayModes(_this, display); } - } else if (window->w < window->h) { - if (UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO]; + + int i; + const SDL_DisplayMode *bestmode = NULL; + for (i = display->num_display_modes; i >= 0; i--) { + const SDL_DisplayMode *mode = &display->display_modes[i]; + if ((mode->w >= window->w) && (mode->h >= window->h)) { + bestmode = mode; + } + } + + if (bestmode) { + SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata; + [data.uiscreen setCurrentMode:modedata.uiscreenmode]; + + /* desktop_mode doesn't change here (the higher level will + * use it to set all the screens back to their defaults + * upon window destruction, SDL_Quit(), etc. */ + display->current_mode = *bestmode; } } - } - /* ignore the size user requested, and make a fullscreen window */ - /* !!! FIXME: can we have a smaller view? */ - UIWindow *uiwindow = [UIWindow alloc]; - uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]]; + if (data.uiscreen == [UIScreen mainScreen]) { + NSUInteger orientations = UIKit_GetSupportedOrientations(window); + UIApplication *app = [UIApplication sharedApplication]; - /* put the window on an external display if appropriate. This implicitly - * does [uiwindow setframe:[uiscreen bounds]], so don't do it on the - * main display, where we land by default, as that would eat the - * status bar real estate. - */ - if (external) { - [uiwindow setScreen:data->uiscreen]; - } + if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { + app.statusBarHidden = YES; + } else { + app.statusBarHidden = NO; + } + } - if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) { - [uiwindow release]; - return -1; + /* ignore the size user requested, and make a fullscreen window */ + /* !!! FIXME: can we have a smaller view? */ + UIWindow *uiwindow = [[SDL_uikitwindow alloc] initWithFrame:data.uiscreen.bounds]; + + /* put the window on an external display if appropriate. */ + if (data.uiscreen != [UIScreen mainScreen]) { + [uiwindow setScreen:data.uiscreen]; + } + + if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) { + return -1; + } } return 1; +} +void +UIKit_SetWindowTitle(_THIS, SDL_Window * window) +{ + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + data.viewcontroller.title = @(window->title); + } } void UIKit_ShowWindow(_THIS, SDL_Window * window) { - UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; - - [uiwindow makeKeyAndVisible]; + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + [data.uiwindow makeKeyAndVisible]; + } } void UIKit_HideWindow(_THIS, SDL_Window * window) { - UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; - - uiwindow.hidden = YES; + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + data.uiwindow.hidden = YES; + } } void UIKit_RaiseWindow(_THIS, SDL_Window * window) { /* We don't currently offer a concept of "raising" the SDL window, since - * we only allow one per display, in the iOS fashion. + * we only allow one per display, in the iOS fashion. * However, we use this entry point to rebind the context to the view - * during OnWindowRestored processing. - */ + * during OnWindowRestored processing. */ _this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx); } +static void +UIKit_UpdateWindowBorder(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + SDL_uikitviewcontroller *viewcontroller = data.viewcontroller; + + if (data.uiwindow.screen == [UIScreen mainScreen]) { + if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) { + [UIApplication sharedApplication].statusBarHidden = YES; + } else { + [UIApplication sharedApplication].statusBarHidden = NO; + } + + /* iOS 7+ won't update the status bar until we tell it to. */ + if ([viewcontroller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + [viewcontroller setNeedsStatusBarAppearanceUpdate]; + } + } + + /* Update the view's frame to account for the status bar change. */ + viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen); + [viewcontroller.view setNeedsLayout]; + [viewcontroller.view layoutIfNeeded]; +} + +void +UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) +{ + @autoreleasepool { + UIKit_UpdateWindowBorder(_this, window); + } +} + void UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) { - SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; - SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata; - UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; - - if (fullscreen) { - [UIApplication sharedApplication].statusBarHidden = YES; - } else { - [UIApplication sharedApplication].statusBarHidden = NO; - } - - CGRect bounds; - if (fullscreen) { - bounds = [displaydata->uiscreen bounds]; - } else { - bounds = [displaydata->uiscreen applicationFrame]; - } - - /* Get frame dimensions in pixels */ - int width = (int)(bounds.size.width * displaymodedata->scale); - int height = (int)(bounds.size.height * displaymodedata->scale); - - /* We can pick either width or height here and we'll rotate the - screen to match, so we pick the closest to what we wanted. - */ - if (window->w >= window->h) { - if (width > height) { - window->w = width; - window->h = height; - } else { - window->w = height; - window->h = width; - } - } else { - if (width > height) { - window->w = height; - window->h = width; - } else { - window->w = width; - window->h = height; - } + @autoreleasepool { + UIKit_UpdateWindowBorder(_this, window); } } void UIKit_DestroyWindow(_THIS, SDL_Window * window) { - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; - - if (data) { - [data->viewcontroller release]; - [data->uiwindow release]; - SDL_free(data); + @autoreleasepool { + if (window->driverdata != NULL) { + SDL_WindowData *data = (SDL_WindowData *) CFBridgingRelease(window->driverdata); + [data.viewcontroller stopAnimation]; + } } window->driverdata = NULL; } @@ -301,29 +311,97 @@ UIKit_DestroyWindow(_THIS, SDL_Window * window) SDL_bool UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { - UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; - if (info->version.major <= SDL_MAJOR_VERSION) { - info->subsystem = SDL_SYSWM_UIKIT; - info->info.uikit.window = uiwindow; - return SDL_TRUE; - } else { - SDL_SetError("Application not compiled with SDL %d.%d\n", - SDL_MAJOR_VERSION, SDL_MINOR_VERSION); - return SDL_FALSE; + if (info->version.major <= SDL_MAJOR_VERSION) { + int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch); + + info->subsystem = SDL_SYSWM_UIKIT; + info->info.uikit.window = data.uiwindow; + + /* These struct members were added in SDL 2.0.4. */ + if (versionnum >= SDL_VERSIONNUM(2,0,4)) { + if ([data.viewcontroller.view isKindOfClass:[SDL_uikitopenglview class]]) { + SDL_uikitopenglview *glview = (SDL_uikitopenglview *)data.viewcontroller.view; + info->info.uikit.framebuffer = glview.drawableFramebuffer; + info->info.uikit.colorbuffer = glview.drawableRenderbuffer; + } else { + info->info.uikit.framebuffer = 0; + info->info.uikit.colorbuffer = 0; + } + } + + return SDL_TRUE; + } else { + SDL_SetError("Application not compiled with SDL %d.%d\n", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION); + return SDL_FALSE; + } } } +NSUInteger +UIKit_GetSupportedOrientations(SDL_Window * window) +{ + const char *hint = SDL_GetHint(SDL_HINT_ORIENTATIONS); + NSUInteger orientationMask = 0; + + @autoreleasepool { + if (hint != NULL) { + NSArray *orientations = [@(hint) componentsSeparatedByString:@" "]; + + if ([orientations containsObject:@"LandscapeLeft"]) { + orientationMask |= UIInterfaceOrientationMaskLandscapeLeft; + } + if ([orientations containsObject:@"LandscapeRight"]) { + orientationMask |= UIInterfaceOrientationMaskLandscapeRight; + } + if ([orientations containsObject:@"Portrait"]) { + orientationMask |= UIInterfaceOrientationMaskPortrait; + } + if ([orientations containsObject:@"PortraitUpsideDown"]) { + orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown; + } + } + + if (orientationMask == 0 && (window->flags & SDL_WINDOW_RESIZABLE)) { + /* any orientation is okay. */ + orientationMask = UIInterfaceOrientationMaskAll; + } + + if (orientationMask == 0) { + if (window->w >= window->h) { + orientationMask |= UIInterfaceOrientationMaskLandscape; + } + if (window->h >= window->w) { + orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown); + } + } + + /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { + orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; + } + } + + return orientationMask; +} + int SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam) { - SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL; - - if (!data || !data->view) { - return SDL_SetError("Invalid window or view not set"); + if (!window || !window->driverdata) { + return SDL_SetError("Invalid window"); + } + + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *)window->driverdata; + [data.viewcontroller setAnimationCallback:interval + callback:callback + callbackParam:callbackParam]; } - [data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam]; return 0; } diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index cb729001e..929aa72a1 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -52,6 +52,10 @@ struct SDL_WaylandInput { SDL_WindowData *pointer_focus; SDL_WindowData *keyboard_focus; + /* Last motion location */ + wl_fixed_t sx_w; + wl_fixed_t sy_w; + struct { struct xkb_keymap *keymap; struct xkb_state *state; @@ -119,13 +123,53 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, { struct SDL_WaylandInput *input = data; SDL_WindowData *window = input->pointer_focus; - int sx = wl_fixed_to_int(sx_w); - int sy = wl_fixed_to_int(sy_w); + input->sx_w = sx_w; + input->sy_w = sy_w; if (input->pointer_focus) { + const int sx = wl_fixed_to_int(sx_w); + const int sy = wl_fixed_to_int(sy_w); SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); } } +static SDL_bool +ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) +{ + SDL_WindowData *window_data = input->pointer_focus; + SDL_Window *window = window_data->sdlwindow; + + if (window->hit_test) { + const SDL_Point point = { wl_fixed_to_int(input->sx_w), wl_fixed_to_int(input->sy_w) }; + const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); + static const uint32_t directions[] = { + WL_SHELL_SURFACE_RESIZE_TOP_LEFT, WL_SHELL_SURFACE_RESIZE_TOP, + WL_SHELL_SURFACE_RESIZE_TOP_RIGHT, WL_SHELL_SURFACE_RESIZE_RIGHT, + WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, WL_SHELL_SURFACE_RESIZE_BOTTOM, + WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT, WL_SHELL_SURFACE_RESIZE_LEFT + }; + switch (rc) { + case SDL_HITTEST_DRAGGABLE: + wl_shell_surface_move(window_data->shell_surface, input->seat, serial); + return SDL_TRUE; + + case SDL_HITTEST_RESIZE_TOPLEFT: + case SDL_HITTEST_RESIZE_TOP: + case SDL_HITTEST_RESIZE_TOPRIGHT: + case SDL_HITTEST_RESIZE_RIGHT: + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: + case SDL_HITTEST_RESIZE_BOTTOM: + case SDL_HITTEST_RESIZE_BOTTOMLEFT: + case SDL_HITTEST_RESIZE_LEFT: + wl_shell_surface_resize(window_data->shell_surface, input->seat, serial, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]); + return SDL_TRUE; + + default: return SDL_FALSE; + } + } + + return SDL_FALSE; +} + static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state_w) @@ -139,6 +183,9 @@ pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, switch (button) { case BTN_LEFT: sdl_button = SDL_BUTTON_LEFT; + if (ProcessHitTest(data, serial)) { + return; /* don't pass this event on to app. */ + } break; case BTN_MIDDLE: sdl_button = SDL_BUTTON_MIDDLE; @@ -184,7 +231,7 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, return; } - SDL_SendMouseWheel(window->sdlwindow, 0, x, y); + SDL_SendMouseWheel(window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); } } @@ -364,7 +411,8 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id) input->display = d; input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, 1); - + input->sx_w = wl_fixed_from_int(0); + input->sy_w = wl_fixed_from_int(0); d->input = input; wl_seat_add_listener(input->seat, &seat_listener, input); diff --git a/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 338f42f87..85f037598 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -356,8 +356,7 @@ Wayland_WarpMouseGlobal(int x, int y) static int Wayland_SetRelativeMouseMode(SDL_bool enabled) { - SDL_Unsupported(); - return -1; + return SDL_Unsupported(); } void diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 43826b831..8f36efa59 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -43,11 +43,6 @@ #define WAYLANDVID_DRIVER_NAME "wayland" -struct wayland_mode { - SDL_DisplayMode mode; - struct wl_list link; -}; - /* Initialization/Query functions */ static int Wayland_VideoInit(_THIS); @@ -87,7 +82,7 @@ static SDL_VideoDevice * Wayland_CreateDevice(int devindex) { SDL_VideoDevice *device; - + if (!SDL_WAYLAND_LoadSymbols()) { return NULL; } @@ -124,6 +119,7 @@ Wayland_CreateDevice(int devindex) device->SetWindowFullscreen = Wayland_SetWindowFullscreen; device->SetWindowSize = Wayland_SetWindowSize; device->DestroyWindow = Wayland_DestroyWindow; + device->SetWindowHitTest = Wayland_SetWindowHitTest; device->free = Wayland_DeleteDevice; @@ -135,27 +131,6 @@ VideoBootStrap Wayland_bootstrap = { Wayland_Available, Wayland_CreateDevice }; -static void -wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m) -{ - struct wayland_mode *mode; - - /* Check for duplicate mode */ - wl_list_for_each(mode, &d->modes_list, link) - if (mode->mode.w == m.w && mode->mode.h == m.h && - mode->mode.refresh_rate == m.refresh_rate) - return; - - /* Add new mode to the list */ - mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode); - - if (!mode) - return; - - mode->mode = m; - WAYLAND_wl_list_insert(&d->modes_list, &mode->link); -} - static void display_handle_geometry(void *data, struct wl_output *output, @@ -168,55 +143,80 @@ display_handle_geometry(void *data, int transform) { - SDL_VideoData *d = data; + SDL_VideoDisplay *display = data; - d->screen_allocation.x = x; - d->screen_allocation.y = y; + display->name = strdup(model); + display->driverdata = output; } static void display_handle_mode(void *data, - struct wl_output *wl_output, + struct wl_output *output, uint32_t flags, int width, int height, int refresh) { - SDL_VideoData *d = data; + SDL_VideoDisplay *display = data; SDL_DisplayMode mode; SDL_zero(mode); mode.w = width; mode.h = height; - mode.refresh_rate = refresh / 1000; - - wayland_add_mode(d, mode); + mode.refresh_rate = refresh / 1000; // mHz to Hz + SDL_AddDisplayMode(display, &mode); if (flags & WL_OUTPUT_MODE_CURRENT) { - d->screen_allocation.width = width; - d->screen_allocation.height = height; + display->current_mode = mode; + display->desktop_mode = mode; } } +static void +display_handle_done(void *data, + struct wl_output *output) +{ + SDL_VideoDisplay *display = data; + SDL_AddVideoDisplay(display); + SDL_free(display->name); + SDL_free(display); +} + +static void +display_handle_scale(void *data, + struct wl_output *output, + int32_t factor) +{ + // TODO: do HiDPI stuff. +} + static const struct wl_output_listener output_listener = { display_handle_geometry, - display_handle_mode + display_handle_mode, + display_handle_done, + display_handle_scale }; static void -shm_handle_format(void *data, - struct wl_shm *shm, - uint32_t format) +Wayland_add_display(SDL_VideoData *d, uint32_t id) { - SDL_VideoData *d = data; + struct wl_output *output; + SDL_VideoDisplay *display = SDL_malloc(sizeof *display); + if (!display) { + SDL_OutOfMemory(); + return; + } + SDL_zero(*display); - d->shm_formats |= (1 << format); + output = wl_registry_bind(d->registry, id, &wl_output_interface, 2); + if (!output) { + SDL_SetError("Failed to retrieve output."); + return; + } + + wl_output_add_listener(output, &output_listener, display); } -static const struct wl_shm_listener shm_listener = { - shm_handle_format -}; - #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager, @@ -238,15 +238,14 @@ static const struct qt_windowmanager_listener windowmanager_listener = { static void display_handle_global(void *data, struct wl_registry *registry, uint32_t id, - const char *interface, uint32_t version) + const char *interface, uint32_t version) { SDL_VideoData *d = data; - + if (strcmp(interface, "wl_compositor") == 0) { d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1); } else if (strcmp(interface, "wl_output") == 0) { - d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1); - wl_output_add_listener(d->output, &output_listener, d); + Wayland_add_display(d, id); } else if (strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id); } else if (strcmp(interface, "wl_shell") == 0) { @@ -255,8 +254,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm); d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr"); - wl_shm_add_listener(d->shm, &shm_listener, d); - + #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (strcmp(interface, "qt_touch_extension") == 0) { Wayland_touch_create(d, id); @@ -272,73 +270,43 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } static const struct wl_registry_listener registry_listener = { - display_handle_global + display_handle_global }; int Wayland_VideoInit(_THIS) { - SDL_VideoData *data; - SDL_VideoDisplay display; - SDL_DisplayMode mode; - int i; - - data = malloc(sizeof *data); + SDL_VideoData *data = SDL_malloc(sizeof *data); if (data == NULL) - return 0; + return SDL_OutOfMemory(); memset(data, 0, sizeof *data); _this->driverdata = data; - WAYLAND_wl_list_init(&data->modes_list); - data->display = WAYLAND_wl_display_connect(NULL); if (data->display == NULL) { - SDL_SetError("Failed to connect to a Wayland display"); - return 0; + return SDL_SetError("Failed to connect to a Wayland display"); } data->registry = wl_display_get_registry(data->display); - - if ( data->registry == NULL) { - SDL_SetError("Failed to get the Wayland registry"); - return 0; + if (data->registry == NULL) { + return SDL_SetError("Failed to get the Wayland registry"); } - + wl_registry_add_listener(data->registry, ®istry_listener, data); - for (i=0; i < 100; i++) { - if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) { - break; - } - WAYLAND_wl_display_dispatch(data->display); - } - - if (data->screen_allocation.width == 0) { - SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display)); - return 0; - } + // First roundtrip to receive all registry objects. + WAYLAND_wl_display_roundtrip(data->display); + + // Second roundtrip to receive all output events. + WAYLAND_wl_display_roundtrip(data->display); data->xkb_context = WAYLAND_xkb_context_new(0); if (!data->xkb_context) { - SDL_SetError("Failed to create XKB context"); - return 0; + return SDL_SetError("Failed to create XKB context"); } - /* Use a fake 32-bpp desktop mode */ - mode.format = SDL_PIXELFORMAT_RGB888; - mode.w = data->screen_allocation.width; - mode.h = data->screen_allocation.height; - mode.refresh_rate = 0; - mode.driverdata = NULL; - wayland_add_mode(data, mode); - SDL_zero(display); - display.desktop_mode = mode; - display.current_mode = mode; - display.driverdata = NULL; - SDL_AddVideoDisplay(&display); - - Wayland_InitMouse (); + Wayland_InitMouse(); WAYLAND_wl_display_flush(data->display); @@ -348,46 +316,29 @@ Wayland_VideoInit(_THIS) static void Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display) { - SDL_VideoData *data = _this->driverdata; - SDL_DisplayMode mode; - struct wayland_mode *m; - - Wayland_PumpEvents(_this); - - wl_list_for_each(m, &data->modes_list, link) { - m->mode.format = SDL_PIXELFORMAT_RGB888; - SDL_AddDisplayMode(sdl_display, &m->mode); - m->mode.format = SDL_PIXELFORMAT_RGBA8888; - SDL_AddDisplayMode(sdl_display, &m->mode); - } - - mode.w = data->screen_allocation.width; - mode.h = data->screen_allocation.height; - mode.refresh_rate = 0; - mode.driverdata = NULL; - - mode.format = SDL_PIXELFORMAT_RGB888; - SDL_AddDisplayMode(sdl_display, &mode); - mode.format = SDL_PIXELFORMAT_RGBA8888; - SDL_AddDisplayMode(sdl_display, &mode); + // Nothing to do here, everything was already done in the wl_output + // callbacks. } static int Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) { - return 0; + return SDL_Unsupported(); } void Wayland_VideoQuit(_THIS) { SDL_VideoData *data = _this->driverdata; - struct wayland_mode *t, *m; + int i; Wayland_FiniMouse (); - if (data->output) - wl_output_destroy(data->output); + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + wl_output_destroy(display->driverdata); + display->driverdata = NULL; + } Wayland_display_destroy_input(data); @@ -417,16 +368,13 @@ Wayland_VideoQuit(_THIS) if (data->compositor) wl_compositor_destroy(data->compositor); + if (data->registry) + wl_registry_destroy(data->registry); + if (data->display) { WAYLAND_wl_display_flush(data->display); WAYLAND_wl_display_disconnect(data->display); } - - wl_list_for_each_safe(m, t, &data->modes_list, link) { - WAYLAND_wl_list_remove(&m->link); - free(m); - } - free(data); _this->driverdata = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 06bcdc48d..d56e0c939 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -40,35 +40,26 @@ typedef struct { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; - struct wl_output *output; struct wl_shm *shm; struct wl_cursor_theme *cursor_theme; struct wl_cursor *default_cursor; struct wl_pointer *pointer; struct wl_shell *shell; - struct { - int32_t x, y, width, height; - } screen_allocation; - - struct wl_list modes_list; - EGLDisplay edpy; EGLContext context; EGLConfig econf; struct xkb_context *xkb_context; struct SDL_WaylandInput *input; - -#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH + +#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch *touch; struct qt_surface_extension *surface_extension; struct qt_windowmanager *windowmanager; #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ - - uint32_t shm_formats; } SDL_VideoData; -#endif /* _SDL_nullvideo_h */ +#endif /* _SDL_waylandvideo_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 3760c0d3b..3cfb1a8ee 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -29,6 +29,7 @@ #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" +#include "SDL_waylanddyn.h" static void handle_ping(void *data, struct wl_shell_surface *shell_surface, @@ -108,6 +109,12 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) return SDL_TRUE; } +int +Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) +{ + return 0; /* just succeed, the real work is done elsewhere. */ +} + void Wayland_ShowWindow(_THIS, SDL_Window *window) { SDL_WindowData *wind = window->driverdata; @@ -115,7 +122,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) if (window->flags & SDL_WINDOW_FULLSCREEN) wl_shell_surface_set_fullscreen(wind->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, - 0, NULL); + 0, (struct wl_output *)window->fullscreen_mode.driverdata); else wl_shell_surface_set_toplevel(wind->shell_surface); @@ -131,7 +138,7 @@ Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, if (fullscreen) wl_shell_surface_set_fullscreen(wind->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, - 0, NULL); + 0, (struct wl_output *)_display->driverdata); else wl_shell_surface_set_toplevel(wind->shell_surface); @@ -146,7 +153,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) data = calloc(1, sizeof *data); if (data == NULL) - return 0; + return SDL_OutOfMemory(); c = _this->driverdata; window->driverdata = data; @@ -178,17 +185,6 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ - /** - * If the user specified 0x0 as the size (turned to 1x1 by SDL_CreateWindow - * in SDL_video.c), we want to make the window fill the whole screen - **/ - if (window->w == 1) { - window->w = c->screen_allocation.width; - } - if (window->h == 1) { - window->h = c->screen_allocation.height; - } - data->egl_window = WAYLAND_wl_egl_window_create(data->surface, window->w, window->h); @@ -196,8 +192,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window); if (data->egl_surface == EGL_NO_SURFACE) { - SDL_SetError("failed to create a window surface"); - return -1; + return SDL_SetError("failed to create a window surface"); } if (data->shell_surface) { diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index c1190d521..d80512d6e 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -55,6 +55,7 @@ extern void Wayland_DestroyWindow(_THIS, SDL_Window *window); extern SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); +extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled); #endif /* _SDL_waylandwindow_h */ diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 28801d2fc..524e67adf 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -498,12 +498,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) s_AccumulatedMotion += GET_WHEEL_DELTA_WPARAM(wParam); if (s_AccumulatedMotion > 0) { while (s_AccumulatedMotion >= WHEEL_DELTA) { - SDL_SendMouseWheel(data->window, 0, 0, 1); + SDL_SendMouseWheel(data->window, 0, 0, 1, SDL_MOUSEWHEEL_NORMAL); s_AccumulatedMotion -= WHEEL_DELTA; } } else { while (s_AccumulatedMotion <= -WHEEL_DELTA) { - SDL_SendMouseWheel(data->window, 0, 0, -1); + SDL_SendMouseWheel(data->window, 0, 0, -1, SDL_MOUSEWHEEL_NORMAL); s_AccumulatedMotion += WHEEL_DELTA; } } @@ -517,12 +517,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) s_AccumulatedMotion += GET_WHEEL_DELTA_WPARAM(wParam); if (s_AccumulatedMotion > 0) { while (s_AccumulatedMotion >= WHEEL_DELTA) { - SDL_SendMouseWheel(data->window, 0, 1, 0); + SDL_SendMouseWheel(data->window, 0, 1, 0, SDL_MOUSEWHEEL_NORMAL); s_AccumulatedMotion -= WHEEL_DELTA; } } else { while (s_AccumulatedMotion <= -WHEEL_DELTA) { - SDL_SendMouseWheel(data->window, 0, -1, 0); + SDL_SendMouseWheel(data->window, 0, -1, 0, SDL_MOUSEWHEEL_NORMAL); s_AccumulatedMotion += WHEEL_DELTA; } } @@ -559,10 +559,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) GetKeyboardState(keyboardState); if (ToUnicode(wParam, (lParam >> 16) & 0xff, keyboardState, (LPWSTR)&utf32, 1, 0) > 0) { - WORD repetition; - for (repetition = lParam & 0xffff; repetition > 0; repetition--) { - WIN_ConvertUTF32toUTF8(utf32, text); - SDL_SendKeyboardText(text); + if (WIN_ConvertUTF32toUTF8(utf32, text)) { + WORD repetition; + for (repetition = lParam & 0xffff; repetition > 0; repetition--) { + SDL_SendKeyboardText(text); + } } } } diff --git a/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c index 71855c874..bab97fae0 100644 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -74,6 +74,13 @@ #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 #endif +#ifndef WGL_ARB_context_flush_control +#define WGL_ARB_context_flush_control +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif + typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, @@ -405,6 +412,11 @@ WIN_GL_InitExtensions(_THIS) _this->gl_data->HAS_WGL_EXT_create_context_es2_profile = SDL_TRUE; } + /* Check for GLX_ARB_context_flush_control */ + if (HasExtension("WGL_ARB_context_flush_control", extensions)) { + _this->gl_data->HAS_WGL_ARB_context_flush_control = SDL_TRUE; + } + _this->gl_data->wglMakeCurrent(hdc, NULL); _this->gl_data->wglDeleteContext(hglrc); ReleaseDC(hwnd, hdc); @@ -648,8 +660,8 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) SDL_SetError("GL 3.x is not supported"); context = temp_context; } else { - /* max 8 attributes plus terminator */ - int attribs[9] = { + /* max 10 attributes plus terminator */ + int attribs[11] = { WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version, WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version, 0 @@ -668,6 +680,14 @@ WIN_GL_CreateContext(_THIS, SDL_Window * window) attribs[iattr++] = _this->gl_config.flags; } + /* only set if wgl extension is available */ + if( _this->gl_data->HAS_WGL_ARB_context_flush_control ) { + attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB; + attribs[iattr++] = _this->gl_config.release_behavior ? + WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : + WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; + } + attribs[iattr++] = 0; /* Create the GL 3.x context */ diff --git a/src/video/windows/SDL_windowsopengl.h b/src/video/windows/SDL_windowsopengl.h index b96e0ac1e..b95b90f74 100644 --- a/src/video/windows/SDL_windowsopengl.h +++ b/src/video/windows/SDL_windowsopengl.h @@ -30,6 +30,7 @@ struct SDL_GLDriverData SDL_bool HAS_WGL_ARB_pixel_format; SDL_bool HAS_WGL_EXT_swap_control_tear; SDL_bool HAS_WGL_EXT_create_context_es2_profile; + SDL_bool HAS_WGL_ARB_context_flush_control; void *(WINAPI * wglGetProcAddress) (const char *proc); HGLRC(WINAPI * wglCreateContext) (HDC hdc); diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 94328339f..d3aaebd42 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -371,14 +371,8 @@ void WIN_SetWindowTitle(_THIS, SDL_Window * window) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; - LPTSTR title; - - if (window->title) { - title = WIN_UTF8ToString(window->title); - } else { - title = NULL; - } - SetWindowText(hwnd, title ? title : TEXT("")); + LPTSTR title = WIN_UTF8ToString(window->title); + SetWindowText(hwnd, title); SDL_free(title); } @@ -643,10 +637,11 @@ WIN_DestroyWindow(_THIS, SDL_Window * window) SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { - HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata; if (info->version.major <= SDL_MAJOR_VERSION) { info->subsystem = SDL_SYSWM_WINDOWS; - info->info.win.window = hwnd; + info->info.win.window = data->hwnd; + info->info.win.hdc = data->hdc; return SDL_TRUE; } else { SDL_SetError("Application not compiled with SDL %d.%d\n", diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp index e3a955be1..4c7199824 100644 --- a/src/video/winrt/SDL_winrtopengles.cpp +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -36,10 +36,17 @@ using namespace Windows::UI::Core; /* ANGLE/WinRT constants */ static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0; -#define EGL_PLATFORM_ANGLE_ANGLE 0x3201 -#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202 -#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3203 -#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_ANGLE 0x3202 +#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204 +#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205 +#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209 +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B +#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F + +#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER 0x320B + /* * SDL/EGL top-level implementation @@ -80,11 +87,40 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) Microsoft::WRL::ComPtr cpp_display = video_data->winrtEglWindow; _this->egl_data->egl_display = ((eglGetDisplay_Old_Function)_this->egl_data->eglGetDisplay)(cpp_display); if (!_this->egl_data->egl_display) { - return SDL_SetError("Could not get EGL display"); + return SDL_SetError("Could not get Windows 8.0 EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + return SDL_SetError("Could not initialize Windows 8.0 EGL"); } } else { - const EGLint displayAttributes[] = { + /* Declare some ANGLE/EGL initialization property-sets, as suggested by + * MSOpenTech's ANGLE-for-WinRT template apps: + */ + const EGLint defaultDisplayAttributes[] = + { EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint fl9_3DisplayAttributes[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, + EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, + EGL_NONE, + }; + + const EGLint warpDisplayAttributes[] = + { + EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, + EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER, EGL_TRUE, + EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; @@ -99,14 +135,41 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) return SDL_SetError("Could not retrieve ANGLE/WinRT display function(s)"); } - _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, displayAttributes); +#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) + /* Try initializing EGL at D3D11 Feature Level 10_0+ (which is not + * supported on WinPhone 8.x. + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, defaultDisplayAttributes); if (!_this->egl_data->egl_display) { - return SDL_SetError("Could not get EGL display"); + return SDL_SetError("Could not get 10_0+ EGL display"); } - } - if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { - return SDL_SetError("Could not initialize EGL"); + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) +#endif + { + /* Try initializing EGL at D3D11 Feature Level 9_3, in case the + * 10_0 init fails, or we're on Windows Phone (which only supports + * 9_3). + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get 9_3 EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + /* Try initializing EGL at D3D11 Feature Level 11_0 on WARP + * (a Windows-provided, software rasterizer) if all else fails. + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warpDisplayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get WARP EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + return SDL_SetError("Could not initialize WinRT 8.x+ EGL"); + } + } + } } return 0; diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp index b811cb008..da20cc3c9 100644 --- a/src/video/winrt/SDL_winrtpointerinput.cpp +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -315,7 +315,7 @@ WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::Po // FIXME: This may need to accumulate deltas up to WHEEL_DELTA short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; - SDL_SendMouseWheel(window, 0, 0, motion); + SDL_SendMouseWheel(window, 0, 0, motion, SDL_MOUSEWHEEL_NORMAL); } void diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 038a26d9f..c16bb82a7 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -325,7 +325,7 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) if (SDL_EGL_ChooseConfig(_this) != 0) { char buf[512]; SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError()); - return SDL_SetError(buf); + return SDL_SetError("%s", buf); } if (video_data->winrtEglWindow) { /* ... is the 'old' version of ANGLE/WinRT being used? */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 0703447b0..e5a9c2848 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -448,63 +448,38 @@ static SDL_bool ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) { SDL_Window *window = data->window; - SDL_bool ret = SDL_FALSE; if (window->hit_test) { const SDL_Point point = { xev->xbutton.x, xev->xbutton.y }; const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); + static const int directions[] = { + _NET_WM_MOVERESIZE_SIZE_TOPLEFT, _NET_WM_MOVERESIZE_SIZE_TOP, + _NET_WM_MOVERESIZE_SIZE_TOPRIGHT, _NET_WM_MOVERESIZE_SIZE_RIGHT, + _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT, _NET_WM_MOVERESIZE_SIZE_BOTTOM, + _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT, _NET_WM_MOVERESIZE_SIZE_LEFT + }; + switch (rc) { - case SDL_HITTEST_DRAGGABLE: { - InitiateWindowMove(_this, data, &point); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_TOPLEFT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPLEFT); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_TOP: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOP); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_TOPRIGHT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_TOPRIGHT); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_RIGHT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_RIGHT); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_BOTTOMRIGHT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_BOTTOM: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOM); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_BOTTOMLEFT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT); - ret = SDL_TRUE; - } - break; - case SDL_HITTEST_RESIZE_LEFT: { - InitiateWindowResize(_this, data, &point, _NET_WM_MOVERESIZE_SIZE_LEFT); - ret = SDL_TRUE; - } - break; - default: - break; + case SDL_HITTEST_DRAGGABLE: + InitiateWindowMove(_this, data, &point); + return SDL_TRUE; + + case SDL_HITTEST_RESIZE_TOPLEFT: + case SDL_HITTEST_RESIZE_TOP: + case SDL_HITTEST_RESIZE_TOPRIGHT: + case SDL_HITTEST_RESIZE_RIGHT: + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: + case SDL_HITTEST_RESIZE_BOTTOM: + case SDL_HITTEST_RESIZE_BOTTOMLEFT: + case SDL_HITTEST_RESIZE_LEFT: + InitiateWindowResize(_this, data, &point, directions[rc - SDL_HITTEST_RESIZE_TOPLEFT]); + return SDL_TRUE; + + default: return SDL_FALSE; } } - return ret; + return SDL_FALSE; } static void @@ -677,8 +652,17 @@ X11_DispatchEvent(_THIS) data->window == SDL_GetKeyboardFocus()) { ReconcileKeyboardState(_this, data); } - data->pending_focus = PENDING_FOCUS_IN; - data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusIn(data); + } + else + { + data->pending_focus = PENDING_FOCUS_IN; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; + } } break; @@ -701,8 +685,17 @@ X11_DispatchEvent(_THIS) #ifdef DEBUG_XEVENTS printf("window %p: FocusOut!\n", data); #endif - data->pending_focus = PENDING_FOCUS_OUT; - data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_OUT_TIME; + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusOut(data); + } + else + { + data->pending_focus = PENDING_FOCUS_OUT; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; + } } break; @@ -990,7 +983,7 @@ X11_DispatchEvent(_THIS) case ButtonPress:{ int ticks = 0; if (X11_IsWheelEvent(display,&xevent,&ticks)) { - SDL_SendMouseWheel(data->window, 0, 0, ticks); + SDL_SendMouseWheel(data->window, 0, 0, ticks, SDL_MOUSEWHEEL_NORMAL); } else { if(xevent.xbutton.button == Button1) { if (ProcessHitTest(_this, data, &xevent)) { @@ -1090,15 +1083,25 @@ X11_DispatchEvent(_THIS) without ever mapping / unmapping them, so we handle that here, because they use the NETWM protocol to notify us of changes. */ - Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); - if ((flags^data->window->flags) & SDL_WINDOW_HIDDEN || - (flags^data->window->flags) & SDL_WINDOW_FULLSCREEN ) { - if (flags & SDL_WINDOW_HIDDEN) { - X11_DispatchUnmapNotify(data); - } else { - X11_DispatchMapNotify(data); + const Uint32 flags = X11_GetNetWMState(_this, xevent.xproperty.window); + const Uint32 changed = flags ^ data->window->flags; + + if ((changed & SDL_WINDOW_HIDDEN) || (changed & SDL_WINDOW_FULLSCREEN)) { + if (flags & SDL_WINDOW_HIDDEN) { + X11_DispatchUnmapNotify(data); + } else { + X11_DispatchMapNotify(data); } } + + if (changed & SDL_WINDOW_MAXIMIZED) { + if (flags & SDL_WINDOW_MAXIMIZED) { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); + } else { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); + } + } + } } break; @@ -1283,9 +1286,15 @@ X11_PumpEvents(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + if (data->last_mode_change_deadline) { + if (SDL_TICKS_PASSED(SDL_GetTicks(), data->last_mode_change_deadline)) { + data->last_mode_change_deadline = 0; /* assume we're done. */ + } + } + /* Update activity every 30 seconds to prevent screensaver */ if (_this->suspend_screensaver) { - Uint32 now = SDL_GetTicks(); + const Uint32 now = SDL_GetTicks(); if (!data->screensaver_activity || SDL_TICKS_PASSED(now, data->screensaver_activity + 30000)) { X11_XResetScreenSaver(data->display); diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 2a98e3c3e..ea99cdc25 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -31,8 +31,8 @@ #include -#define SDL_FORK_MESSAGEBOX 0 -#define SDL_SET_LOCALE 0 +#define SDL_FORK_MESSAGEBOX 1 +#define SDL_SET_LOCALE 1 #if SDL_FORK_MESSAGEBOX #include @@ -366,6 +366,7 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) int x, y; XSizeHints *sizehints; XSetWindowAttributes wnd_attr; + Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG; Display *display = data->display; SDL_WindowData *windowdata = NULL; const SDL_MessageBoxData *messageboxdata = data->messageboxdata; @@ -401,6 +402,13 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) X11_XStoreName( display, data->window, messageboxdata->title ); + /* Let the window manager know this is a dialog box */ + _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); + _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); + X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, + PropModeReplace, + (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1); + /* Allow the window to be deleted by the window manager */ data->wm_protocols = X11_XInternAtom( display, "WM_PROTOCOLS", False ); data->wm_delete_message = X11_XInternAtom( display, "WM_DELETE_WINDOW", False ); @@ -710,9 +718,6 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int fds[2]; int status = 0; - /* Need to flush here in case someone has turned grab off and it hasn't gone through yet, etc. */ - X11_XFlush(data->display); - if (pipe(fds) == -1) { return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */ } diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 0fc6d2386..5248f7655 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -24,6 +24,7 @@ #include "SDL_hints.h" #include "SDL_x11video.h" +#include "SDL_timer.h" #include "edid.h" /* #define X11MODES_DEBUG */ @@ -813,10 +814,13 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) int X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode) { - Display *display = ((SDL_VideoData *) _this->driverdata)->display; + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + Display *display = viddata->display; SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; + viddata->last_mode_change_deadline = SDL_GetTicks() + (PENDING_FOCUS_TIME * 2); + #if SDL_VIDEO_DRIVER_X11_XRANDR if (data->use_xrandr) { XRRScreenResources *res; diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 1e94b041c..7bc3256bd 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -122,6 +122,13 @@ typedef GLXContext(*PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display * dpy, #define GLX_LATE_SWAPS_TEAR_EXT 0x20F3 #endif +#ifndef GLX_ARB_context_flush_control +#define GLX_ARB_context_flush_control +#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000 +#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#endif + #define OPENGL_REQUIRES_DLOPEN #if defined(OPENGL_REQUIRES_DLOPEN) && defined(SDL_LOADSO_DLOPEN) #include @@ -279,14 +286,14 @@ HasExtension(const char *extension, const char *extensions) const char *start; const char *where, *terminator; + if (!extensions) + return SDL_FALSE; + /* Extension names should not have spaces. */ where = SDL_strchr(extension, ' '); if (where || *extension == '\0') return SDL_FALSE; - if (!extensions) - return SDL_FALSE; - /* It takes a bit of care to be fool-proof about parsing the * OpenGL extensions string. Don't be fooled by sub-strings, * etc. */ @@ -312,32 +319,10 @@ static void X11_GL_InitExtensions(_THIS) { Display *display = ((SDL_VideoData *) _this->driverdata)->display; - int screen = DefaultScreen(display); - XVisualInfo *vinfo; - XSetWindowAttributes xattr; - Window w; - GLXContext context; + const int screen = DefaultScreen(display); const char *(*glXQueryExtensionsStringFunc) (Display *, int); const char *extensions; - vinfo = X11_GL_GetVisual(_this, display, screen); - if (!vinfo) { - return; - } - xattr.background_pixel = 0; - xattr.border_pixel = 0; - xattr.colormap = - X11_XCreateColormap(display, RootWindow(display, screen), vinfo->visual, - AllocNone); - w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0, 32, 32, 0, - vinfo->depth, InputOutput, vinfo->visual, - (CWBackPixel | CWBorderPixel | CWColormap), &xattr); - context = _this->gl_data->glXCreateContext(display, vinfo, NULL, True); - if (context) { - _this->gl_data->glXMakeCurrent(display, w, context); - } - X11_XFree(vinfo); - glXQueryExtensionsStringFunc = (const char *(*)(Display *, int)) X11_GL_GetProcAddress(_this, "glXQueryExtensionsString"); @@ -373,6 +358,16 @@ X11_GL_InitExtensions(_THIS) (int (*)(int)) X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI"); } + /* Check for GLX_ARB_create_context */ + if (HasExtension("GLX_ARB_create_context", extensions)) { + _this->gl_data->glXCreateContextAttribsARB = + (GLXContext (*)(Display*,GLXFBConfig,GLXContext,Bool,const int *)) + X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB"); + _this->gl_data->glXChooseFBConfig = + (GLXFBConfig *(*)(Display *, int, const int *, int *)) + X11_GL_GetProcAddress(_this, "glXChooseFBConfig"); + } + /* Check for GLX_EXT_visual_rating */ if (HasExtension("GLX_EXT_visual_rating", extensions)) { _this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE; @@ -388,18 +383,16 @@ X11_GL_InitExtensions(_THIS) _this->gl_data->HAS_GLX_EXT_create_context_es2_profile = SDL_TRUE; } - if (context) { - _this->gl_data->glXMakeCurrent(display, None, NULL); - _this->gl_data->glXDestroyContext(display, context); + /* Check for GLX_ARB_context_flush_control */ + if (HasExtension("GLX_ARB_context_flush_control", extensions)) { + _this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE; } - X11_XDestroyWindow(display, w); - X11_PumpEvents(_this); } /* glXChooseVisual and glXChooseFBConfig have some small differences in * the attribute encoding, it can be chosen with the for_FBConfig parameter. */ -int +static int X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int size, Bool for_FBConfig) { int i = 0; @@ -481,9 +474,7 @@ X11_GL_GetAttributes(_THIS, Display * display, int screen, int * attribs, int si if (_this->gl_config.framebuffer_srgb_capable) { attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB; - if( for_FBConfig ) { - attribs[i++] = True; - } + attribs[i++] = True; /* always needed, for_FBConfig or not! */ } if (_this->gl_config.accelerated >= 0 && @@ -576,7 +567,6 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) XVisualInfo v, *vinfo; int n; GLXContext context = NULL, share_context; - PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = NULL; if (_this->gl_config.share_with_current_context) { share_context = (GLXContext)SDL_GL_GetCurrentContext(); @@ -601,78 +591,61 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) context = _this->gl_data->glXCreateContext(display, vinfo, share_context, True); } else { - /* If we want a GL 3.0 context or later we need to get a temporary - context to grab the new context creation function */ - GLXContext temp_context = - _this->gl_data->glXCreateContext(display, vinfo, NULL, True); - if (temp_context) { - /* max 8 attributes plus terminator */ - int attribs[9] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, - _this->gl_config.major_version, - GLX_CONTEXT_MINOR_VERSION_ARB, - _this->gl_config.minor_version, - 0 - }; - int iattr = 4; + /* max 10 attributes plus terminator */ + int attribs[11] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + _this->gl_config.major_version, + GLX_CONTEXT_MINOR_VERSION_ARB, + _this->gl_config.minor_version, + 0 + }; + int iattr = 4; - /* SDL profile bits match GLX profile bits */ - if( _this->gl_config.profile_mask != 0 ) { - attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; - attribs[iattr++] = _this->gl_config.profile_mask; - } + /* SDL profile bits match GLX profile bits */ + if( _this->gl_config.profile_mask != 0 ) { + attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB; + attribs[iattr++] = _this->gl_config.profile_mask; + } - /* SDL flags match GLX flags */ - if( _this->gl_config.flags != 0 ) { - attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; - attribs[iattr++] = _this->gl_config.flags; - } + /* SDL flags match GLX flags */ + if( _this->gl_config.flags != 0 ) { + attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB; + attribs[iattr++] = _this->gl_config.flags; + } - attribs[iattr++] = 0; + /* only set if glx extension is available */ + if( _this->gl_data->HAS_GLX_ARB_context_flush_control ) { + attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB; + attribs[iattr++] = + _this->gl_config.release_behavior ? + GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : + GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; + } - /* Get a pointer to the context creation function for GL 3.0 */ - glXCreateContextAttribs = - (PFNGLXCREATECONTEXTATTRIBSARBPROC) _this->gl_data-> - glXGetProcAddress((GLubyte *) - "glXCreateContextAttribsARB"); - if (!glXCreateContextAttribs) { - SDL_SetError("GL 3.x is not supported"); - context = temp_context; + attribs[iattr++] = 0; + + /* Get a pointer to the context creation function for GL 3.0 */ + if (!_this->gl_data->glXCreateContextAttribsARB) { + SDL_SetError("OpenGL 3.0 and later are not supported by this system"); + } else { + int glxAttribs[64]; + + /* Create a GL 3.x context */ + GLXFBConfig *framebuffer_config = NULL; + int fbcount = 0; + + X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); + + if (!_this->gl_data->glXChooseFBConfig + || !(framebuffer_config = + _this->gl_data->glXChooseFBConfig(display, + DefaultScreen(display), glxAttribs, + &fbcount))) { + SDL_SetError("No good framebuffers found. OpenGL 3.0 and later unavailable"); } else { - int glxAttribs[64]; - - /* Create a GL 3.x context */ - GLXFBConfig *framebuffer_config = NULL; - int fbcount = 0; - GLXFBConfig *(*glXChooseFBConfig) (Display * disp, - int screen, - const int *attrib_list, - int *nelements); - - glXChooseFBConfig = - (GLXFBConfig * - (*)(Display *, int, const int *, - int *)) _this->gl_data-> - glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); - - X11_GL_GetAttributes(_this,display,screen,glxAttribs,64,SDL_TRUE); - - if (!glXChooseFBConfig - || !(framebuffer_config = - glXChooseFBConfig(display, - DefaultScreen(display), glxAttribs, - &fbcount))) { - SDL_SetError - ("No good framebuffers found. GL 3.x disabled"); - context = temp_context; - } else { - context = - glXCreateContextAttribs(display, + context = _this->gl_data->glXCreateContextAttribsARB(display, framebuffer_config[0], share_context, True, attribs); - _this->gl_data->glXDestroyContext(display, - temp_context); - } } } } diff --git a/src/video/x11/SDL_x11opengl.h b/src/video/x11/SDL_x11opengl.h index ed7f292d4..5856c9b79 100644 --- a/src/video/x11/SDL_x11opengl.h +++ b/src/video/x11/SDL_x11opengl.h @@ -35,11 +35,14 @@ struct SDL_GLDriverData SDL_bool HAS_GLX_EXT_visual_info; SDL_bool HAS_GLX_EXT_swap_control_tear; SDL_bool HAS_GLX_EXT_create_context_es2_profile; + SDL_bool HAS_GLX_ARB_context_flush_control; Bool (*glXQueryExtension) (Display*,int*,int*); void *(*glXGetProcAddress) (const GLubyte*); XVisualInfo *(*glXChooseVisual) (Display*,int,int*); GLXContext (*glXCreateContext) (Display*,XVisualInfo*,GLXContext,Bool); + GLXContext (*glXCreateContextAttribsARB) (Display*,GLXFBConfig,GLXContext,Bool,const int *); + GLXFBConfig *(*glXChooseFBConfig) (Display*,int,const int *,int *); void (*glXDestroyContext) (Display*, GLXContext); Bool(*glXMakeCurrent) (Display*,GLXDrawable,GLXContext); void (*glXSwapBuffers) (Display*, GLXDrawable); diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index f076ccec1..ed6b14fa4 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -112,6 +112,7 @@ typedef struct SDL_VideoData SDL_Scancode key_layout[256]; SDL_bool selection_waiting; + Uint32 last_mode_change_deadline; } SDL_VideoData; extern SDL_bool X11_UseDirectColorVisuals(void); diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 05621e0ca..27e1c999a 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -333,7 +333,7 @@ SetWindowBordered(Display *display, int screen, Window window, SDL_bool border) X11_XChangeProperty(display, window, WM_HINTS, WM_HINTS, 32, PropModeReplace, (unsigned char *) &MWMHints, - sizeof(MWMHints) / 4); + sizeof(MWMHints) / sizeof(long)); } else { /* set the transient hints instead, if necessary */ X11_XSetTransientForHint(display, window, RootWindow(display, screen)); } @@ -656,67 +656,39 @@ X11_SetWindowTitle(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; - XTextProperty titleprop, iconprop; + XTextProperty titleprop; Status status; - const char *title = window->title; - const char *icon = NULL; + const char *title = window->title ? window->title : ""; + char *title_locale = NULL; #ifdef X_HAVE_UTF8_STRING Atom _NET_WM_NAME = data->videodata->_NET_WM_NAME; - Atom _NET_WM_ICON_NAME = data->videodata->_NET_WM_ICON_NAME; #endif - if (title != NULL) { - char *title_locale = SDL_iconv_utf8_locale(title); - if (!title_locale) { - SDL_OutOfMemory(); - return; - } - status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop); - SDL_free(title_locale); - if (status) { - X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME); + title_locale = SDL_iconv_utf8_locale(title); + if (!title_locale) { + SDL_OutOfMemory(); + return; + } + + status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop); + SDL_free(title_locale); + if (status) { + X11_XSetTextProperty(display, data->xwindow, &titleprop, XA_WM_NAME); + X11_XFree(titleprop.value); + } +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1, + XUTF8StringStyle, &titleprop); + if (status == Success) { + X11_XSetTextProperty(display, data->xwindow, &titleprop, + _NET_WM_NAME); X11_XFree(titleprop.value); } -#ifdef X_HAVE_UTF8_STRING - if (SDL_X11_HAVE_UTF8) { - status = - X11_Xutf8TextListToTextProperty(display, (char **) &title, 1, - XUTF8StringStyle, &titleprop); - if (status == Success) { - X11_XSetTextProperty(display, data->xwindow, &titleprop, - _NET_WM_NAME); - X11_XFree(titleprop.value); - } - } -#endif } - if (icon != NULL) { - char *icon_locale = SDL_iconv_utf8_locale(icon); - if (!icon_locale) { - SDL_OutOfMemory(); - return; - } - status = X11_XStringListToTextProperty(&icon_locale, 1, &iconprop); - SDL_free(icon_locale); - if (status) { - X11_XSetTextProperty(display, data->xwindow, &iconprop, - XA_WM_ICON_NAME); - X11_XFree(iconprop.value); - } -#ifdef X_HAVE_UTF8_STRING - if (SDL_X11_HAVE_UTF8) { - status = - X11_Xutf8TextListToTextProperty(display, (char **) &icon, 1, - XUTF8StringStyle, &iconprop); - if (status == Success) { - X11_XSetTextProperty(display, data->xwindow, &iconprop, - _NET_WM_ICON_NAME); - X11_XFree(iconprop.value); - } - } #endif - } + X11_XFlush(display); } diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 789d2f7cc..ce3f58439 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -27,8 +27,7 @@ video mode changes and we can respond to them by triggering more mode changes. */ -#define PENDING_FOCUS_IN_TIME 200 -#define PENDING_FOCUS_OUT_TIME 200 +#define PENDING_FOCUS_TIME 200 #if SDL_VIDEO_OPENGL_EGL #include diff --git a/test/Makefile.in b/test/Makefile.in index 79edbc31a..1a8cec614 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -38,6 +38,7 @@ TARGETS = \ testloadso$(EXE) \ testlock$(EXE) \ testmultiaudio$(EXE) \ + testaudiohotplug$(EXE) \ testnative$(EXE) \ testoverlay2$(EXE) \ testplatform$(EXE) \ @@ -105,6 +106,9 @@ testautomation$(EXE): $(srcdir)/testautomation.c \ testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) +testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c + $(CC) -o $@ $^ $(CFLAGS) $(LIBS) + testatomic$(EXE): $(srcdir)/testatomic.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) @@ -196,6 +200,15 @@ testnative$(EXE): $(srcdir)/testnative.c \ $(CC) -o $@ $^ $(CFLAGS) $(LIBS) @XLIB@ endif +#there's probably a better way of doing this +ifeq (@ISMACOSX@,false) +ifeq (@ISWINDOWS@,false) +ifeq (@ISUNIX@,false) +testnative$(EXE): ; +endif +endif +endif + testoverlay2$(EXE): $(srcdir)/testoverlay2.c $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/test/checkkeys.c b/test/checkkeys.c index e157b2892..1f03265d0 100644 --- a/test/checkkeys.c +++ b/test/checkkeys.c @@ -19,8 +19,14 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" +int done; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -128,12 +134,37 @@ PrintText(char *text) SDL_Log("Text (%s): \"%s%s\"\n", expanded, *text == '"' ? "\\" : "", text); } +void +loop() +{ + SDL_Event event; + /* Check for events */ + /*SDL_WaitEvent(&event); emscripten does not like waiting*/ + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + //case SDL_KEYUP: + PrintKey(&event.key.keysym, (event.key.state == SDL_PRESSED) ? SDL_TRUE : SDL_FALSE, (event.key.repeat) ? SDL_TRUE : SDL_FALSE); + break; + case SDL_TEXTINPUT: + PrintText(event.text.text); + break; + case SDL_MOUSEBUTTONDOWN: + /* Any button press quits the app... */ + case SDL_QUIT: + done = 1; + break; + default: + break; + } + } +} + int main(int argc, char *argv[]) { SDL_Window *window; - SDL_Event event; - int done; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -163,26 +194,14 @@ main(int argc, char *argv[]) /* Watch keystrokes */ done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ - SDL_WaitEvent(&event); - switch (event.type) { - case SDL_KEYDOWN: - case SDL_KEYUP: - PrintKey(&event.key.keysym, (event.key.state == SDL_PRESSED) ? SDL_TRUE : SDL_FALSE, (event.key.repeat) ? SDL_TRUE : SDL_FALSE); - break; - case SDL_TEXTINPUT: - PrintText(event.text.text); - break; - case SDL_MOUSEBUTTONDOWN: - /* Any button press quits the app... */ - case SDL_QUIT: - done = 1; - break; - default: - break; - } + loop(); } +#endif SDL_Quit(); return (0); diff --git a/test/configure b/test/configure index c4545ecb8..61c32fba1 100755 --- a/test/configure +++ b/test/configure @@ -2980,6 +2980,11 @@ fi MATHLIB="" SYS_GL_LIBS="-lGLES_CM" ;; + *-*-emscripten* ) + EXE=".bc" + MATHLIB="" + SYS_GL_LIBS="" + ;; *) ISUNIX="true" EXE="" diff --git a/test/configure.in b/test/configure.in index a55e63df8..fd3f3022b 100644 --- a/test/configure.in +++ b/test/configure.in @@ -65,6 +65,12 @@ case "$host" in MATHLIB="" SYS_GL_LIBS="-lGLES_CM" ;; + *-*-emscripten* ) + dnl This should really be .js, but we need to specify extra flags when compiling to js + EXE=".bc" + MATHLIB="" + SYS_GL_LIBS="" + ;; *) dnl Oh well, call it Unix... ISUNIX="true" diff --git a/test/controllermap.c b/test/controllermap.c index fd7b14440..8e5d13e0c 100644 --- a/test/controllermap.c +++ b/test/controllermap.c @@ -191,7 +191,6 @@ WatchJoystick(SDL_Joystick * joystick) step->button = -1; step->hat = -1; step->hat_value = -1; - SDL_SetClipboardText("TESTING TESTING 123"); switch(step->marker) { case MARKER_AXIS: diff --git a/test/emscripten/joystick-pre.js b/test/emscripten/joystick-pre.js new file mode 100644 index 000000000..5fd789d1f --- /dev/null +++ b/test/emscripten/joystick-pre.js @@ -0,0 +1,25 @@ +Module['arguments'] = ['0']; +//Gamepads don't appear until a button is pressed and the joystick/gamepad tests expect one to be connected +Module['preRun'].push(function() +{ + Module['print']("Waiting for gamepad..."); + Module['addRunDependency']("gamepad"); + window.addEventListener('gamepadconnected', function() + { + //OK, got one + Module['removeRunDependency']("gamepad"); + }, false); + + //chrome + if(!!navigator.webkitGetGamepads) + { + var timeout = function() + { + if(navigator.webkitGetGamepads()[0] !== undefined) + Module['removeRunDependency']("gamepad"); + else + setTimeout(timeout, 100); + } + setTimeout(timeout, 100); + } +}); diff --git a/test/loopwave.c b/test/loopwave.c index 288cea4a6..e09fe0f72 100644 --- a/test/loopwave.c +++ b/test/loopwave.c @@ -24,8 +24,11 @@ #include #endif +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" -#include "SDL_audio.h" struct { @@ -75,6 +78,15 @@ poked(int sig) done = 1; } +#ifdef __EMSCRIPTEN__ +void +loop() +{ + if(done || (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)) + emscripten_cancel_main_loop(); +} +#endif + int main(int argc, char *argv[]) { @@ -131,8 +143,13 @@ main(int argc, char *argv[]) /* Let the audio run */ SDL_PauseAudio(0); + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) SDL_Delay(1000); +#endif /* Clean up on signal */ SDL_CloseAudio(); diff --git a/test/loopwavequeue.c b/test/loopwavequeue.c index 8ca31dd03..babff3b3f 100644 --- a/test/loopwavequeue.c +++ b/test/loopwavequeue.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" #if HAVE_SIGNAL_H @@ -45,10 +49,32 @@ poked(int sig) done = 1; } +void +loop() +{ +#ifdef __EMSCRIPTEN__ + if (done || (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)) { + emscripten_cancel_main_loop(); + } + else +#endif + { + /* The device from SDL_OpenAudio() is always device #1. */ + const Uint32 queued = SDL_GetQueuedAudioSize(1); + SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); + if (queued <= 8192) { /* time to requeue the whole thing? */ + if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { + SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); + } else { + SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); + } + } + } +} + int main(int argc, char *argv[]) { - int i; char filename[4096]; /* Enable standard application logging */ @@ -97,25 +123,22 @@ main(int argc, char *argv[]) /* Let the audio run */ SDL_PauseAudio(0); + done = 0; + /* Note that we stuff the entire audio buffer into the queue in one shot. Most apps would want to feed it a little at a time, as it plays, but we're going for simplicity here. */ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) { - /* The device from SDL_OpenAudio() is always device #1. */ - const Uint32 queued = SDL_GetQueuedAudioSize(1); - SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); - if (queued <= 8192) { /* time to requeue the whole thing? */ - if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { - SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); - } else { - SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); - } - } + loop(); SDL_Delay(100); /* let it play for awhile. */ } +#endif /* Clean up on signal */ SDL_CloseAudio(); diff --git a/test/relative_mode.markdown b/test/relative_mode.markdown index 9ae88aa1c..5b2ed6185 100644 --- a/test/relative_mode.markdown +++ b/test/relative_mode.markdown @@ -37,9 +37,11 @@ Code int main(int argc, char *argv[]) { + SDL_Window *win; + SDL_Init(SDL_INIT_VIDEO); - SDL_Window *win = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0); + win = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, 0); SDL_SetRelativeMouseMode(SDL_TRUE); while (1) diff --git a/test/testatomic.c b/test/testatomic.c index 662a017ca..178de7ac1 100644 --- a/test/testatomic.c +++ b/test/testatomic.c @@ -12,9 +12,6 @@ #include #include "SDL.h" -#include "SDL_atomic.h" -#include "SDL_assert.h" -#include "SDL_cpuinfo.h" /* Absolutely basic tests just to see if we get the expected value diff --git a/test/testaudiohotplug.c b/test/testaudiohotplug.c new file mode 100644 index 000000000..6c3d88cd1 --- /dev/null +++ b/test/testaudiohotplug.c @@ -0,0 +1,183 @@ +/* + Copyright (C) 1997-2014 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Program to test hotplugging of audio devices */ + +#include "SDL_config.h" + +#include +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#ifdef __EMSCRIPTEN__ +#include +#endif + +#include "SDL.h" + +static SDL_AudioSpec spec; +static Uint8 *sound = NULL; /* Pointer to wave data */ +static Uint32 soundlen = 0; /* Length of wave data */ + +static int posindex = 0; +static Uint32 positions[64]; + +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void +quit(int rc) +{ + SDL_Quit(); + exit(rc); +} + +void SDLCALL +fillerup(void *_pos, Uint8 * stream, int len) +{ + Uint32 pos = *((Uint32 *) _pos); + Uint8 *waveptr; + int waveleft; + + /* Set up the pointers */ + waveptr = sound + pos; + waveleft = soundlen - pos; + + /* Go! */ + while (waveleft <= len) { + SDL_memcpy(stream, waveptr, waveleft); + stream += waveleft; + len -= waveleft; + waveptr = sound; + waveleft = soundlen; + pos = 0; + } + SDL_memcpy(stream, waveptr, len); + pos += len; + *((Uint32 *) _pos) = pos; +} + +static int done = 0; +void +poked(int sig) +{ + done = 1; +} + +static void +iteration() +{ + SDL_Event e; + SDL_AudioDeviceID dev; + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + done = 1; + } else if (e.type == SDL_AUDIODEVICEADDED) { + const char *name = SDL_GetAudioDeviceName(e.adevice.which, 0); + SDL_Log("New %s audio device: %s\n", e.adevice.iscapture ? "capture" : "output", name); + if (!e.adevice.iscapture) { + positions[posindex] = 0; + spec.userdata = &positions[posindex++]; + spec.callback = fillerup; + dev = SDL_OpenAudioDevice(name, 0, &spec, NULL, 0); + if (!dev) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open '%s': %s\n", name, SDL_GetError()); + } else { + SDL_Log("Opened '%s' as %u\n", name, (unsigned int) dev); + SDL_PauseAudioDevice(dev, 0); + } + } + } else if (e.type == SDL_AUDIODEVICEREMOVED) { + dev = (SDL_AudioDeviceID) e.adevice.which; + SDL_Log("%s device %u removed.\n", e.adevice.iscapture ? "capture" : "output", (unsigned int) dev); + SDL_CloseAudioDevice(dev); + } + } +} + +#ifdef __EMSCRIPTEN__ +void +loop() +{ + if(done) + emscripten_cancel_main_loop(); + else + iteration(); +} +#endif + +int +main(int argc, char *argv[]) +{ + int i; + char filename[4096]; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Load the SDL library */ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return (1); + } + + /* Some targets (Mac CoreAudio) need an event queue for audio hotplug, so make and immediately hide a window. */ + SDL_MinimizeWindow(SDL_CreateWindow("testaudiohotplug", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0)); + + if (argc > 1) { + SDL_strlcpy(filename, argv[1], sizeof(filename)); + } else { + SDL_strlcpy(filename, "sample.wav", sizeof(filename)); + } + /* Load the wave file into memory */ + if (SDL_LoadWAV(filename, &spec, &sound, &soundlen) == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); + quit(1); + } + +#if HAVE_SIGNAL_H + /* Set the signals */ +#ifdef SIGHUP + signal(SIGHUP, poked); +#endif + signal(SIGINT, poked); +#ifdef SIGQUIT + signal(SIGQUIT, poked); +#endif + signal(SIGTERM, poked); +#endif /* HAVE_SIGNAL_H */ + + /* Show the list of available drivers */ + SDL_Log("Available audio drivers:"); + for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) { + SDL_Log("%i: %s", i, SDL_GetAudioDriver(i)); + } + + SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver()); + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + SDL_Delay(100); + iteration(); + } +#endif + + /* Clean up on signal */ + SDL_Quit(); + SDL_FreeWAV(sound); + return (0); +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/testautomation.c b/test/testautomation.c index 8eab76e9c..ceb352ab7 100644 --- a/test/testautomation.c +++ b/test/testautomation.c @@ -62,7 +62,7 @@ main(int argc, char *argv[]) } else if (SDL_strcasecmp(argv[i], "--execKey") == 0) { if (argv[i + 1]) { - SDL_sscanf(argv[i + 1], "%llu", (long long unsigned int *)&userExecKey); + SDL_sscanf(argv[i + 1], "%"SDL_PRIu64, (long long unsigned int *)&userExecKey); consumed = 2; } } diff --git a/test/testautomation_platform.c b/test/testautomation_platform.c index 5228bfdc7..5211a4a70 100644 --- a/test/testautomation_platform.c +++ b/test/testautomation_platform.c @@ -92,11 +92,7 @@ int platform_testEndianessAndSwap(void *arg) /* Test 64 swap. */ SDLTest_AssertCheck( SDL_Swap64(value64) == swapped64, -#ifdef _MSC_VER - "SDL_Swap64(): 64 bit swapped: 0x%I64X => 0x%I64X", -#else - "SDL_Swap64(): 64 bit swapped: 0x%llX => 0x%llX", -#endif + "SDL_Swap64(): 64 bit swapped: 0x%"SDL_PRIX64" => 0x%"SDL_PRIX64, value64, SDL_Swap64(value64) ); return TEST_COMPLETED; diff --git a/test/testautomation_rwops.c b/test/testautomation_rwops.c index 3a1f682f2..16f2161fe 100644 --- a/test/testautomation_rwops.c +++ b/test/testautomation_rwops.c @@ -105,7 +105,7 @@ _testGenericRWopsValidations(SDL_RWops *rw, int write) /* Set to start. */ i = SDL_RWseek(rw, 0, RW_SEEK_SET ); SDLTest_AssertPass("Call to SDL_RWseek succeeded"); - SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (RW_SEEK_SET), expected 0, got %lli", i); + SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (RW_SEEK_SET), expected 0, got %"SDL_PRIs64, i); /* Test write. */ s = SDL_RWwrite(rw, RWopsHelloWorldTestString, sizeof(RWopsHelloWorldTestString)-1, 1); @@ -120,12 +120,12 @@ _testGenericRWopsValidations(SDL_RWops *rw, int write) /* Test seek to random position */ i = SDL_RWseek( rw, seekPos, RW_SEEK_SET ); SDLTest_AssertPass("Call to SDL_RWseek succeeded"); - SDLTest_AssertCheck(i == (Sint64)seekPos, "Verify seek to %i with SDL_RWseek (RW_SEEK_SET), expected %i, got %lli", seekPos, seekPos, i); + SDLTest_AssertCheck(i == (Sint64)seekPos, "Verify seek to %i with SDL_RWseek (RW_SEEK_SET), expected %i, got %"SDL_PRIs64, seekPos, seekPos, i); /* Test seek back to start */ i = SDL_RWseek(rw, 0, RW_SEEK_SET ); SDLTest_AssertPass("Call to SDL_RWseek succeeded"); - SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (RW_SEEK_SET), expected 0, got %lli", i); + SDLTest_AssertCheck(i == (Sint64)0, "Verify seek to 0 with SDL_RWseek (RW_SEEK_SET), expected 0, got %"SDL_PRIs64, i); /* Test read */ s = SDL_RWread( rw, buf, 1, sizeof(RWopsHelloWorldTestString)-1 ); @@ -144,7 +144,7 @@ _testGenericRWopsValidations(SDL_RWops *rw, int write) SDLTest_AssertPass("Call to SDL_RWseek(...,-4,RW_SEEK_CUR) succeeded"); SDLTest_AssertCheck( i == (Sint64)(sizeof(RWopsHelloWorldTestString)-5), - "Verify seek to -4 with SDL_RWseek (RW_SEEK_CUR), expected %i, got %lli", + "Verify seek to -4 with SDL_RWseek (RW_SEEK_CUR), expected %i, got %"SDL_PRIs64, sizeof(RWopsHelloWorldTestString)-5, i); @@ -152,7 +152,7 @@ _testGenericRWopsValidations(SDL_RWops *rw, int write) SDLTest_AssertPass("Call to SDL_RWseek(...,-1,RW_SEEK_END) succeeded"); SDLTest_AssertCheck( i == (Sint64)(sizeof(RWopsHelloWorldTestString)-2), - "Verify seek to -1 with SDL_RWseek (RW_SEEK_END), expected %i, got %lli", + "Verify seek to -1 with SDL_RWseek (RW_SEEK_END), expected %i, got %"SDL_PRIs64, sizeof(RWopsHelloWorldTestString)-2, i); @@ -161,7 +161,7 @@ _testGenericRWopsValidations(SDL_RWops *rw, int write) SDLTest_AssertPass("Call to SDL_RWseek(...,0,invalid_whence) succeeded"); SDLTest_AssertCheck( i == (Sint64)(-1), - "Verify seek with SDL_RWseek (invalid_whence); expected: -1, got %lli", + "Verify seek with SDL_RWseek (invalid_whence); expected: -1, got %"SDL_PRIs64, i); } @@ -560,7 +560,7 @@ rwops_testCompareRWFromMemWithRWFromFile(void) /* Compare */ SDLTest_AssertCheck(rv_mem == rv_file, "Verify returned read blocks matches for mem and file reads; got: rv_mem=%d rv_file=%d", rv_mem, rv_file); - SDLTest_AssertCheck(sv_mem == sv_file, "Verify SEEK_END position matches for mem and file seeks; got: sv_mem=%llu sv_file=%llu", sv_mem, sv_file); + SDLTest_AssertCheck(sv_mem == sv_file, "Verify SEEK_END position matches for mem and file seeks; got: sv_mem=%"SDL_PRIu64" sv_file=%"SDL_PRIu64, sv_mem, sv_file); SDLTest_AssertCheck(buffer_mem[slen] == 0, "Verify mem buffer termination; expected: 0, got: %d", buffer_mem[slen]); SDLTest_AssertCheck(buffer_file[slen] == 0, "Verify file buffer termination; expected: 0, got: %d", buffer_file[slen]); SDLTest_AssertCheck( @@ -668,7 +668,7 @@ rwops_testFileWriteReadEndian(void) /* Test seek to start */ result = SDL_RWseek( rw, 0, RW_SEEK_SET ); SDLTest_AssertPass("Call to SDL_RWseek succeeded"); - SDLTest_AssertCheck(result == 0, "Verify result from position 0 with SDL_RWseek, expected 0, got %lli", result); + SDLTest_AssertCheck(result == 0, "Verify result from position 0 with SDL_RWseek, expected 0, got %"SDL_PRIs64, result); /* Read test data */ BE16test = SDL_ReadBE16(rw); @@ -679,7 +679,7 @@ rwops_testFileWriteReadEndian(void) SDLTest_AssertCheck(BE32test == BE32value, "Validate return value from SDL_ReadBE32, expected: %u, got: %u", BE32value, BE32test); BE64test = SDL_ReadBE64(rw); SDLTest_AssertPass("Call to SDL_ReadBE64()"); - SDLTest_AssertCheck(BE64test == BE64value, "Validate return value from SDL_ReadBE64, expected: %llu, got: %llu", BE64value, BE64test); + SDLTest_AssertCheck(BE64test == BE64value, "Validate return value from SDL_ReadBE64, expected: %"SDL_PRIu64", got: %"SDL_PRIu64, BE64value, BE64test); LE16test = SDL_ReadLE16(rw); SDLTest_AssertPass("Call to SDL_ReadLE16()"); SDLTest_AssertCheck(LE16test == LE16value, "Validate return value from SDL_ReadLE16, expected: %hu, got: %hu", LE16value, LE16test); @@ -688,7 +688,7 @@ rwops_testFileWriteReadEndian(void) SDLTest_AssertCheck(LE32test == LE32value, "Validate return value from SDL_ReadLE32, expected: %u, got: %u", LE32value, LE32test); LE64test = SDL_ReadLE64(rw); SDLTest_AssertPass("Call to SDL_ReadLE64()"); - SDLTest_AssertCheck(LE64test == LE64value, "Validate return value from SDL_ReadLE64, expected: %llu, got: %llu", LE64value, LE64test); + SDLTest_AssertCheck(LE64test == LE64value, "Validate return value from SDL_ReadLE64, expected: %"SDL_PRIu64", got: %"SDL_PRIu64, LE64value, LE64test); /* Close handle */ cresult = SDL_RWclose(rw); diff --git a/test/testautomation_sdltest.c b/test/testautomation_sdltest.c index 2238ba4f0..ec1da8a50 100644 --- a/test/testautomation_sdltest.c +++ b/test/testautomation_sdltest.c @@ -93,35 +93,35 @@ sdltest_randomNumber(void *arg) result = (Sint64)SDLTest_RandomUint8(); umax = (1 << 8) - 1; SDLTest_AssertPass("Call to SDLTest_RandomUint8"); - SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%llu], got: %lld", umax, result); + SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%"SDL_PRIu64"], got: %"SDL_PRIs64, umax, result); result = (Sint64)SDLTest_RandomSint8(); min = 0 - (1 << 7); max = (1 << 7) - 1; SDLTest_AssertPass("Call to SDLTest_RandomSint8"); - SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%lld,%lld], got: %lld", min, max, result); + SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%"SDL_PRIs64",%"SDL_PRIs64"], got: %"SDL_PRIs64, min, max, result); result = (Sint64)SDLTest_RandomUint16(); umax = (1 << 16) - 1; SDLTest_AssertPass("Call to SDLTest_RandomUint16"); - SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%llu], got: %lld", umax, result); + SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%"SDL_PRIu64"], got: %"SDL_PRIs64, umax, result); result = (Sint64)SDLTest_RandomSint16(); min = 0 - (1 << 15); max = (1 << 15) - 1; SDLTest_AssertPass("Call to SDLTest_RandomSint16"); - SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%lld,%lld], got: %lld", min, max, result); + SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%"SDL_PRIs64",%"SDL_PRIs64"], got: %"SDL_PRIs64, min, max, result); result = (Sint64)SDLTest_RandomUint32(); umax = ((Uint64)1 << 32) - 1; SDLTest_AssertPass("Call to SDLTest_RandomUint32"); - SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%llu], got: %lld", umax, result); + SDLTest_AssertCheck(result >= 0 && result <= (Sint64)umax, "Verify result value, expected: [0,%"SDL_PRIu64"], got: %"SDL_PRIs64, umax, result); result = (Sint64)SDLTest_RandomSint32(); min = 0 - ((Sint64)1 << 31); max = ((Sint64)1 << 31) - 1; SDLTest_AssertPass("Call to SDLTest_RandomSint32"); - SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%lld,%lld], got: %lld", min, max, result); + SDLTest_AssertCheck(result >= min && result <= max, "Verify result value, expected: [%"SDL_PRIs64",%"SDL_PRIs64"], got: %"SDL_PRIs64, min, max, result); uresult = SDLTest_RandomUint64(); SDLTest_AssertPass("Call to SDLTest_RandomUint64"); @@ -166,63 +166,63 @@ sdltest_randomBoundaryNumberUint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", uresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", uresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", uresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12 || uresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", uresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 0 || uresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", uresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(0, 99, SDL_FALSE) returns 100 */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(0, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 100, - "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %lld", uresult); + "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 0xff, SDL_FALSE) returns 0 (no error) */ uresult = (Uint64)SDLTest_RandomUint8BoundaryValue(1, 255, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters (1,255,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters (1,255,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -232,7 +232,7 @@ sdltest_randomBoundaryNumberUint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 0xff, - "Validate result value for parameters (0,254,SDL_FALSE); expected: 0xff, got: %lld", uresult); + "Validate result value for parameters (0,254,SDL_FALSE); expected: 0xff, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -242,7 +242,7 @@ sdltest_randomBoundaryNumberUint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint8BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters(0,255,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters(0,255,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -276,63 +276,63 @@ sdltest_randomBoundaryNumberUint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", uresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", uresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", uresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12 || uresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", uresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 0 || uresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", uresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(0, 99, SDL_FALSE) returns 100 */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(0, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 100, - "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %lld", uresult); + "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 0xffff, SDL_FALSE) returns 0 (no error) */ uresult = (Uint64)SDLTest_RandomUint16BoundaryValue(1, 0xffff, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters (1,0xffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters (1,0xffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -342,7 +342,7 @@ sdltest_randomBoundaryNumberUint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 0xffff, - "Validate result value for parameters (0,0xfffe,SDL_FALSE); expected: 0xffff, got: %lld", uresult); + "Validate result value for parameters (0,0xfffe,SDL_FALSE); expected: 0xffff, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -352,7 +352,7 @@ sdltest_randomBoundaryNumberUint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint16BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters(0,0xffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters(0,0xffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -386,63 +386,63 @@ sdltest_randomBoundaryNumberUint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", uresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", uresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", uresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12 || uresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", uresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 0 || uresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", uresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(0, 99, SDL_FALSE) returns 100 */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(0, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 100, - "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %lld", uresult); + "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 0xffffffff, SDL_FALSE) returns 0 (no error) */ uresult = (Uint64)SDLTest_RandomUint32BoundaryValue(1, 0xffffffff, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters (1,0xffffffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters (1,0xffffffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -452,7 +452,7 @@ sdltest_randomBoundaryNumberUint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 0xffffffff, - "Validate result value for parameters (0,0xfffffffe,SDL_FALSE); expected: 0xffffffff, got: %lld", uresult); + "Validate result value for parameters (0,0xfffffffe,SDL_FALSE); expected: 0xffffffff, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -462,7 +462,7 @@ sdltest_randomBoundaryNumberUint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint32BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters(0,0xffffffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters(0,0xffffffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -496,63 +496,63 @@ sdltest_randomBoundaryNumberUint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", uresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", uresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", uresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 12 || uresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", uresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 10 || uresult == 11 || uresult == 19 || uresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", uresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 0 || uresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", uresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(0, 99, SDL_FALSE) returns 100 */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(0, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 100, - "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %lld", uresult); + "Validate result value for parameters (0,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, uresult); /* RandomUintXBoundaryValue(1, 0xffffffffffffffff, SDL_FALSE) returns 0 (no error) */ uresult = (Uint64)SDLTest_RandomUint64BoundaryValue(1, (Uint64)0xffffffffffffffffULL, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters (1,0xffffffffffffffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters (1,0xffffffffffffffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -562,7 +562,7 @@ sdltest_randomBoundaryNumberUint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == (Uint64)0xffffffffffffffffULL, - "Validate result value for parameters (0,0xfffffffffffffffe,SDL_FALSE); expected: 0xffffffffffffffff, got: %lld", uresult); + "Validate result value for parameters (0,0xfffffffffffffffe,SDL_FALSE); expected: 0xffffffffffffffff, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -572,7 +572,7 @@ sdltest_randomBoundaryNumberUint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomUint64BoundaryValue"); SDLTest_AssertCheck( uresult == 0, - "Validate result value for parameters(0,0xffffffffffffffff,SDL_FALSE); expected: 0, got: %lld", uresult); + "Validate result value for parameters(0,0xffffffffffffffff,SDL_FALSE); expected: 0, got: %"SDL_PRIs64, uresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -606,63 +606,63 @@ sdltest_randomBoundaryNumberSint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", sresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", sresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", sresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12 || sresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", sresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 0 || sresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", sresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(SCHAR_MIN, 99, SDL_FALSE) returns 100 */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(SCHAR_MIN, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == 100, - "Validate result value for parameters (SCHAR_MIN,99,SDL_FALSE); expected: 100, got: %lld", sresult); + "Validate result value for parameters (SCHAR_MIN,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(SCHAR_MIN + 1, SCHAR_MAX, SDL_FALSE) returns SCHAR_MIN (no error) */ sresult = (Sint64)SDLTest_RandomSint8BoundaryValue(SCHAR_MIN + 1, SCHAR_MAX, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == SCHAR_MIN, - "Validate result value for parameters (SCHAR_MIN + 1,SCHAR_MAX,SDL_FALSE); expected: %d, got: %lld", SCHAR_MIN, sresult); + "Validate result value for parameters (SCHAR_MIN + 1,SCHAR_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SCHAR_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -672,7 +672,7 @@ sdltest_randomBoundaryNumberSint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == SCHAR_MAX, - "Validate result value for parameters (SCHAR_MIN,SCHAR_MAX - 1,SDL_FALSE); expected: %d, got: %lld", SCHAR_MAX, sresult); + "Validate result value for parameters (SCHAR_MIN,SCHAR_MAX - 1,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SCHAR_MAX, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -682,7 +682,7 @@ sdltest_randomBoundaryNumberSint8(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint8BoundaryValue"); SDLTest_AssertCheck( sresult == SCHAR_MIN, - "Validate result value for parameters(SCHAR_MIN,SCHAR_MAX,SDL_FALSE); expected: %d, got: %lld", SCHAR_MIN, sresult); + "Validate result value for parameters(SCHAR_MIN,SCHAR_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SCHAR_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -716,63 +716,63 @@ sdltest_randomBoundaryNumberSint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", sresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", sresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", sresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12 || sresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", sresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 0 || sresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", sresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(SHRT_MIN, 99, SDL_FALSE) returns 100 */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(SHRT_MIN, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == 100, - "Validate result value for parameters (SHRT_MIN,99,SDL_FALSE); expected: 100, got: %lld", sresult); + "Validate result value for parameters (SHRT_MIN,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(SHRT_MIN + 1, SHRT_MAX, SDL_FALSE) returns SHRT_MIN (no error) */ sresult = (Sint64)SDLTest_RandomSint16BoundaryValue(SHRT_MIN + 1, SHRT_MAX, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == SHRT_MIN, - "Validate result value for parameters (SHRT_MIN+1,SHRT_MAX,SDL_FALSE); expected: %d, got: %lld", SHRT_MIN, sresult); + "Validate result value for parameters (SHRT_MIN+1,SHRT_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SHRT_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -782,7 +782,7 @@ sdltest_randomBoundaryNumberSint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == SHRT_MAX, - "Validate result value for parameters (SHRT_MIN,SHRT_MAX - 1,SDL_FALSE); expected: %d, got: %lld", SHRT_MAX, sresult); + "Validate result value for parameters (SHRT_MIN,SHRT_MAX - 1,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SHRT_MAX, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -792,7 +792,7 @@ sdltest_randomBoundaryNumberSint16(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint16BoundaryValue"); SDLTest_AssertCheck( sresult == SHRT_MIN, - "Validate result value for parameters(SHRT_MIN,SHRT_MAX,SDL_FALSE); expected: %d, got: %lld", SHRT_MIN, sresult); + "Validate result value for parameters(SHRT_MIN,SHRT_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, SHRT_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -833,63 +833,63 @@ sdltest_randomBoundaryNumberSint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", sresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", sresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", sresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12 || sresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", sresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 0 || sresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", sresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(LONG_MIN, 99, SDL_FALSE) returns 100 */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(long_min, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == 100, - "Validate result value for parameters (LONG_MIN,99,SDL_FALSE); expected: 100, got: %lld", sresult); + "Validate result value for parameters (LONG_MIN,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(LONG_MIN + 1, LONG_MAX, SDL_FALSE) returns LONG_MIN (no error) */ sresult = (Sint64)SDLTest_RandomSint32BoundaryValue(long_min + 1, long_max, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == long_min, - "Validate result value for parameters (LONG_MIN+1,LONG_MAX,SDL_FALSE); expected: %d, got: %lld", long_min, sresult); + "Validate result value for parameters (LONG_MIN+1,LONG_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, long_min, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -899,7 +899,7 @@ sdltest_randomBoundaryNumberSint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == long_max, - "Validate result value for parameters (LONG_MIN,LONG_MAX - 1,SDL_FALSE); expected: %d, got: %lld", long_max, sresult); + "Validate result value for parameters (LONG_MIN,LONG_MAX - 1,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, long_max, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -909,7 +909,7 @@ sdltest_randomBoundaryNumberSint32(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint32BoundaryValue"); SDLTest_AssertCheck( sresult == long_min, - "Validate result value for parameters(LONG_MIN,LONG_MAX,SDL_FALSE); expected: %d, got: %lld", long_min, sresult); + "Validate result value for parameters(LONG_MIN,LONG_MAX,SDL_FALSE); expected: %d, got: %"SDL_PRIs64, long_min, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, @@ -943,63 +943,63 @@ sdltest_randomBoundaryNumberSint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10, - "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %lld", sresult); + "Validate result value for parameters (10,10,SDL_TRUE); expected: 10, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 11, SDL_TRUE) returns 10, 11 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(10, 11, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11, - "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %lld", sresult); + "Validate result value for parameters (10,11,SDL_TRUE); expected: 10|11, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 12, SDL_TRUE) returns 10, 11, 12 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(10, 12, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12, - "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %lld", sresult); + "Validate result value for parameters (10,12,SDL_TRUE); expected: 10|11|12, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 13, SDL_TRUE) returns 10, 11, 12, 13 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(10, 13, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 12 || sresult == 13, - "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %lld", sresult); + "Validate result value for parameters (10,13,SDL_TRUE); expected: 10|11|12|13, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(10, 20, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(10, 20, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (10,20,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(20, 10, SDL_TRUE) returns 10, 11, 19 or 20 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(20, 10, SDL_TRUE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 10 || sresult == 11 || sresult == 19 || sresult == 20, - "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %lld", sresult); + "Validate result value for parameters (20,10,SDL_TRUE); expected: 10|11|19|20, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(1, 20, SDL_FALSE) returns 0, 21 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(1, 20, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 0 || sresult == 21, - "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %lld", sresult); + "Validate result value for parameters (1,20,SDL_FALSE); expected: 0|21, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(LLONG_MIN, 99, SDL_FALSE) returns 100 */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(LLONG_MIN, 99, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == 100, - "Validate result value for parameters (LLONG_MIN,99,SDL_FALSE); expected: 100, got: %lld", sresult); + "Validate result value for parameters (LLONG_MIN,99,SDL_FALSE); expected: 100, got: %"SDL_PRIs64, sresult); /* RandomSintXBoundaryValue(LLONG_MIN + 1, LLONG_MAX, SDL_FALSE) returns LLONG_MIN (no error) */ sresult = (Sint64)SDLTest_RandomSint64BoundaryValue(LLONG_MIN + 1, LLONG_MAX, SDL_FALSE); SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == LLONG_MIN, - "Validate result value for parameters (LLONG_MIN+1,LLONG_MAX,SDL_FALSE); expected: %lld, got: %lld", LLONG_MIN, sresult); + "Validate result value for parameters (LLONG_MIN+1,LLONG_MAX,SDL_FALSE); expected: %"SDL_PRIs64", got: %"SDL_PRIs64, LLONG_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -1009,7 +1009,7 @@ sdltest_randomBoundaryNumberSint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == LLONG_MAX, - "Validate result value for parameters (LLONG_MIN,LLONG_MAX - 1,SDL_FALSE); expected: %lld, got: %lld", LLONG_MAX, sresult); + "Validate result value for parameters (LLONG_MIN,LLONG_MAX - 1,SDL_FALSE); expected: %"SDL_PRIs64", got: %"SDL_PRIs64, LLONG_MAX, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError == NULL || lastError[0] == '\0', "Validate no error message was set"); @@ -1019,7 +1019,7 @@ sdltest_randomBoundaryNumberSint64(void *arg) SDLTest_AssertPass("Call to SDLTest_RandomSint64BoundaryValue"); SDLTest_AssertCheck( sresult == LLONG_MIN, - "Validate result value for parameters(LLONG_MIN,LLONG_MAX,SDL_FALSE); expected: %lld, got: %lld", LLONG_MIN, sresult); + "Validate result value for parameters(LLONG_MIN,LLONG_MAX,SDL_FALSE); expected: %"SDL_PRIs64", got: %"SDL_PRIs64, LLONG_MIN, sresult); lastError = (char *)SDL_GetError(); SDLTest_AssertPass("SDL_GetError()"); SDLTest_AssertCheck(lastError != NULL && SDL_strcmp(lastError, expectedError) == 0, diff --git a/test/testautomation_surface.c b/test/testautomation_surface.c index d65351a66..ca41d4a0c 100644 --- a/test/testautomation_surface.c +++ b/test/testautomation_surface.c @@ -8,6 +8,9 @@ #define _CRT_NONSTDC_NO_DEPRECATE #include +#ifndef _MSC_VER +#include +#endif #include #include "SDL.h" diff --git a/test/testautomation_timer.c b/test/testautomation_timer.c index 0e8364550..6d73856ee 100644 --- a/test/testautomation_timer.c +++ b/test/testautomation_timer.c @@ -42,7 +42,7 @@ timer_getPerformanceCounter(void *arg) result = SDL_GetPerformanceCounter(); SDLTest_AssertPass("Call to SDL_GetPerformanceCounter()"); - SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %llu", result); + SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %"SDL_PRIu64, result); return TEST_COMPLETED; } @@ -57,7 +57,7 @@ timer_getPerformanceFrequency(void *arg) result = SDL_GetPerformanceFrequency(); SDLTest_AssertPass("Call to SDL_GetPerformanceFrequency()"); - SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %llu", result); + SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %"SDL_PRIu64, result); return TEST_COMPLETED; } diff --git a/test/testautomation_video.c b/test/testautomation_video.c index f90ff5c2a..cfc4a238e 100644 --- a/test/testautomation_video.c +++ b/test/testautomation_video.c @@ -541,7 +541,6 @@ video_getWindowBrightnessNegative(void *arg) { const char *invalidWindowError = "Invalid window"; char *lastError; - const char* title = "video_getWindowBrightnessNegative Test Window"; float result; /* Call against invalid window */ @@ -728,7 +727,6 @@ video_getWindowGammaRamp(void *arg) int video_getWindowGammaRampNegative(void *arg) { - const char* title = "video_getWindowGammaRampNegative Test Window"; Uint16 red[256]; Uint16 green[256]; Uint16 blue[256]; diff --git a/test/testdraw2.c b/test/testdraw2.c index 8c14185cb..7685e3b2e 100644 --- a/test/testdraw2.c +++ b/test/testdraw2.c @@ -16,6 +16,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" #define NUM_OBJECTS 100 @@ -29,6 +33,8 @@ static int current_alpha = 255; static int current_color = 255; static SDL_BlendMode blendMode = SDL_BLENDMODE_NONE; +int done; + void DrawPoints(SDL_Renderer * renderer) { @@ -169,11 +175,35 @@ DrawRects(SDL_Renderer * renderer) } } +void +loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + for (i = 0; i < state->num_windows; ++i) { + SDL_Renderer *renderer = state->renderers[i]; + if (state->windows[i] == NULL) + continue; + SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); + SDL_RenderClear(renderer); + + DrawRects(renderer); + DrawLines(renderer); + DrawPoints(renderer); + + SDL_RenderPresent(renderer); + } +} + int main(int argc, char *argv[]) { - int i, done; - SDL_Event event; + int i; Uint32 then, now, frames; /* Enable standard application logging */ @@ -245,26 +275,16 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); + loop(); } - for (i = 0; i < state->num_windows; ++i) { - SDL_Renderer *renderer = state->renderers[i]; - if (state->windows[i] == NULL) - continue; - SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); - SDL_RenderClear(renderer); +#endif - DrawRects(renderer); - DrawLines(renderer); - DrawPoints(renderer); - - SDL_RenderPresent(renderer); - } - } SDLTest_CommonQuit(state); diff --git a/test/testdrawchessboard.c b/test/testdrawchessboard.c index 2456b6909..3272f5aeb 100644 --- a/test/testdrawchessboard.c +++ b/test/testdrawchessboard.c @@ -14,8 +14,19 @@ /* Sample program: Draw a Chess Board by using SDL_CreateSoftwareRenderer API */ +#include +#include + +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" +SDL_Window *window; +SDL_Renderer *renderer; +int done; + void DrawChessBoard(SDL_Renderer * renderer) { @@ -44,12 +55,33 @@ DrawChessBoard(SDL_Renderer * renderer) } } +void +loop() +{ + SDL_Event e; + if (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + done = 1; + return; + } + + if(e.key.keysym.sym == SDLK_ESCAPE) { + done = 1; + return; + } + } + + DrawChessBoard(renderer); + + /* Got everything on rendering surface, + now Update the drawing image on window screen */ + SDL_UpdateWindowSurface(window); +} + int main(int argc, char *argv[]) { - SDL_Window *window; SDL_Surface *surface; - SDL_Renderer *renderer; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -83,24 +115,14 @@ main(int argc, char *argv[]) /* Draw the Image on rendering surface */ - while(1) - { - SDL_Event e; - if (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT) - break; - - if(e.key.keysym.sym == SDLK_ESCAPE) - break; - } - - DrawChessBoard(renderer); - - /* Got everything on rendering surface, - now Update the drawing image on window screen */ - SDL_UpdateWindowSurface(window); - + done = 0; +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + loop(); } +#endif return 0; } diff --git a/test/testerror.c b/test/testerror.c index 1fa60885b..8290680e0 100644 --- a/test/testerror.c +++ b/test/testerror.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" static int alive = 0; diff --git a/test/testfile.c b/test/testfile.c index 172da865c..38a6bb799 100644 --- a/test/testfile.c +++ b/test/testfile.c @@ -22,7 +22,6 @@ #endif #include "SDL.h" -#include "SDL_endian.h" #include diff --git a/test/testfilesystem.c b/test/testfilesystem.c index 701b98ad6..197a5f7c4 100644 --- a/test/testfilesystem.c +++ b/test/testfilesystem.c @@ -25,6 +25,25 @@ main(int argc, char *argv[]) return 1; } + char *base_path = SDL_GetBasePath(); + if(base_path == NULL){ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find base path: %s\n", + SDL_GetError()); + return 0; + } + + SDL_Log("base path: '%s'\n", SDL_GetBasePath()); + SDL_free(base_path); + + char *pref_path = SDL_GetPrefPath("libsdl", "testfilesystem"); + if(pref_path == NULL){ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path: %s\n", + SDL_GetError()); + return 0; + } + SDL_Log("pref path: '%s'\n", SDL_GetPrefPath("libsdl", "testfilesystem")); + SDL_free(pref_path); + SDL_Log("base path: '%s'\n", SDL_GetBasePath()); SDL_Log("pref path: '%s'\n", SDL_GetPrefPath("libsdl", "testfilesystem")); diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c index 10046bd39..414872cf2 100644 --- a/test/testgamecontroller.c +++ b/test/testgamecontroller.c @@ -18,6 +18,10 @@ #include "SDL.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + #ifndef SDL_JOYSTICK_DISABLED #ifdef __IPHONEOS__ @@ -28,6 +32,40 @@ #define SCREEN_HEIGHT 317 #endif +/* This is indexed by SDL_GameControllerButton. */ +static const struct { int x; int y; } button_positions[] = { + {387, 167}, /* A */ + {431, 132}, /* B */ + {342, 132}, /* X */ + {389, 101}, /* Y */ + {174, 132}, /* BACK */ + {233, 132}, /* GUIDE */ + {289, 132}, /* START */ + {75, 154}, /* LEFTSTICK */ + {305, 230}, /* RIGHTSTICK */ + {77, 40}, /* LEFTSHOULDER */ + {396, 36}, /* RIGHTSHOULDER */ + {154, 188}, /* DPAD_UP */ + {154, 249}, /* DPAD_DOWN */ + {116, 217}, /* DPAD_LEFT */ + {186, 217}, /* DPAD_RIGHT */ +}; + +/* This is indexed by SDL_GameControllerAxis. */ +static const struct { int x; int y; double angle; } axis_positions[] = { + {75, 154, 0.0}, /* LEFTX */ + {75, 154, 90.0}, /* LEFTY */ + {305, 230, 0.0}, /* RIGHTX */ + {305, 230, 90.0}, /* RIGHTY */ + {91, 0, 90.0}, /* TRIGGERLEFT */ + {375, 0, 90.0}, /* TRIGGERRIGHT */ +}; + +SDL_Renderer *screen = NULL; +SDL_bool retval = SDL_FALSE; +SDL_bool done = SDL_FALSE; +SDL_Texture *background, *button, *axis; + static SDL_Texture * LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent) { @@ -60,49 +98,74 @@ LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent) return texture; } +void +loop(void *arg) +{ + SDL_Event event; + int i; + SDL_GameController *gamecontroller = (SDL_GameController *)arg; + + /* blank screen, set up for drawing this frame. */ + SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE); + SDL_RenderClear(screen); + SDL_RenderCopy(screen, background, NULL, NULL); + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + if (event.key.keysym.sym != SDLK_ESCAPE) { + break; + } + /* Fall through to signal quit */ + case SDL_QUIT: + done = SDL_TRUE; + break; + default: + break; + } + } + + /* Update visual controller state */ + for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) { + if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) { + const SDL_Rect dst = { button_positions[i].x, button_positions[i].y, 50, 50 }; + SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, 0); + } + } + + for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) { + const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */ + const Sint16 value = SDL_GameControllerGetAxis(gamecontroller, (SDL_GameControllerAxis)(i)); + if (value < -deadzone) { + const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 }; + const double angle = axis_positions[i].angle; + SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0); + } else if (value > deadzone) { + const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 }; + const double angle = axis_positions[i].angle + 180.0; + SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0); + } + } + + SDL_RenderPresent(screen); + + if (!SDL_GameControllerGetAttached(gamecontroller)) { + done = SDL_TRUE; + retval = SDL_TRUE; /* keep going, wait for reattach. */ + } +} + SDL_bool WatchGameController(SDL_GameController * gamecontroller) { - /* This is indexed by SDL_GameControllerButton. */ - static const struct { int x; int y; } button_positions[] = { - {387, 167}, /* A */ - {431, 132}, /* B */ - {342, 132}, /* X */ - {389, 101}, /* Y */ - {174, 132}, /* BACK */ - {233, 132}, /* GUIDE */ - {289, 132}, /* START */ - {75, 154}, /* LEFTSTICK */ - {305, 230}, /* RIGHTSTICK */ - {77, 40}, /* LEFTSHOULDER */ - {396, 36}, /* RIGHTSHOULDER */ - {154, 188}, /* DPAD_UP */ - {154, 249}, /* DPAD_DOWN */ - {116, 217}, /* DPAD_LEFT */ - {186, 217}, /* DPAD_RIGHT */ - }; - - /* This is indexed by SDL_GameControllerAxis. */ - static const struct { int x; int y; double angle; } axis_positions[] = { - {75, 154, 0.0}, /* LEFTX */ - {75, 154, 90.0}, /* LEFTY */ - {305, 230, 0.0}, /* RIGHTX */ - {305, 230, 90.0}, /* RIGHTY */ - {91, 0, 90.0}, /* TRIGGERLEFT */ - {375, 0, 90.0}, /* TRIGGERRIGHT */ - }; - const char *name = SDL_GameControllerName(gamecontroller); const char *basetitle = "Game Controller Test: "; const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + 1; char *title = (char *)SDL_malloc(titlelen); - SDL_Texture *background, *button, *axis; SDL_Window *window = NULL; - SDL_Renderer *screen = NULL; - SDL_bool retval = SDL_FALSE; - SDL_bool done = SDL_FALSE; - SDL_Event event; - int i; + + retval = SDL_FALSE; + done = SDL_FALSE; if (title) { SDL_snprintf(title, titlelen, "%s%s", basetitle, name); @@ -151,58 +214,19 @@ WatchGameController(SDL_GameController * gamecontroller) SDL_Log("Watching controller %s\n", name ? name : "Unknown Controller"); /* Loop, getting controller events! */ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop_arg(loop, gamecontroller, 0, 1); +#else while (!done) { - /* blank screen, set up for drawing this frame. */ - SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE); - SDL_RenderClear(screen); - SDL_RenderCopy(screen, background, NULL, NULL); - - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - if (event.key.keysym.sym != SDLK_ESCAPE) { - break; - } - /* Fall through to signal quit */ - case SDL_QUIT: - done = SDL_TRUE; - break; - default: - break; - } - } - - /* Update visual controller state */ - for (i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) { - if (SDL_GameControllerGetButton(gamecontroller, (SDL_GameControllerButton)i) == SDL_PRESSED) { - const SDL_Rect dst = { button_positions[i].x, button_positions[i].y, 50, 50 }; - SDL_RenderCopyEx(screen, button, NULL, &dst, 0, NULL, 0); - } - } - - for (i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i) { - const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */ - const Sint16 value = SDL_GameControllerGetAxis(gamecontroller, (SDL_GameControllerAxis)(i)); - if (value < -deadzone) { - const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 }; - const double angle = axis_positions[i].angle; - SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0); - } else if (value > deadzone) { - const SDL_Rect dst = { axis_positions[i].x, axis_positions[i].y, 50, 50 }; - const double angle = axis_positions[i].angle + 180.0; - SDL_RenderCopyEx(screen, axis, NULL, &dst, angle, NULL, 0); - } - } - - SDL_RenderPresent(screen); - - if (!SDL_GameControllerGetAttached(gamecontroller)) { - done = SDL_TRUE; - retval = SDL_TRUE; /* keep going, wait for reattach. */ - } + loop(gamecontroller); } +#endif SDL_DestroyRenderer(screen); + screen = NULL; + background = NULL; + button = NULL; + axis = NULL; SDL_DestroyWindow(window); return retval; } diff --git a/test/testgesture.c b/test/testgesture.c index 9e4f1dffa..7f766c590 100644 --- a/test/testgesture.c +++ b/test/testgesture.c @@ -15,12 +15,11 @@ * l to load all touches from "./gestureSave" */ -#include -#include - #include "SDL.h" -#include "SDL_touch.h" -#include "SDL_gesture.h" + +#ifdef __EMSCRIPTEN__ +#include +#endif #define WIDTH 640 #define HEIGHT 480 @@ -33,13 +32,16 @@ #define VERBOSE 0 -static SDL_Window *window; static SDL_Event events[EVENT_BUF_SIZE]; static int eventWrite; static int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF}; +SDL_Surface *screen; +SDL_Window *window; +SDL_bool quitting = SDL_FALSE; + typedef struct { float x,y; } Point; @@ -51,18 +53,6 @@ typedef struct { static Knob knob; -void handler (int sig) -{ - SDL_Log ("exiting...(%d)", sig); - exit (0); -} - -void perror_exit (char *error) -{ - perror (error); - handler (9); -} - void setpix(SDL_Surface *screen, float _x, float _y, unsigned int col) { Uint32 *pixmem32; @@ -104,7 +94,7 @@ void drawCircle(SDL_Surface* screen,float x,float y,float r,unsigned int c) float tx,ty; float xr; for(ty = (float)-SDL_fabs(r);ty <= (float)SDL_fabs((int)r);ty++) { - xr = (float)sqrt(r*r - ty*ty); + xr = (float)SDL_sqrt(r*r - ty*ty); if(r > 0) { /* r > 0 ==> filled circle */ for(tx=-xr+.5f;tx<=xr-.5;tx++) { setpix(screen,x+tx,y+ty,c); @@ -123,7 +113,7 @@ void drawKnob(SDL_Surface* screen,Knob k) { (k.p.y+k.r/2*SDL_sinf(k.ang))*screen->h,k.r/4*screen->w,0); } -void DrawScreen(SDL_Surface* screen) +void DrawScreen(SDL_Surface* screen, SDL_Window* window) { int i; #if 1 @@ -165,44 +155,24 @@ void DrawScreen(SDL_Surface* screen) SDL_UpdateWindowSurface(window); } -SDL_Surface* initScreen(int width,int height) +/* Returns a new SDL_Window if window is NULL or window if not. */ +SDL_Window* initWindow(SDL_Window *window, int width,int height) { if (!window) { window = SDL_CreateWindow("Gesture Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE); } - if (!window) { - return NULL; - } - return SDL_GetWindowSurface(window); + return window; } -int main(int argc, char* argv[]) +void loop() { - SDL_Surface *screen; - SDL_Event event; - SDL_bool quitting = SDL_FALSE; - SDL_RWops *stream; + SDL_Event event; + SDL_RWops *stream; - /* Enable standard application logging */ - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); - - /* gesture variables */ - knob.r = .1f; - knob.ang = 0; - - if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1; - - if (!(screen = initScreen(WIDTH,HEIGHT))) - { - SDL_Quit(); - return 1; - } - - while(!quitting) { while(SDL_PollEvent(&event)) - { + { /* Record _all_ events */ events[eventWrite & (EVENT_BUF_SIZE-1)] = event; eventWrite++; @@ -244,10 +214,11 @@ int main(int argc, char* argv[]) break; case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_RESIZED) { - if (!(screen = initScreen(event.window.data1, event.window.data2))) + if (!(window = initWindow(window, event.window.data1, event.window.data2)) || + !(screen = SDL_GetWindowSurface(window))) { SDL_Quit(); - return 1; + exit(1); } } break; @@ -292,9 +263,40 @@ int main(int argc, char* argv[]) SDL_Log("Recorded gesture: %"SDL_PRIs64"",event.dgesture.gestureId); break; } - } - DrawScreen(screen); + } + DrawScreen(screen, window); +} + +int main(int argc, char* argv[]) +{ + window = NULL; + screen = NULL; + quitting = SDL_FALSE; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* gesture variables */ + knob.r = .1f; + knob.ang = 0; + + if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1; + + if (!(window = initWindow(window, WIDTH, HEIGHT)) || + !(screen = SDL_GetWindowSurface(window))) + { + SDL_Quit(); + return 1; } + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while(!quitting) { + loop(); + } +#endif + SDL_Quit(); return 0; } diff --git a/test/testgles2.c b/test/testgles2.c index fcbdbf036..fedf311a6 100644 --- a/test/testgles2.c +++ b/test/testgles2.c @@ -14,6 +14,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" #if defined(__IPHONEOS__) || defined(__ANDROID__) || defined(__NACL__) @@ -408,17 +412,72 @@ Render(unsigned int width, unsigned int height, shader_data* data) GL_CHECK(ctx.glDrawArrays(GL_TRIANGLES, 0, 36)); } +int done; +Uint32 frames; +shader_data *datas; + +void loop() +{ + SDL_Event event; + int i; + int status; + + /* Check for events */ + ++frames; + while (SDL_PollEvent(&event) && !done) { + switch (event.type) { + case SDL_WINDOWEVENT: + switch (event.window.event) { + case SDL_WINDOWEVENT_RESIZED: + for (i = 0; i < state->num_windows; ++i) { + if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { + int w, h; + status = SDL_GL_MakeCurrent(state->windows[i], context[i]); + if (status) { + SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + break; + } + /* Change view port to the new window dimensions */ + SDL_GL_GetDrawableSize(state->windows[i], &w, &h); + ctx.glViewport(0, 0, w, h); + state->window_w = event.window.data1; + state->window_h = event.window.data2; + /* Update window content */ + Render(event.window.data1, event.window.data2, &datas[i]); + SDL_GL_SwapWindow(state->windows[i]); + break; + } + } + break; + } + } + SDLTest_CommonEvent(state, &event, &done); + } + if (!done) { + for (i = 0; i < state->num_windows; ++i) { + status = SDL_GL_MakeCurrent(state->windows[i], context[i]); + if (status) { + SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); + + /* Continue for next window */ + continue; + } + Render(state->window_w, state->window_h, &datas[i]); + SDL_GL_SwapWindow(state->windows[i]); + } + } +} + int main(int argc, char *argv[]) { int fsaa, accel; int value; - int i, done; + int i; SDL_DisplayMode mode; - SDL_Event event; - Uint32 then, now, frames; + Uint32 then, now; int status; - shader_data *datas, *data; + shader_data *data; /* Initialize parameters */ fsaa = 0; @@ -581,6 +640,7 @@ main(int argc, char *argv[]) /* Set rendering settings for each context */ for (i = 0; i < state->num_windows; ++i) { + int w, h; status = SDL_GL_MakeCurrent(state->windows[i], context[i]); if (status) { SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); @@ -588,7 +648,8 @@ main(int argc, char *argv[]) /* Continue for next window */ continue; } - ctx.glViewport(0, 0, state->window_w, state->window_h); + SDL_GL_GetDrawableSize(state->windows[i], &w, &h); + ctx.glViewport(0, 0, w, h); data = &datas[i]; data->angle_x = 0; data->angle_y = 0; data->angle_z = 0; @@ -630,48 +691,14 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; - while (!done) { - /* Check for events */ - ++frames; - while (SDL_PollEvent(&event) && !done) { - switch (event.type) { - case SDL_WINDOWEVENT: - switch (event.window.event) { - case SDL_WINDOWEVENT_RESIZED: - for (i = 0; i < state->num_windows; ++i) { - if (event.window.windowID == SDL_GetWindowID(state->windows[i])) { - status = SDL_GL_MakeCurrent(state->windows[i], context[i]); - if (status) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); - break; - } - /* Change view port to the new window dimensions */ - ctx.glViewport(0, 0, event.window.data1, event.window.data2); - /* Update window content */ - Render(event.window.data1, event.window.data2, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - break; - } - } - break; - } - } - SDLTest_CommonEvent(state, &event, &done); - } - if (!done) { - for (i = 0; i < state->num_windows; ++i) { - status = SDL_GL_MakeCurrent(state->windows[i], context[i]); - if (status) { - SDL_Log("SDL_GL_MakeCurrent(): %s\n", SDL_GetError()); - /* Continue for next window */ - continue; - } - Render(state->window_w, state->window_h, &datas[i]); - SDL_GL_SwapWindow(state->windows[i]); - } - } +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + loop(); } +#endif /* Print out some timing information */ now = SDL_GetTicks(); diff --git a/test/testhaptic.c b/test/testhaptic.c index ac8ab4158..bffe4467d 100644 --- a/test/testhaptic.c +++ b/test/testhaptic.c @@ -22,8 +22,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ifndef SDL_HAPTIC_DISABLED -#include "SDL_haptic.h" - static SDL_Haptic *haptic; diff --git a/test/testhotplug.c b/test/testhotplug.c index ba06dea0f..1b68db1e4 100644 --- a/test/testhotplug.c +++ b/test/testhotplug.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_haptic.h" #if !defined SDL_JOYSTICK_DISABLED && !defined SDL_HAPTIC_DISABLED diff --git a/test/testintersections.c b/test/testintersections.c index 7ea3b5553..77bb51460 100644 --- a/test/testintersections.c +++ b/test/testintersections.c @@ -16,6 +16,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" #define SWAP(typ,a,b) do{typ t=a;a=b;b=t;}while(0) @@ -30,6 +34,9 @@ static int current_alpha = 255; static int current_color = 255; static SDL_BlendMode blendMode = SDL_BLENDMODE_NONE; +int mouse_begin_x = -1, mouse_begin_y = -1; +int done; + void DrawPoints(SDL_Renderer * renderer) { @@ -191,12 +198,71 @@ DrawRectRectIntersections(SDL_Renderer * renderer) } } +void +loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + switch (event.type) { + case SDL_MOUSEBUTTONDOWN: + mouse_begin_x = event.button.x; + mouse_begin_y = event.button.y; + break; + case SDL_MOUSEBUTTONUP: + if (event.button.button == 3) + add_line(mouse_begin_x, mouse_begin_y, event.button.x, + event.button.y); + if (event.button.button == 1) + add_rect(mouse_begin_x, mouse_begin_y, event.button.x, + event.button.y); + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case 'l': + if (event.key.keysym.mod & KMOD_SHIFT) + num_lines = 0; + else + add_line(rand() % 640, rand() % 480, rand() % 640, + rand() % 480); + break; + case 'r': + if (event.key.keysym.mod & KMOD_SHIFT) + num_rects = 0; + else + add_rect(rand() % 640, rand() % 480, rand() % 640, + rand() % 480); + break; + } + break; + default: + break; + } + } + for (i = 0; i < state->num_windows; ++i) { + SDL_Renderer *renderer = state->renderers[i]; + if (state->windows[i] == NULL) + continue; + SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); + SDL_RenderClear(renderer); + + DrawRects(renderer); + DrawPoints(renderer); + DrawRectRectIntersections(renderer); + DrawLines(renderer); + DrawRectLineIntersections(renderer); + + SDL_RenderPresent(renderer); + } +} + int main(int argc, char *argv[]) { - int mouse_begin_x = -1, mouse_begin_y = -1; - int i, done; - SDL_Event event; + int i; Uint32 then, now, frames; /* Enable standard application logging */ @@ -268,62 +334,15 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - switch (event.type) { - case SDL_MOUSEBUTTONDOWN: - mouse_begin_x = event.button.x; - mouse_begin_y = event.button.y; - break; - case SDL_MOUSEBUTTONUP: - if (event.button.button == 3) - add_line(mouse_begin_x, mouse_begin_y, event.button.x, - event.button.y); - if (event.button.button == 1) - add_rect(mouse_begin_x, mouse_begin_y, event.button.x, - event.button.y); - break; - case SDL_KEYDOWN: - switch (event.key.keysym.sym) { - case 'l': - if (event.key.keysym.mod & KMOD_SHIFT) - num_lines = 0; - else - add_line(rand() % 640, rand() % 480, rand() % 640, - rand() % 480); - break; - case 'r': - if (event.key.keysym.mod & KMOD_SHIFT) - num_rects = 0; - else - add_rect(rand() % 640, rand() % 480, rand() % 640, - rand() % 480); - break; - } - break; - default: - break; - } - } - for (i = 0; i < state->num_windows; ++i) { - SDL_Renderer *renderer = state->renderers[i]; - if (state->windows[i] == NULL) - continue; - SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); - SDL_RenderClear(renderer); - - DrawRects(renderer); - DrawPoints(renderer); - DrawRectRectIntersections(renderer); - DrawLines(renderer); - DrawRectLineIntersections(renderer); - - SDL_RenderPresent(renderer); - } + loop(); } +#endif SDLTest_CommonQuit(state); diff --git a/test/testjoystick.c b/test/testjoystick.c index 2dc965da2..adb376e02 100644 --- a/test/testjoystick.c +++ b/test/testjoystick.c @@ -18,6 +18,10 @@ #include "SDL.h" +#ifdef __EMSCRIPTEN__ +#include +#endif + #ifndef SDL_JOYSTICK_DISABLED #ifdef __IPHONEOS__ @@ -28,6 +32,9 @@ #define SCREEN_HEIGHT 480 #endif +SDL_Renderer *screen = NULL; +SDL_bool retval = SDL_FALSE; +SDL_bool done = SDL_FALSE; static void DrawRect(SDL_Renderer *r, const int x, const int y, const int w, const int h) @@ -36,54 +43,25 @@ DrawRect(SDL_Renderer *r, const int x, const int y, const int w, const int h) SDL_RenderFillRect(r, &area); } -static SDL_bool -WatchJoystick(SDL_Joystick * joystick) +void +loop(void *arg) { - SDL_Window *window = NULL; - SDL_Renderer *screen = NULL; - const char *name = NULL; - SDL_bool retval = SDL_FALSE; - SDL_bool done = SDL_FALSE; SDL_Event event; int i; + SDL_Joystick *joystick = (SDL_Joystick *)arg; - /* Create a window to display joystick axis position */ - window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, - SCREEN_HEIGHT, 0); - if (window == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); - return SDL_FALSE; - } - - screen = SDL_CreateRenderer(window, -1, 0); - if (screen == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); - SDL_DestroyWindow(window); - return SDL_FALSE; - } - - SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE); - SDL_RenderClear(screen); - SDL_RenderPresent(screen); - SDL_RaiseWindow(window); - - /* Print info about the joystick we are watching */ - name = SDL_JoystickName(joystick); - SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick), - name ? name : "Unknown Joystick"); - SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n", - SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), - SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick)); - - /* Loop, getting joystick events! */ - while (!done) { /* blank screen, set up for drawing this frame. */ - SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE); + SDL_SetRenderDrawColor(screen, 0x0, 0x0, 0x0, SDL_ALPHA_OPAQUE); SDL_RenderClear(screen); 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, @@ -197,9 +175,57 @@ WatchJoystick(SDL_Joystick * joystick) done = SDL_TRUE; retval = SDL_TRUE; /* keep going, wait for reattach. */ } +} + +static SDL_bool +WatchJoystick(SDL_Joystick * joystick) +{ + SDL_Window *window = NULL; + const char *name = NULL; + + retval = SDL_FALSE; + done = SDL_FALSE; + + /* Create a window to display joystick axis position */ + window = SDL_CreateWindow("Joystick Test", SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, + SCREEN_HEIGHT, 0); + if (window == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); + return SDL_FALSE; } + screen = SDL_CreateRenderer(window, -1, 0); + if (screen == NULL) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create renderer: %s\n", SDL_GetError()); + SDL_DestroyWindow(window); + return SDL_FALSE; + } + + SDL_SetRenderDrawColor(screen, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE); + SDL_RenderClear(screen); + SDL_RenderPresent(screen); + SDL_RaiseWindow(window); + + /* Print info about the joystick we are watching */ + name = SDL_JoystickName(joystick); + SDL_Log("Watching joystick %d: (%s)\n", SDL_JoystickInstanceID(joystick), + name ? name : "Unknown Joystick"); + SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n", + SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), + SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick)); + + /* Loop, getting joystick events! */ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop_arg(loop, joystick, 0, 1); +#else + while (!done) { + loop(joystick); + } +#endif + SDL_DestroyRenderer(screen); + screen = NULL; SDL_DestroyWindow(window); return retval; } diff --git a/test/testlock.c b/test/testlock.c index 9ca3ca199..92a5e9b3f 100644 --- a/test/testlock.c +++ b/test/testlock.c @@ -19,8 +19,6 @@ #include /* for atexit() */ #include "SDL.h" -#include "SDL_mutex.h" -#include "SDL_thread.h" static SDL_mutex *mutex = NULL; static SDL_threadID mainthread; diff --git a/test/testmessage.c b/test/testmessage.c index f44880c3f..b0bf39c89 100644 --- a/test/testmessage.c +++ b/test/testmessage.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void diff --git a/test/testmultiaudio.c b/test/testmultiaudio.c index cc3cdcb68..4f979d534 100644 --- a/test/testmultiaudio.c +++ b/test/testmultiaudio.c @@ -13,6 +13,10 @@ #include /* for fflush() and stdout */ +#ifdef __EMSCRIPTEN__ +#include +#endif + static SDL_AudioSpec spec; static Uint8 *sound = NULL; /* Pointer to wave data */ static Uint32 soundlen = 0; /* Length of wave data */ @@ -24,6 +28,8 @@ typedef struct volatile int done; } callback_data; +callback_data cbd[64]; + void SDLCALL play_through_once(void *arg, Uint8 * stream, int len) { @@ -44,16 +50,30 @@ play_through_once(void *arg, Uint8 * stream, int len) } } +void +loop() +{ + if(cbd[0].done) { +#ifdef __EMSCRIPTEN__ + emscripten_cancel_main_loop(); +#endif + SDL_PauseAudioDevice(cbd[0].dev, 1); + SDL_CloseAudioDevice(cbd[0].dev); + SDL_FreeWAV(sound); + SDL_Quit(); + } +} + static void test_multi_audio(int devcount) { - callback_data cbd[64]; int keep_going = 1; int i; #ifdef __ANDROID__ SDL_Event event; + /* Create a Window to get fully initialized event processing for testing pause on Android. */ SDL_CreateWindow("testmultiaudio", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0); #endif @@ -77,13 +97,19 @@ test_multi_audio(int devcount) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Open device failed: %s\n", SDL_GetError()); } else { SDL_PauseAudioDevice(cbd[0].dev, 0); - while (!cbd[0].done) { -#ifdef __ANDROID__ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!cbd[0].done) + { + #ifdef __ANDROID__ + /* Empty queue, some application events would prevent pause. */ while (SDL_PollEvent(&event)){} -#endif + #endif SDL_Delay(100); } SDL_PauseAudioDevice(cbd[0].dev, 1); +#endif SDL_Log("done.\n"); SDL_CloseAudioDevice(cbd[0].dev); } @@ -114,12 +140,15 @@ test_multi_audio(int devcount) keep_going = 1; } } -#ifdef __ANDROID__ + #ifdef __ANDROID__ + /* Empty queue, some application events would prevent pause. */ while (SDL_PollEvent(&event)){} -#endif + #endif + SDL_Delay(100); } +#ifndef __EMSCRIPTEN__ for (i = 0; i < devcount; i++) { if (cbd[i].dev) { SDL_PauseAudioDevice(cbd[i].dev, 1); @@ -128,6 +157,7 @@ test_multi_audio(int devcount) } SDL_Log("All done!\n"); +#endif } diff --git a/test/testoverlay2.c b/test/testoverlay2.c index d9bd82737..69238fa42 100644 --- a/test/testoverlay2.c +++ b/test/testoverlay2.c @@ -20,6 +20,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" #define MOOSEPIC_W 64 @@ -135,6 +139,18 @@ SDL_Color MooseColors[84] = { , {239, 206, 173} }; +Uint8 MooseFrame[MOOSEFRAMES_COUNT][MOOSEFRAME_SIZE*2]; +SDL_Texture *MooseTexture; +SDL_Rect displayrect; +int window_w; +int window_h; +SDL_Window *window; +SDL_Renderer *renderer; +int paused = 0; +int i; +SDL_bool done = SDL_FALSE; +Uint32 pixel_format = SDL_PIXELFORMAT_YV12; +int fpsdelay; /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void @@ -246,21 +262,65 @@ PrintUsage(char *argv0) SDL_Log("\n"); } +void +loop() +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_RESIZED) { + SDL_RenderSetViewport(renderer, NULL); + displayrect.w = window_w = event.window.data1; + displayrect.h = window_h = event.window.data2; + } + break; + case SDL_MOUSEBUTTONDOWN: + displayrect.x = event.button.x - window_w / 2; + displayrect.y = event.button.y - window_h / 2; + break; + case SDL_MOUSEMOTION: + if (event.motion.state) { + displayrect.x = event.motion.x - window_w / 2; + displayrect.y = event.motion.y - window_h / 2; + } + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_SPACE) { + paused = !paused; + break; + } + if (event.key.keysym.sym != SDLK_ESCAPE) { + break; + } + case SDL_QUIT: + done = SDL_TRUE; + break; + } + } + +#ifndef __EMSCRIPTEN__ + SDL_Delay(fpsdelay); +#endif + + if (!paused) { + i = (i + 1) % MOOSEFRAMES_COUNT; + + SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*SDL_BYTESPERPIXEL(pixel_format)); + } + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, MooseTexture, NULL, &displayrect); + SDL_RenderPresent(renderer); +} + int main(int argc, char **argv) { Uint8 *RawMooseData; SDL_RWops *handle; - int window_w; - int window_h; SDL_Window *window; - SDL_Renderer *renderer; - Uint8 MooseFrame[MOOSEFRAMES_COUNT][MOOSEFRAME_SIZE*2]; - SDL_Texture *MooseTexture; - SDL_Rect displayrect; - SDL_Event event; - int paused = 0; - int i, j; + int j; int fps = 12; int fpsdelay; int nodelay = 0; @@ -270,7 +330,6 @@ main(int argc, char **argv) Uint32 pixel_format = SDL_PIXELFORMAT_YV12; #endif int scale = 5; - SDL_bool done = SDL_FALSE; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -430,50 +489,14 @@ main(int argc, char **argv) SDL_EventState(SDL_KEYUP, SDL_IGNORE); /* Loop, waiting for QUIT or RESIZE */ +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, nodelay ? 0 : fps, 1); +#else while (!done) { - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_WINDOWEVENT: - if (event.window.event == SDL_WINDOWEVENT_RESIZED) { - SDL_RenderSetViewport(renderer, NULL); - displayrect.w = window_w = event.window.data1; - displayrect.h = window_h = event.window.data2; - } - break; - case SDL_MOUSEBUTTONDOWN: - displayrect.x = event.button.x - window_w / 2; - displayrect.y = event.button.y - window_h / 2; - break; - case SDL_MOUSEMOTION: - if (event.motion.state) { - displayrect.x = event.motion.x - window_w / 2; - displayrect.y = event.motion.y - window_h / 2; - } - break; - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_SPACE) { - paused = !paused; - break; - } - if (event.key.keysym.sym != SDLK_ESCAPE) { - break; - } - case SDL_QUIT: - done = SDL_TRUE; - break; + loop(); } - } - SDL_Delay(fpsdelay); +#endif - if (!paused) { - i = (i + 1) % MOOSEFRAMES_COUNT; - - SDL_UpdateTexture(MooseTexture, NULL, MooseFrame[i], MOOSEPIC_W*SDL_BYTESPERPIXEL(pixel_format)); - } - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, MooseTexture, NULL, &displayrect); - SDL_RenderPresent(renderer); - } SDL_DestroyRenderer(renderer); quit(0); return 0; diff --git a/test/testplatform.c b/test/testplatform.c index ae367ff4b..068be8efc 100644 --- a/test/testplatform.c +++ b/test/testplatform.c @@ -13,9 +13,6 @@ #include #include "SDL.h" -#include "SDL_endian.h" -#include "SDL_cpuinfo.h" -#include "SDL_assert.h" /* * Watcom C flags these as Warning 201: "Unreachable code" if you just @@ -119,14 +116,8 @@ TestEndian(SDL_bool verbose) ++error; } if (verbose) { -#ifdef _MSC_VER - SDL_Log("Value 64 = 0x%I64X, swapped = 0x%I64X\n", value64, + SDL_Log("Value 64 = 0x%"SDL_PRIX64", swapped = 0x%"SDL_PRIX64"\n", value64, SDL_Swap64(value64)); -#else - SDL_Log("Value 64 = 0x%llX, swapped = 0x%llX\n", - (unsigned long long) value64, - (unsigned long long) SDL_Swap64(value64)); -#endif } if (SDL_Swap64(value64) != swapped64) { if (verbose) { @@ -176,7 +167,7 @@ TestAssertions(SDL_bool verbose) #endif { - const SDL_assert_data *item = SDL_GetAssertionReport(); + const SDL_AssertData *item = SDL_GetAssertionReport(); while (item) { SDL_Log("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n", item->condition, item->function, item->filename, diff --git a/test/testrelative.c b/test/testrelative.c index 2c87ba1de..3b6ef810e 100644 --- a/test/testrelative.c +++ b/test/testrelative.c @@ -18,8 +18,14 @@ #include "SDL_test_common.h" +#ifdef __EMSCRIPTEN__ +#include +#endif static SDLTest_CommonState *state; +int i, done; +SDL_Rect rect; +SDL_Event event; static void DrawRects(SDL_Renderer * renderer, SDL_Rect * rect) @@ -28,12 +34,44 @@ DrawRects(SDL_Renderer * renderer, SDL_Rect * rect) SDL_RenderFillRect(renderer, rect); } +static void +loop(){ + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + switch(event.type) { + case SDL_MOUSEMOTION: + { + rect.x += event.motion.xrel; + rect.y += event.motion.yrel; + } + break; + } + } + 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); + } +} + int main(int argc, char *argv[]) { - int i, done; - SDL_Rect rect; - SDL_Event event; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -69,32 +107,13 @@ main(int argc, char *argv[]) rect.h = 10; /* Main render loop */ done = 0; +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - switch(event.type) { - case SDL_MOUSEMOTION: - { - rect.x += event.motion.xrel; - rect.y += event.motion.yrel; - } - break; - } + loop(); } - for (i = 0; i < state->num_windows; ++i) { - SDL_Renderer *renderer = state->renderers[i]; - if (state->windows[i] == NULL) - continue; - SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); - SDL_RenderClear(renderer); - - DrawRects(renderer, &rect); - - SDL_RenderPresent(renderer); - } - } - +#endif SDLTest_CommonQuit(state); return 0; } diff --git a/test/testrendercopyex.c b/test/testrendercopyex.c index 95a77a17f..379819ce2 100644 --- a/test/testrendercopyex.c +++ b/test/testrendercopyex.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" @@ -29,6 +33,9 @@ typedef struct { int scale_direction; } DrawState; +DrawState *drawstates; +int done; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -130,12 +137,27 @@ Draw(DrawState *s) /* SDL_Delay(10); */ } +void loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + for (i = 0; i < state->num_windows; ++i) { + if (state->windows[i] == NULL) + continue; + Draw(&drawstates[i]); + } +} + int main(int argc, char *argv[]) { - DrawState *drawstates; - int i, done; - SDL_Event event; + int i; int frames; Uint32 then, now; @@ -181,19 +203,15 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; - while (!done) { - /* Check for events */ - ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - } - for (i = 0; i < state->num_windows; ++i) { - if (state->windows[i] == NULL) - continue; - Draw(&drawstates[i]); - } - } +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + ++frames; + loop(); + } +#endif /* Print out some timing information */ now = SDL_GetTicks(); if (now > then) { diff --git a/test/testrendertarget.c b/test/testrendertarget.c index 61a3a5fdd..c03e6394b 100644 --- a/test/testrendertarget.c +++ b/test/testrendertarget.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" @@ -29,6 +33,10 @@ typedef struct { int scale_direction; } DrawState; +DrawState *drawstates; +int done; +SDL_bool test_composite = SDL_FALSE; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -214,15 +222,33 @@ Draw(DrawState *s) return SDL_TRUE; } +void +loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + for (i = 0; i < state->num_windows; ++i) { + if (state->windows[i] == NULL) + continue; + if (test_composite) { + if (!DrawComposite(&drawstates[i])) done = 1; + } else { + if (!Draw(&drawstates[i])) done = 1; + } + } +} + int main(int argc, char *argv[]) { - DrawState *drawstates; - int i, done; - SDL_Event event; + int i; int frames; Uint32 then, now; - SDL_bool test_composite = SDL_FALSE; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -278,22 +304,15 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - } - for (i = 0; i < state->num_windows; ++i) { - if (state->windows[i] == NULL) - continue; - if (test_composite) { - if (!DrawComposite(&drawstates[i])) done = 1; - } else { - if (!Draw(&drawstates[i])) done = 1; - } - } + loop(); } +#endif /* Print out some timing information */ now = SDL_GetTicks(); diff --git a/test/testrumble.c b/test/testrumble.c index 74a7e98fc..d72e5d94a 100644 --- a/test/testrumble.c +++ b/test/testrumble.c @@ -33,8 +33,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #ifndef SDL_HAPTIC_DISABLED -#include "SDL_haptic.h" - static SDL_Haptic *haptic; diff --git a/test/testscale.c b/test/testscale.c index edd2c2fd3..e52eacb43 100644 --- a/test/testscale.c +++ b/test/testscale.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" #define WINDOW_WIDTH 640 @@ -31,6 +35,9 @@ typedef struct { int scale_direction; } DrawState; +DrawState *drawstates; +int done; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -120,12 +127,27 @@ Draw(DrawState *s) SDL_RenderPresent(s->renderer); } +void +loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + for (i = 0; i < state->num_windows; ++i) { + if (state->windows[i] == NULL) + continue; + Draw(&drawstates[i]); + } +} + int main(int argc, char *argv[]) { - DrawState *drawstates; - int i, done; - SDL_Event event; + int i; int frames; Uint32 then, now; @@ -171,18 +193,15 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - } - for (i = 0; i < state->num_windows; ++i) { - if (state->windows[i] == NULL) - continue; - Draw(&drawstates[i]); - } + loop(); } +#endif /* Print out some timing information */ now = SDL_GetTicks(); diff --git a/test/testsem.c b/test/testsem.c index ca71ec2e6..8d41e083f 100644 --- a/test/testsem.c +++ b/test/testsem.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" #define NUM_THREADS 10 diff --git a/test/testsprite2.c b/test/testsprite2.c index 945280f9f..17a9cd5f4 100644 --- a/test/testsprite2.c +++ b/test/testsprite2.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test.h" #include "SDL_test_common.h" @@ -38,6 +42,8 @@ static SDL_BlendMode blendMode = SDL_BLENDMODE_BLEND; /* -1: infinite random moves (default); >=0: enables N deterministic moves */ static int iterations = -1; +int done; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -230,11 +236,27 @@ MoveSprites(SDL_Renderer * renderer, SDL_Texture * sprite) SDL_RenderPresent(renderer); } +void +loop() +{ + int i; + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + for (i = 0; i < state->num_windows; ++i) { + if (state->windows[i] == NULL) + continue; + MoveSprites(state->renderers[i], sprites[i]); + } +} + int main(int argc, char *argv[]) { - int i, done; - SDL_Event event; + int i; Uint32 then, now, frames; Uint64 seed; const char *icon = "icon.bmp"; @@ -351,18 +373,15 @@ main(int argc, char *argv[]) frames = 0; then = SDL_GetTicks(); done = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - /* Check for events */ ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - } - for (i = 0; i < state->num_windows; ++i) { - if (state->windows[i] == NULL) - continue; - MoveSprites(state->renderers[i], sprites[i]); - } + loop(); } +#endif /* Print out some timing information */ now = SDL_GetTicks(); diff --git a/test/testspriteminimal.c b/test/testspriteminimal.c index bdcb8b389..fc7d31f17 100644 --- a/test/testspriteminimal.c +++ b/test/testspriteminimal.c @@ -15,6 +15,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" #define WINDOW_WIDTH 640 @@ -27,6 +31,9 @@ static SDL_Rect positions[NUM_SPRITES]; static SDL_Rect velocities[NUM_SPRITES]; static int sprite_w, sprite_h; +SDL_Renderer *renderer; +int done; + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -118,13 +125,25 @@ MoveSprites(SDL_Renderer * renderer, SDL_Texture * sprite) SDL_RenderPresent(renderer); } +void loop() +{ + SDL_Event event; + + /* Check for events */ + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN) { + done = 1; + } + } + MoveSprites(renderer, sprite); +} + int main(int argc, char *argv[]) { SDL_Window *window; - SDL_Renderer *renderer; - int i, done; - SDL_Event event; + int i; + /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -154,16 +173,14 @@ main(int argc, char *argv[]) /* Main render loop */ done = 0; - while (!done) { - /* Check for events */ - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN) { - done = 1; - } - } - MoveSprites(renderer, sprite); - } +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + loop(); + } +#endif quit(0); return 0; /* to prevent compiler warning */ diff --git a/test/teststreaming.c b/test/teststreaming.c index e8bb1f21f..da618c4cf 100644 --- a/test/teststreaming.c +++ b/test/teststreaming.c @@ -18,6 +18,10 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL.h" #define MOOSEPIC_W 64 @@ -52,6 +56,11 @@ SDL_Color MooseColors[84] = { Uint8 MooseFrames[MOOSEFRAMES_COUNT][MOOSEFRAME_SIZE]; +SDL_Renderer *renderer; +int frame; +SDL_Texture *MooseTexture; +SDL_bool done = SDL_FALSE; + void quit(int rc) { SDL_Quit(); @@ -82,16 +91,37 @@ void UpdateTexture(SDL_Texture *texture, int frame) SDL_UnlockTexture(texture); } +void +loop() +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) { + done = SDL_TRUE; + } + break; + case SDL_QUIT: + done = SDL_TRUE; + break; + } + } + + frame = (frame + 1) % MOOSEFRAMES_COUNT; + UpdateTexture(MooseTexture, frame); + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, MooseTexture, NULL, NULL); + SDL_RenderPresent(renderer); +} + int main(int argc, char **argv) { SDL_Window *window; - SDL_Renderer *renderer; SDL_RWops *handle; - SDL_Texture *MooseTexture; - SDL_Event event; - SDL_bool done = SDL_FALSE; - int frame; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -136,27 +166,15 @@ main(int argc, char **argv) /* Loop, waiting for QUIT or the escape key */ frame = 0; + +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else while (!done) { - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) { - done = SDL_TRUE; - } - break; - case SDL_QUIT: - done = SDL_TRUE; - break; - } + loop(); } +#endif - frame = (frame + 1) % MOOSEFRAMES_COUNT; - UpdateTexture(MooseTexture, frame); - - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, MooseTexture, NULL, NULL); - SDL_RenderPresent(renderer); - } SDL_DestroyRenderer(renderer); quit(0); diff --git a/test/testthread.c b/test/testthread.c index d732320a5..75aed83fc 100644 --- a/test/testthread.c +++ b/test/testthread.c @@ -17,7 +17,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" static SDL_TLSID tls; static int alive = 0; diff --git a/test/testtimer.c b/test/testtimer.c index ef6bcb6a8..f02364cd2 100644 --- a/test/testtimer.c +++ b/test/testtimer.c @@ -107,7 +107,7 @@ main(int argc, char *argv[]) now = SDL_GetPerformanceCounter(); SDL_Log("1 million iterations of ticktock took %f ms\n", (double)((now - start)*1000) / SDL_GetPerformanceFrequency()); - SDL_Log("Performance counter frequency: %llu\n", (unsigned long long) SDL_GetPerformanceFrequency()); + SDL_Log("Performance counter frequency: %"PRIu64"\n", (unsigned long long) SDL_GetPerformanceFrequency()); start32 = SDL_GetTicks(); start = SDL_GetPerformanceCounter(); SDL_Delay(1000); diff --git a/test/testviewport.c b/test/testviewport.c index c9d323409..2ac8031ab 100644 --- a/test/testviewport.c +++ b/test/testviewport.c @@ -15,12 +15,23 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test.h" #include "SDL_test_common.h" static SDLTest_CommonState *state; +SDL_Rect viewport; +int done, j; +SDL_bool use_target = SDL_FALSE; +#ifdef __EMSCRIPTEN__ +Uint32 wait_start; +#endif + /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ static void quit(int rc) @@ -77,14 +88,54 @@ DrawOnViewport(SDL_Renderer * renderer, SDL_Rect viewport) SDL_RenderFillRect(renderer, &rect); } +void +loop() +{ +#ifdef __EMSCRIPTEN__ + /* Avoid using delays */ + if(SDL_GetTicks() - wait_start < 1000) + return; + wait_start = SDL_GetTicks(); +#endif + SDL_Event event; + int i; + /* Check for events */ + while (SDL_PollEvent(&event)) { + SDLTest_CommonEvent(state, &event, &done); + } + + /* Move a viewport box in steps around the screen */ + viewport.x = j * 100; + viewport.y = viewport.x; + viewport.w = 100 + j * 50; + viewport.h = 100 + j * 50; + j = (j + 1) % 4; + SDL_Log("Current Viewport x=%i y=%i w=%i h=%i", viewport.x, viewport.y, viewport.w, viewport.h); + + for (i = 0; i < state->num_windows; ++i) { + if (state->windows[i] == NULL) + continue; + + /* Draw using viewport */ + DrawOnViewport(state->renderers[i], viewport); + + /* Update the screen! */ + if (use_target) { + SDL_SetRenderTarget(state->renderers[i], NULL); + SDL_RenderCopy(state->renderers[i], state->targets[i], NULL, NULL); + SDL_RenderPresent(state->renderers[i]); + SDL_SetRenderTarget(state->renderers[i], state->targets[i]); + } else { + SDL_RenderPresent(state->renderers[i]); + } + } +} + int main(int argc, char *argv[]) { - int i, j, done; - SDL_Event event; + int i; Uint32 then, now, frames; - SDL_Rect viewport; - SDL_bool use_target = SDL_FALSE; /* Initialize test framework */ state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); @@ -135,41 +186,17 @@ main(int argc, char *argv[]) then = SDL_GetTicks(); done = 0; j = 0; - while (!done) { - /* Check for events */ - ++frames; - while (SDL_PollEvent(&event)) { - SDLTest_CommonEvent(state, &event, &done); - } - - /* Move a viewport box in steps around the screen */ - viewport.x = j * 100; - viewport.y = viewport.x; - viewport.w = 100 + j * 50; - viewport.h = 100 + j * 50; - j = (j + 1) % 4; - SDL_Log("Current Viewport x=%i y=%i w=%i h=%i", viewport.x, viewport.y, viewport.w, viewport.h); - - for (i = 0; i < state->num_windows; ++i) { - if (state->windows[i] == NULL) - continue; - - /* Draw using viewport */ - DrawOnViewport(state->renderers[i], viewport); - /* Update the screen! */ - if (use_target) { - SDL_SetRenderTarget(state->renderers[i], NULL); - SDL_RenderCopy(state->renderers[i], state->targets[i], NULL, NULL); - SDL_RenderPresent(state->renderers[i]); - SDL_SetRenderTarget(state->renderers[i], state->targets[i]); - } else { - SDL_RenderPresent(state->renderers[i]); - } - } - +#ifdef __EMSCRIPTEN__ + wait_start = SDL_GetTicks(); + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + ++frames; + loop(); SDL_Delay(1000); } +#endif /* Print out some timing information */ now = SDL_GetTicks(); diff --git a/test/testwm2.c b/test/testwm2.c index 186e0827a..8d8ff4613 100644 --- a/test/testwm2.c +++ b/test/testwm2.c @@ -13,22 +13,16 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "SDL_test_common.h" static SDLTest_CommonState *state; +int done; -/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ -static void -quit(int rc) -{ - SDLTest_CommonQuit(state); - exit(rc); -} - -int -main(int argc, char *argv[]) -{ - static const char *cursorNames[] = { +static const char *cursorNames[] = { "arrow", "ibeam", "wait", @@ -41,44 +35,22 @@ main(int argc, char *argv[]) "sizeALL", "NO", "hand", - }; +}; +int system_cursor = -1; +SDL_Cursor *cursor = NULL; - int i, done; +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ +static void +quit(int rc) +{ + SDLTest_CommonQuit(state); + exit(rc); +} + +void +loop() +{ SDL_Event event; - int system_cursor = -1; - SDL_Cursor *cursor = NULL; - - /* Enable standard application logging */ - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); - - SDL_assert(SDL_arraysize(cursorNames) == SDL_NUM_SYSTEM_CURSORS); - - /* Initialize test framework */ - state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); - if (!state) { - return 1; - } - state->skip_renderer = SDL_TRUE; - for (i = 1; i < argc;) { - int consumed; - - consumed = SDLTest_CommonArg(state, i); - if (consumed == 0) { - consumed = -1; - } - if (consumed < 0) { - SDL_Log("Usage: %s %s\n", argv[0], SDLTest_CommonUsage(state)); - quit(1); - } - i += consumed; - } - if (!SDLTest_CommonInit(state)) { - quit(2); - } - - /* Main render loop */ - done = 0; - while (!done) { /* Check for events */ while (SDL_PollEvent(&event)) { SDLTest_CommonEvent(state, &event, &done); @@ -128,7 +100,50 @@ main(int argc, char *argv[]) } } } +} + +int +main(int argc, char *argv[]) +{ + int i; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + SDL_assert(SDL_arraysize(cursorNames) == SDL_NUM_SYSTEM_CURSORS); + + /* Initialize test framework */ + state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); + if (!state) { + return 1; } + state->skip_renderer = SDL_TRUE; + for (i = 1; i < argc;) { + int consumed; + + consumed = SDLTest_CommonArg(state, i); + if (consumed == 0) { + consumed = -1; + } + if (consumed < 0) { + SDL_Log("Usage: %s %s\n", argv[0], SDLTest_CommonUsage(state)); + quit(1); + } + i += consumed; + } + if (!SDLTest_CommonInit(state)) { + quit(2); + } + + /* Main render loop */ + done = 0; +#ifdef __EMSCRIPTEN__ + emscripten_set_main_loop(loop, 0, 1); +#else + while (!done) { + loop(); + } +#endif SDL_FreeCursor(cursor); quit(0); diff --git a/test/torturethread.c b/test/torturethread.c index bc4e1132f..2e572b64c 100644 --- a/test/torturethread.c +++ b/test/torturethread.c @@ -18,7 +18,6 @@ #include #include "SDL.h" -#include "SDL_thread.h" #define NUMTHREADS 10