From c1346423cb0eae256aac6c4550f4b52ea11d43dc Mon Sep 17 00:00:00 2001 From: underscorediscovery Date: Tue, 8 Sep 2015 08:07:57 -0230 Subject: [PATCH] SDL hg-9859:2ec928ff921c --- files.xml | 13 + include/SDL.h | 2 +- include/SDL_assert.h | 36 +- include/SDL_atomic.h | 4 +- include/SDL_audio.h | 2 +- include/SDL_bits.h | 2 +- include/SDL_blendmode.h | 4 +- include/SDL_clipboard.h | 2 +- include/SDL_config_android.h | 6 +- include/SDL_config_iphoneos.h | 5 +- include/SDL_config_macosx.h | 3 +- include/SDL_config_minimal.h | 2 +- include/SDL_config_pandora.h | 2 +- include/SDL_config_psp.h | 2 +- include/SDL_config_windows.h | 2 +- include/SDL_config_winrt.h | 4 +- include/SDL_config_wiz.h | 2 +- include/SDL_copying.h | 2 +- include/SDL_cpuinfo.h | 2 +- include/SDL_egl.h | 2 +- include/SDL_endian.h | 6 +- include/SDL_error.h | 2 +- include/SDL_events.h | 32 +- include/SDL_filesystem.h | 4 +- include/SDL_gamecontroller.h | 12 +- include/SDL_gesture.h | 2 +- include/SDL_haptic.h | 16 +- include/SDL_hints.h | 78 +- include/SDL_joystick.h | 11 +- include/SDL_keyboard.h | 2 +- include/SDL_keycode.h | 2 +- include/SDL_loadso.h | 2 +- include/SDL_log.h | 2 +- include/SDL_main.h | 11 +- include/SDL_messagebox.h | 2 +- include/SDL_mouse.h | 14 +- include/SDL_mutex.h | 2 +- include/SDL_name.h | 2 +- include/SDL_opengl.h | 2 +- include/SDL_opengl_glext.h | 5 + include/SDL_opengles.h | 2 +- include/SDL_opengles2.h | 2 +- include/SDL_pixels.h | 27 +- include/SDL_platform.h | 2 +- include/SDL_power.h | 2 +- include/SDL_quit.h | 2 +- include/SDL_rect.h | 2 +- include/SDL_render.h | 12 +- include/SDL_revision.h | 4 +- include/SDL_rwops.h | 2 +- include/SDL_scancode.h | 2 +- include/SDL_shape.h | 2 +- include/SDL_stdinc.h | 70 +- include/SDL_surface.h | 2 +- include/SDL_system.h | 52 +- include/SDL_syswm.h | 8 +- include/SDL_test.h | 4 +- include/SDL_test_assert.h | 4 +- include/SDL_test_common.h | 2 +- include/SDL_test_compare.h | 6 +- include/SDL_test_crc32.h | 26 +- include/SDL_test_font.h | 2 +- include/SDL_test_fuzzer.h | 6 +- include/SDL_test_harness.h | 2 +- include/SDL_test_images.h | 2 +- include/SDL_test_log.h | 2 +- include/SDL_test_md5.h | 20 +- include/SDL_test_random.h | 2 +- include/SDL_thread.h | 2 +- include/SDL_timer.h | 2 +- include/SDL_touch.h | 2 +- include/SDL_types.h | 2 +- include/SDL_version.h | 2 +- include/SDL_video.h | 35 +- include/begin_code.h | 4 +- include/close_code.h | 2 +- include/configs/default/SDL_config.h | 2 +- src/SDL.c | 6 +- src/SDL_assert.c | 2 +- src/SDL_assert_c.h | 2 +- src/SDL_error.c | 40 +- src/SDL_error_c.h | 2 +- src/SDL_hints.c | 8 +- src/SDL_internal.h | 2 +- src/SDL_log.c | 8 +- src/atomic/SDL_atomic.c | 2 +- src/atomic/SDL_spinlock.c | 2 +- src/audio/SDL_audio.c | 691 ++++++++---------- src/audio/SDL_audio_c.h | 2 +- src/audio/SDL_audiocvt.c | 2 +- src/audio/SDL_audiodev.c | 36 +- src/audio/SDL_audiodev_c.h | 5 +- src/audio/SDL_audiomem.h | 2 +- src/audio/SDL_audiotypecvt.c | 2 +- src/audio/SDL_mixer.c | 2 +- src/audio/SDL_sysaudio.h | 54 +- src/audio/SDL_wave.c | 2 +- src/audio/SDL_wave.h | 2 +- src/audio/alsa/SDL_alsa_audio.c | 6 +- src/audio/alsa/SDL_alsa_audio.h | 2 +- src/audio/android/SDL_androidaudio.c | 4 +- src/audio/android/SDL_androidaudio.h | 2 +- src/audio/arts/SDL_artsaudio.c | 8 +- src/audio/arts/SDL_artsaudio.h | 2 +- src/audio/bsd/SDL_bsdaudio.c | 14 +- src/audio/bsd/SDL_bsdaudio.h | 2 +- src/audio/coreaudio/SDL_coreaudio.c | 329 ++++++--- src/audio/coreaudio/SDL_coreaudio.h | 2 +- src/audio/directsound/SDL_directsound.c | 67 +- src/audio/directsound/SDL_directsound.h | 2 +- src/audio/disk/SDL_diskaudio.c | 19 +- src/audio/disk/SDL_diskaudio.h | 2 +- src/audio/dsp/SDL_dspaudio.c | 12 +- src/audio/dsp/SDL_dspaudio.h | 2 +- src/audio/dummy/SDL_dummyaudio.c | 4 +- src/audio/dummy/SDL_dummyaudio.h | 2 +- src/audio/emscripten/SDL_emscriptenaudio.c | 279 +++++++ src/audio/emscripten/SDL_emscriptenaudio.h | 42 ++ src/audio/esd/SDL_esdaudio.c | 8 +- src/audio/esd/SDL_esdaudio.h | 2 +- src/audio/fusionsound/SDL_fsaudio.c | 6 +- src/audio/fusionsound/SDL_fsaudio.h | 2 +- src/audio/haiku/SDL_haikuaudio.cc | 4 +- src/audio/haiku/SDL_haikuaudio.h | 2 +- src/audio/nacl/SDL_naclaudio.c | 15 +- src/audio/nacl/SDL_naclaudio.h | 2 +- src/audio/nas/SDL_nasaudio.c | 4 +- src/audio/nas/SDL_nasaudio.h | 2 +- src/audio/paudio/SDL_paudio.c | 10 +- src/audio/paudio/SDL_paudio.h | 2 +- src/audio/psp/SDL_pspaudio.c | 10 +- src/audio/psp/SDL_pspaudio.h | 4 +- src/audio/pulseaudio/SDL_pulseaudio.c | 357 ++++++--- src/audio/pulseaudio/SDL_pulseaudio.h | 5 +- src/audio/qsa/SDL_qsa_audio.c | 114 +-- src/audio/qsa/SDL_qsa_audio.h | 2 +- src/audio/sdlgenaudiocvt.pl | 2 +- src/audio/sndio/SDL_sndioaudio.c | 6 +- src/audio/sndio/SDL_sndioaudio.h | 2 +- src/audio/sun/SDL_sunaudio.c | 14 +- src/audio/sun/SDL_sunaudio.h | 2 +- src/audio/winmm/SDL_winmm.c | 65 +- src/audio/winmm/SDL_winmm.h | 2 +- src/audio/xaudio2/SDL_xaudio2.c | 82 +-- .../xaudio2/SDL_xaudio2_winrthelpers.cpp | 2 +- src/audio/xaudio2/SDL_xaudio2_winrthelpers.h | 2 +- src/core/android/SDL_android.c | 124 ++-- src/core/android/SDL_android.h | 19 +- src/core/linux/SDL_dbus.c | 7 +- src/core/linux/SDL_dbus.h | 4 +- src/core/linux/SDL_evdev.c | 47 +- src/core/linux/SDL_evdev.h | 2 +- src/core/linux/SDL_ibus.c | 27 +- src/core/linux/SDL_ibus.h | 2 +- src/core/linux/SDL_udev.c | 37 +- src/core/linux/SDL_udev.h | 2 +- src/core/windows/SDL_directx.h | 2 +- src/core/windows/SDL_windows.c | 4 +- src/core/windows/SDL_windows.h | 2 +- src/core/windows/SDL_xinput.c | 2 +- src/core/windows/SDL_xinput.h | 2 +- src/core/winrt/SDL_winrtapp_common.cpp | 2 +- src/core/winrt/SDL_winrtapp_common.h | 2 +- src/core/winrt/SDL_winrtapp_direct3d.cpp | 20 +- src/core/winrt/SDL_winrtapp_direct3d.h | 3 +- src/core/winrt/SDL_winrtapp_xaml.cpp | 2 +- src/core/winrt/SDL_winrtapp_xaml.h | 4 +- src/cpuinfo/SDL_cpuinfo.c | 20 +- src/dynapi/SDL_dynapi.c | 27 +- src/dynapi/SDL_dynapi.h | 9 +- src/dynapi/SDL_dynapi_overrides.h | 5 +- src/dynapi/SDL_dynapi_procs.h | 9 +- src/dynapi/gendynapi.pl | 2 +- src/events/SDL_clipboardevents.c | 2 +- src/events/SDL_clipboardevents_c.h | 2 +- src/events/SDL_dropevents.c | 2 +- src/events/SDL_dropevents_c.h | 2 +- src/events/SDL_events.c | 19 +- src/events/SDL_events_c.h | 4 +- src/events/SDL_gesture.c | 58 +- src/events/SDL_gesture_c.h | 2 +- src/events/SDL_keyboard.c | 135 ++-- src/events/SDL_keyboard_c.h | 2 +- src/events/SDL_mouse.c | 27 +- src/events/SDL_mouse_c.h | 6 +- src/events/SDL_quit.c | 50 +- src/events/SDL_sysevents.h | 2 +- src/events/SDL_touch.c | 7 +- src/events/SDL_touch_c.h | 2 +- src/events/SDL_windowevents.c | 2 +- src/events/SDL_windowevents_c.h | 2 +- src/events/blank_cursor.h | 2 +- src/events/default_cursor.h | 4 +- src/events/scancodes_darwin.h | 2 +- src/events/scancodes_linux.h | 2 +- src/events/scancodes_windows.h | 6 +- src/events/scancodes_xfree86.h | 18 +- src/file/SDL_rwops.c | 2 +- src/file/cocoa/SDL_rwopsbundlesupport.h | 2 +- src/file/cocoa/SDL_rwopsbundlesupport.m | 7 +- src/filesystem/android/SDL_sysfilesystem.c | 2 +- src/filesystem/cocoa/SDL_sysfilesystem.m | 7 +- src/filesystem/dummy/SDL_sysfilesystem.c | 2 +- src/filesystem/emscripten/SDL_sysfilesystem.c | 69 ++ src/filesystem/haiku/SDL_sysfilesystem.cc | 2 +- src/filesystem/nacl/SDL_sysfilesystem.c | 5 +- src/filesystem/unix/SDL_sysfilesystem.c | 2 +- src/filesystem/windows/SDL_sysfilesystem.c | 54 +- src/filesystem/winrt/SDL_sysfilesystem.cpp | 87 ++- src/haptic/SDL_haptic.c | 3 +- src/haptic/SDL_haptic_c.h | 2 +- src/haptic/SDL_syshaptic.h | 9 +- src/haptic/darwin/SDL_syshaptic.c | 75 +- src/haptic/darwin/SDL_syshaptic_c.h | 2 +- src/haptic/dummy/SDL_syshaptic.c | 4 +- src/haptic/linux/SDL_syshaptic.c | 42 +- src/haptic/windows/SDL_dinputhaptic.c | 14 +- src/haptic/windows/SDL_dinputhaptic_c.h | 2 +- src/haptic/windows/SDL_windowshaptic.c | 6 +- src/haptic/windows/SDL_windowshaptic_c.h | 2 +- src/haptic/windows/SDL_xinputhaptic.c | 16 +- src/haptic/windows/SDL_xinputhaptic_c.h | 2 +- src/joystick/SDL_gamecontroller.c | 57 +- src/joystick/SDL_gamecontrollerdb.h | 16 +- src/joystick/SDL_gamecontrollerdb.h.new | 65 -- src/joystick/SDL_joystick.c | 11 +- src/joystick/SDL_joystick_c.h | 2 +- src/joystick/SDL_sysjoystick.h | 9 +- src/joystick/android/SDL_sysjoystick.c | 27 +- src/joystick/android/SDL_sysjoystick_c.h | 4 +- src/joystick/bsd/SDL_sysjoystick.c | 6 +- src/joystick/darwin/SDL_sysjoystick.c | 201 +++-- src/joystick/darwin/SDL_sysjoystick_c.h | 6 +- src/joystick/dummy/SDL_sysjoystick.c | 11 +- src/joystick/emscripten/SDL_sysjoystick.c | 430 +++++++++++ src/joystick/emscripten/SDL_sysjoystick_c.h | 52 ++ src/joystick/haiku/SDL_haikujoystick.cc | 10 +- src/joystick/iphoneos/SDL_sysjoystick.m | 57 +- src/joystick/linux/SDL_sysjoystick.c | 29 +- src/joystick/linux/SDL_sysjoystick_c.h | 2 +- src/joystick/psp/SDL_sysjoystick.c | 19 +- src/joystick/sort_controllers.py | 16 +- src/joystick/windows/SDL_dinputjoystick.c | 14 +- src/joystick/windows/SDL_dinputjoystick_c.h | 2 +- src/joystick/windows/SDL_mmjoystick.c | 11 +- src/joystick/windows/SDL_windowsjoystick.c | 18 +- src/joystick/windows/SDL_windowsjoystick_c.h | 2 +- src/joystick/windows/SDL_xinputjoystick.c | 11 +- src/joystick/windows/SDL_xinputjoystick_c.h | 2 +- src/libm/math_libm.h | 2 +- src/loadso/dlopen/SDL_sysloadso.c | 2 +- src/loadso/dummy/SDL_sysloadso.c | 2 +- src/loadso/haiku/SDL_sysloadso.c | 2 +- src/loadso/windows/SDL_sysloadso.c | 2 +- src/main/android/SDL_android_main.c | 1 + src/main/haiku/SDL_BApp.h | 4 +- src/main/haiku/SDL_BeApp.cc | 2 +- src/main/haiku/SDL_BeApp.h | 2 +- src/main/nacl/SDL_nacl_main.c | 4 +- src/main/psp/SDL_psp_main.c | 7 + src/main/windows/SDL_windows_main.c | 49 +- src/main/windows/version.rc | 2 +- src/power/SDL_power.c | 8 +- src/power/android/SDL_syspower.c | 2 +- src/power/emscripten/SDL_syspower.c | 62 ++ src/power/haiku/SDL_syspower.c | 2 +- src/power/linux/SDL_syspower.c | 106 ++- src/power/macosx/SDL_syspower.c | 6 +- src/power/psp/SDL_syspower.c | 2 +- src/power/uikit/SDL_syspower.h | 2 +- src/power/uikit/SDL_syspower.m | 39 +- src/power/windows/SDL_syspower.c | 2 +- src/power/winrt/SDL_syspower.cpp | 2 +- src/render/SDL_d3dmath.c | 2 +- src/render/SDL_d3dmath.h | 2 +- src/render/SDL_render.c | 16 +- src/render/SDL_sysrender.h | 2 +- src/render/SDL_yuv_mmx.c | 2 +- src/render/SDL_yuv_sw.c | 2 +- src/render/SDL_yuv_sw_c.h | 2 +- src/render/direct3d/SDL_render_d3d.c | 12 +- src/render/direct3d11/SDL_render_d3d11.c | 31 +- src/render/direct3d11/SDL_render_winrt.cpp | 2 +- src/render/direct3d11/SDL_render_winrt.h | 2 +- src/render/opengl/SDL_glfuncs.h | 2 +- src/render/opengl/SDL_render_gl.c | 19 +- src/render/opengl/SDL_shaders_gl.c | 2 +- src/render/opengl/SDL_shaders_gl.h | 2 +- src/render/opengles/SDL_glesfuncs.h | 2 +- src/render/opengles/SDL_render_gles.c | 58 +- src/render/opengles2/SDL_gles2funcs.h | 6 +- src/render/opengles2/SDL_render_gles2.c | 351 +++++---- src/render/opengles2/SDL_shaders_gles2.c | 20 +- src/render/opengles2/SDL_shaders_gles2.h | 2 +- src/render/psp/SDL_render_psp.c | 4 +- src/render/software/SDL_blendfillrect.c | 2 +- src/render/software/SDL_blendfillrect.h | 2 +- src/render/software/SDL_blendline.c | 2 +- src/render/software/SDL_blendline.h | 2 +- src/render/software/SDL_blendpoint.c | 2 +- src/render/software/SDL_blendpoint.h | 2 +- src/render/software/SDL_draw.h | 2 +- src/render/software/SDL_drawline.c | 2 +- src/render/software/SDL_drawline.h | 2 +- src/render/software/SDL_drawpoint.c | 2 +- src/render/software/SDL_drawpoint.h | 2 +- src/render/software/SDL_render_sw.c | 182 +++-- src/render/software/SDL_render_sw_c.h | 2 +- src/render/software/SDL_rotate.c | 71 +- src/render/software/SDL_rotate.h | 2 +- src/stdlib/SDL_getenv.c | 7 +- src/stdlib/SDL_iconv.c | 7 +- src/stdlib/SDL_malloc.c | 7 +- src/stdlib/SDL_qsort.c | 5 + src/stdlib/SDL_stdlib.c | 11 +- src/stdlib/SDL_string.c | 11 +- src/test/SDL_test_assert.c | 2 +- src/test/SDL_test_common.c | 17 +- src/test/SDL_test_compare.c | 10 +- src/test/SDL_test_crc32.c | 2 +- src/test/SDL_test_font.c | 2 +- src/test/SDL_test_fuzzer.c | 3 +- src/test/SDL_test_harness.c | 3 +- src/test/SDL_test_imageBlit.c | 2 +- src/test/SDL_test_imageBlitBlend.c | 2 +- src/test/SDL_test_imageFace.c | 2 +- src/test/SDL_test_imagePrimitives.c | 2 +- src/test/SDL_test_imagePrimitivesBlend.c | 2 +- src/test/SDL_test_log.c | 2 +- src/test/SDL_test_md5.c | 2 +- src/test/SDL_test_random.c | 2 +- src/thread/SDL_systhread.h | 2 +- src/thread/SDL_thread.c | 2 +- src/thread/SDL_thread_c.h | 2 +- src/thread/generic/SDL_syscond.c | 2 +- src/thread/generic/SDL_sysmutex.c | 2 +- src/thread/generic/SDL_sysmutex_c.h | 2 +- src/thread/generic/SDL_syssem.c | 2 +- src/thread/generic/SDL_systhread.c | 2 +- src/thread/generic/SDL_systhread_c.h | 2 +- src/thread/generic/SDL_systls.c | 2 +- src/thread/psp/SDL_syscond.c | 6 +- src/thread/psp/SDL_sysmutex.c | 6 +- src/thread/psp/SDL_sysmutex_c.h | 2 +- src/thread/psp/SDL_syssem.c | 9 +- src/thread/psp/SDL_systhread.c | 6 +- src/thread/psp/SDL_systhread_c.h | 2 +- src/thread/pthread/SDL_syscond.c | 12 +- src/thread/pthread/SDL_sysmutex.c | 4 +- src/thread/pthread/SDL_sysmutex_c.h | 2 +- src/thread/pthread/SDL_syssem.c | 30 +- src/thread/pthread/SDL_systhread.c | 24 +- src/thread/pthread/SDL_systhread_c.h | 2 +- src/thread/pthread/SDL_systls.c | 2 +- src/thread/stdcpp/SDL_syscond.cpp | 2 +- src/thread/stdcpp/SDL_sysmutex.cpp | 2 +- src/thread/stdcpp/SDL_sysmutex_c.h | 2 +- src/thread/stdcpp/SDL_systhread.cpp | 2 +- src/thread/stdcpp/SDL_systhread_c.h | 2 +- src/thread/windows/SDL_sysmutex.c | 2 +- src/thread/windows/SDL_syssem.c | 2 +- src/thread/windows/SDL_systhread.c | 2 +- src/thread/windows/SDL_systhread_c.h | 2 +- src/thread/windows/SDL_systls.c | 2 +- src/timer/SDL_timer.c | 2 +- src/timer/SDL_timer_c.h | 2 +- src/timer/dummy/SDL_systimer.c | 2 +- src/timer/haiku/SDL_systimer.c | 2 +- src/timer/psp/SDL_systimer.c | 7 +- src/timer/unix/SDL_systimer.c | 17 +- src/timer/windows/SDL_systimer.c | 84 +-- src/video/SDL_RLEaccel.c | 16 +- src/video/SDL_RLEaccel_c.h | 2 +- src/video/SDL_blit.c | 2 +- src/video/SDL_blit.h | 2 +- src/video/SDL_blit_0.c | 2 +- src/video/SDL_blit_1.c | 2 +- src/video/SDL_blit_A.c | 4 +- src/video/SDL_blit_N.c | 42 +- src/video/SDL_blit_auto.c | 2 +- src/video/SDL_blit_auto.h | 2 +- src/video/SDL_blit_copy.c | 2 +- src/video/SDL_blit_copy.h | 2 +- src/video/SDL_blit_slow.c | 2 +- src/video/SDL_blit_slow.h | 2 +- src/video/SDL_bmp.c | 17 +- src/video/SDL_clipboard.c | 16 +- src/video/SDL_egl.c | 192 +++-- src/video/SDL_egl_c.h | 2 +- src/video/SDL_fillrect.c | 24 +- src/video/SDL_pixels.c | 6 +- src/video/SDL_pixels_c.h | 2 +- src/video/SDL_rect.c | 2 +- src/video/SDL_rect_c.h | 2 +- src/video/SDL_shape.c | 2 +- src/video/SDL_shape_internals.h | 2 +- src/video/SDL_stretch.c | 2 +- src/video/SDL_surface.c | 18 +- src/video/SDL_sysvideo.h | 14 +- src/video/SDL_video.c | 274 +++++-- src/video/android/SDL_androidclipboard.c | 2 +- src/video/android/SDL_androidclipboard.h | 2 +- src/video/android/SDL_androidevents.c | 8 +- src/video/android/SDL_androidevents.h | 2 +- src/video/android/SDL_androidgl.c | 2 +- src/video/android/SDL_androidkeyboard.c | 43 +- src/video/android/SDL_androidkeyboard.h | 2 +- src/video/android/SDL_androidmessagebox.c | 4 +- src/video/android/SDL_androidmessagebox.h | 2 +- src/video/android/SDL_androidmouse.c | 84 +++ src/video/android/SDL_androidmouse.h | 31 + src/video/android/SDL_androidtouch.c | 69 +- src/video/android/SDL_androidtouch.h | 3 +- src/video/android/SDL_androidvideo.c | 11 +- src/video/android/SDL_androidvideo.h | 4 +- src/video/android/SDL_androidwindow.c | 2 +- src/video/android/SDL_androidwindow.h | 2 +- src/video/cocoa/SDL_cocoaclipboard.h | 2 +- src/video/cocoa/SDL_cocoaclipboard.m | 2 +- src/video/cocoa/SDL_cocoaevents.h | 3 +- src/video/cocoa/SDL_cocoaevents.m | 131 +++- src/video/cocoa/SDL_cocoakeyboard.h | 2 +- src/video/cocoa/SDL_cocoakeyboard.m | 2 +- src/video/cocoa/SDL_cocoamessagebox.h | 2 +- src/video/cocoa/SDL_cocoamessagebox.m | 2 +- src/video/cocoa/SDL_cocoamodes.h | 2 +- src/video/cocoa/SDL_cocoamodes.m | 3 +- src/video/cocoa/SDL_cocoamouse.h | 2 +- src/video/cocoa/SDL_cocoamouse.m | 49 +- src/video/cocoa/SDL_cocoamousetap.h | 2 +- src/video/cocoa/SDL_cocoamousetap.m | 2 +- src/video/cocoa/SDL_cocoaopengl.h | 2 +- src/video/cocoa/SDL_cocoaopengl.m | 51 +- src/video/cocoa/SDL_cocoashape.h | 2 +- src/video/cocoa/SDL_cocoashape.m | 8 +- src/video/cocoa/SDL_cocoavideo.h | 6 +- src/video/cocoa/SDL_cocoavideo.m | 6 +- src/video/cocoa/SDL_cocoawindow.h | 3 +- src/video/cocoa/SDL_cocoawindow.m | 309 +++++--- src/video/directfb/SDL_DirectFB_WM.c | 4 +- src/video/directfb/SDL_DirectFB_WM.h | 2 +- src/video/directfb/SDL_DirectFB_dyn.c | 2 +- src/video/directfb/SDL_DirectFB_dyn.h | 2 +- src/video/directfb/SDL_DirectFB_events.c | 2 +- src/video/directfb/SDL_DirectFB_events.h | 2 +- src/video/directfb/SDL_DirectFB_modes.c | 2 +- src/video/directfb/SDL_DirectFB_modes.h | 2 +- src/video/directfb/SDL_DirectFB_mouse.c | 2 +- src/video/directfb/SDL_DirectFB_mouse.h | 2 +- src/video/directfb/SDL_DirectFB_opengl.c | 2 +- src/video/directfb/SDL_DirectFB_opengl.h | 2 +- src/video/directfb/SDL_DirectFB_render.c | 2 +- src/video/directfb/SDL_DirectFB_render.h | 2 +- src/video/directfb/SDL_DirectFB_shape.c | 2 +- src/video/directfb/SDL_DirectFB_shape.h | 2 +- src/video/directfb/SDL_DirectFB_video.c | 4 +- src/video/directfb/SDL_DirectFB_video.h | 2 +- src/video/directfb/SDL_DirectFB_window.c | 2 +- src/video/directfb/SDL_DirectFB_window.h | 2 +- src/video/dummy/SDL_nullevents.c | 2 +- src/video/dummy/SDL_nullevents_c.h | 2 +- src/video/dummy/SDL_nullframebuffer.c | 2 +- src/video/dummy/SDL_nullframebuffer_c.h | 2 +- src/video/dummy/SDL_nullvideo.c | 3 +- src/video/dummy/SDL_nullvideo.h | 2 +- src/video/emscripten/SDL_emscriptenevents.c | 644 ++++++++++++++++ src/video/emscripten/SDL_emscriptenevents.h | 36 + .../emscripten/SDL_emscriptenframebuffer.c | 136 ++++ .../emscripten/SDL_emscriptenframebuffer.h | 32 + src/video/emscripten/SDL_emscriptenmouse.c | 232 ++++++ src/video/emscripten/SDL_emscriptenmouse.h | 39 + src/video/emscripten/SDL_emscriptenopengles.c | 117 +++ src/video/emscripten/SDL_emscriptenopengles.h | 49 ++ src/video/emscripten/SDL_emscriptenvideo.c | 319 ++++++++ src/video/emscripten/SDL_emscriptenvideo.h | 52 ++ src/video/haiku/SDL_BWin.h | 2 +- src/video/haiku/SDL_bclipboard.cc | 2 +- src/video/haiku/SDL_bclipboard.h | 2 +- src/video/haiku/SDL_bevents.cc | 2 +- src/video/haiku/SDL_bevents.h | 2 +- src/video/haiku/SDL_bframebuffer.cc | 2 +- src/video/haiku/SDL_bframebuffer.h | 2 +- src/video/haiku/SDL_bkeyboard.cc | 2 +- src/video/haiku/SDL_bkeyboard.h | 2 +- src/video/haiku/SDL_bmodes.cc | 2 +- src/video/haiku/SDL_bmodes.h | 2 +- src/video/haiku/SDL_bopengl.cc | 2 +- src/video/haiku/SDL_bopengl.h | 2 +- src/video/haiku/SDL_bvideo.cc | 2 +- src/video/haiku/SDL_bvideo.h | 2 +- src/video/haiku/SDL_bwindow.cc | 2 +- src/video/haiku/SDL_bwindow.h | 2 +- src/video/mir/SDL_mirdyn.c | 2 +- src/video/mir/SDL_mirdyn.h | 2 +- src/video/mir/SDL_mirevents.c | 4 +- src/video/mir/SDL_mirevents.h | 2 +- src/video/mir/SDL_mirframebuffer.c | 2 +- src/video/mir/SDL_mirframebuffer.h | 2 +- src/video/mir/SDL_mirmouse.c | 6 +- src/video/mir/SDL_mirmouse.h | 2 +- src/video/mir/SDL_miropengl.c | 2 +- src/video/mir/SDL_miropengl.h | 2 +- src/video/mir/SDL_mirsym.h | 7 +- src/video/mir/SDL_mirvideo.c | 2 +- src/video/mir/SDL_mirvideo.h | 2 +- src/video/mir/SDL_mirwindow.c | 12 +- src/video/mir/SDL_mirwindow.h | 4 +- src/video/nacl/SDL_naclevents.c | 10 +- src/video/nacl/SDL_naclevents_c.h | 2 +- src/video/nacl/SDL_naclglue.c | 4 +- src/video/nacl/SDL_naclopengles.c | 2 +- src/video/nacl/SDL_naclopengles.h | 2 +- src/video/nacl/SDL_naclvideo.c | 4 +- src/video/nacl/SDL_naclvideo.h | 2 +- src/video/nacl/SDL_naclwindow.c | 2 +- src/video/nacl/SDL_naclwindow.h | 2 +- src/video/pandora/SDL_pandora.c | 2 +- src/video/pandora/SDL_pandora.h | 2 +- src/video/pandora/SDL_pandora_events.c | 2 +- src/video/pandora/SDL_pandora_events.h | 2 +- src/video/psp/SDL_pspevents.c | 8 +- src/video/psp/SDL_pspevents_c.h | 2 +- src/video/psp/SDL_pspgl.c | 8 +- src/video/psp/SDL_pspgl_c.h | 2 +- src/video/psp/SDL_pspmouse.c | 8 +- src/video/psp/SDL_pspmouse_c.h | 2 +- src/video/psp/SDL_pspvideo.c | 6 +- src/video/psp/SDL_pspvideo.h | 8 +- src/video/raspberry/SDL_rpievents.c | 2 +- src/video/raspberry/SDL_rpievents_c.h | 2 +- src/video/raspberry/SDL_rpimouse.c | 11 +- src/video/raspberry/SDL_rpimouse.h | 2 +- src/video/raspberry/SDL_rpiopengles.c | 2 +- src/video/raspberry/SDL_rpiopengles.h | 2 +- src/video/raspberry/SDL_rpivideo.c | 13 +- src/video/raspberry/SDL_rpivideo.h | 2 +- src/video/sdlgenblit.pl | 2 +- src/video/uikit/SDL_uikitappdelegate.h | 17 +- src/video/uikit/SDL_uikitappdelegate.m | 367 +++++++--- src/video/uikit/SDL_uikitevents.h | 2 +- src/video/uikit/SDL_uikitevents.m | 5 +- src/video/uikit/SDL_uikitmessagebox.h | 2 +- src/video/uikit/SDL_uikitmessagebox.m | 80 +- src/video/uikit/SDL_uikitmodes.h | 24 +- src/video/uikit/SDL_uikitmodes.m | 187 ++--- src/video/uikit/SDL_uikitopengles.h | 4 +- src/video/uikit/SDL_uikitopengles.m | 251 ++++--- src/video/uikit/SDL_uikitopenglview.h | 74 +- src/video/uikit/SDL_uikitopenglview.m | 381 +++++++--- src/video/uikit/SDL_uikitvideo.h | 18 +- src/video/uikit/SDL_uikitvideo.m | 49 +- src/video/uikit/SDL_uikitview.h | 49 +- src/video/uikit/SDL_uikitview.m | 452 +++--------- src/video/uikit/SDL_uikitviewcontroller.h | 52 +- src/video/uikit/SDL_uikitviewcontroller.m | 384 ++++++++-- src/video/uikit/SDL_uikitwindow.h | 25 +- src/video/uikit/SDL_uikitwindow.m | 488 ++++++++----- src/video/uikit/keyinfotable.h | 4 +- src/video/vivante/SDL_vivanteopengles.c | 2 +- src/video/vivante/SDL_vivanteopengles.h | 2 +- src/video/vivante/SDL_vivanteplatform.c | 2 +- src/video/vivante/SDL_vivanteplatform.h | 2 +- src/video/vivante/SDL_vivantevideo.c | 2 +- src/video/vivante/SDL_vivantevideo.h | 2 +- src/video/wayland/SDL_waylanddyn.c | 2 +- src/video/wayland/SDL_waylanddyn.h | 2 +- src/video/wayland/SDL_waylandevents.c | 67 +- src/video/wayland/SDL_waylandevents_c.h | 2 +- src/video/wayland/SDL_waylandmouse.c | 9 +- src/video/wayland/SDL_waylandmouse.h | 2 +- src/video/wayland/SDL_waylandopengles.c | 2 +- src/video/wayland/SDL_waylandopengles.h | 2 +- src/video/wayland/SDL_waylandsym.h | 2 +- src/video/wayland/SDL_waylandtouch.c | 12 +- src/video/wayland/SDL_waylandtouch.h | 2 +- src/video/wayland/SDL_waylandvideo.c | 208 ++---- src/video/wayland/SDL_waylandvideo.h | 17 +- src/video/wayland/SDL_waylandwindow.c | 29 +- src/video/wayland/SDL_waylandwindow.h | 3 +- src/video/windows/SDL_msctf.h | 2 +- src/video/windows/SDL_vkeys.h | 2 +- src/video/windows/SDL_windowsclipboard.c | 2 +- src/video/windows/SDL_windowsclipboard.h | 2 +- src/video/windows/SDL_windowsevents.c | 164 +++-- src/video/windows/SDL_windowsevents.h | 2 +- src/video/windows/SDL_windowsframebuffer.c | 2 +- src/video/windows/SDL_windowsframebuffer.h | 2 +- src/video/windows/SDL_windowskeyboard.c | 30 +- src/video/windows/SDL_windowskeyboard.h | 2 +- src/video/windows/SDL_windowsmessagebox.c | 2 +- src/video/windows/SDL_windowsmessagebox.h | 2 +- src/video/windows/SDL_windowsmodes.c | 105 ++- src/video/windows/SDL_windowsmodes.h | 6 +- src/video/windows/SDL_windowsmouse.c | 5 +- src/video/windows/SDL_windowsmouse.h | 2 +- src/video/windows/SDL_windowsopengl.c | 26 +- src/video/windows/SDL_windowsopengl.h | 3 +- src/video/windows/SDL_windowsopengles.c | 3 +- src/video/windows/SDL_windowsopengles.h | 2 +- src/video/windows/SDL_windowsshape.c | 2 +- src/video/windows/SDL_windowsshape.h | 2 +- src/video/windows/SDL_windowsvideo.c | 11 +- src/video/windows/SDL_windowsvideo.h | 21 +- src/video/windows/SDL_windowswindow.c | 18 +- src/video/windows/SDL_windowswindow.h | 2 +- src/video/windows/wmmsg.h | 2 +- src/video/winrt/SDL_winrtevents.cpp | 2 +- src/video/winrt/SDL_winrtevents_c.h | 3 +- src/video/winrt/SDL_winrtkeyboard.cpp | 501 +++++++------ src/video/winrt/SDL_winrtmessagebox.cpp | 2 +- src/video/winrt/SDL_winrtmessagebox.h | 2 +- src/video/winrt/SDL_winrtmouse.cpp | 2 +- src/video/winrt/SDL_winrtmouse_c.h | 4 +- src/video/winrt/SDL_winrtopengles.cpp | 148 +++- src/video/winrt/SDL_winrtopengles.h | 20 +- src/video/winrt/SDL_winrtpointerinput.cpp | 14 +- src/video/winrt/SDL_winrtvideo.cpp | 45 +- src/video/winrt/SDL_winrtvideo_cpp.h | 2 +- src/video/x11/SDL_x11clipboard.c | 19 +- src/video/x11/SDL_x11clipboard.h | 3 +- src/video/x11/SDL_x11dyn.c | 4 +- src/video/x11/SDL_x11dyn.h | 5 +- src/video/x11/SDL_x11events.c | 420 +++++++---- src/video/x11/SDL_x11events.h | 2 +- src/video/x11/SDL_x11framebuffer.c | 2 +- src/video/x11/SDL_x11framebuffer.h | 2 +- src/video/x11/SDL_x11keyboard.c | 34 +- src/video/x11/SDL_x11keyboard.h | 2 +- src/video/x11/SDL_x11messagebox.c | 91 ++- src/video/x11/SDL_x11messagebox.h | 2 +- src/video/x11/SDL_x11modes.c | 419 +++++++---- src/video/x11/SDL_x11modes.h | 6 +- src/video/x11/SDL_x11mouse.c | 15 +- src/video/x11/SDL_x11mouse.h | 2 +- src/video/x11/SDL_x11opengl.c | 203 +++-- src/video/x11/SDL_x11opengl.h | 5 +- src/video/x11/SDL_x11opengles.c | 2 +- src/video/x11/SDL_x11opengles.h | 2 +- src/video/x11/SDL_x11shape.c | 2 +- src/video/x11/SDL_x11shape.h | 2 +- src/video/x11/SDL_x11sym.h | 22 +- src/video/x11/SDL_x11touch.c | 2 +- src/video/x11/SDL_x11touch.h | 2 +- src/video/x11/SDL_x11video.c | 3 +- src/video/x11/SDL_x11video.h | 6 +- src/video/x11/SDL_x11window.c | 80 +- src/video/x11/SDL_x11window.h | 5 +- src/video/x11/SDL_x11xinput2.c | 24 +- src/video/x11/SDL_x11xinput2.h | 2 +- 649 files changed, 10837 insertions(+), 5253 deletions(-) create mode 100644 src/audio/emscripten/SDL_emscriptenaudio.c create mode 100644 src/audio/emscripten/SDL_emscriptenaudio.h create mode 100644 src/filesystem/emscripten/SDL_sysfilesystem.c delete mode 100644 src/joystick/SDL_gamecontrollerdb.h.new create mode 100644 src/joystick/emscripten/SDL_sysjoystick.c create mode 100644 src/joystick/emscripten/SDL_sysjoystick_c.h create mode 100644 src/power/emscripten/SDL_syspower.c create mode 100644 src/video/android/SDL_androidmouse.c create mode 100644 src/video/android/SDL_androidmouse.h create mode 100644 src/video/emscripten/SDL_emscriptenevents.c create mode 100644 src/video/emscripten/SDL_emscriptenevents.h create mode 100644 src/video/emscripten/SDL_emscriptenframebuffer.c create mode 100644 src/video/emscripten/SDL_emscriptenframebuffer.h create mode 100644 src/video/emscripten/SDL_emscriptenmouse.c create mode 100644 src/video/emscripten/SDL_emscriptenmouse.h create mode 100644 src/video/emscripten/SDL_emscriptenopengles.c create mode 100644 src/video/emscripten/SDL_emscriptenopengles.h create mode 100644 src/video/emscripten/SDL_emscriptenvideo.c create mode 100644 src/video/emscripten/SDL_emscriptenvideo.h diff --git a/files.xml b/files.xml index 02a35162c..230cf24c0 100644 --- a/files.xml +++ b/files.xml @@ -390,10 +390,23 @@ + +
+ + + + + + + + + +
+ diff --git a/include/SDL.h b/include/SDL.h index 703dc3d94..9d1ede336 100644 --- a/include/SDL.h +++ b/include/SDL.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_assert.h b/include/SDL_assert.h index 94d998770..6889514d4 100644 --- a/include/SDL_assert.h +++ b/include/SDL_assert.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..bb01eb9e1 100644 --- a/include/SDL_atomic.h +++ b/include/SDL_atomic.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_audio.h b/include/SDL_audio.h index 5c04b0bf4..359005d02 100644 --- a/include/SDL_audio.h +++ b/include/SDL_audio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_bits.h b/include/SDL_bits.h index 341524fd9..c62766d9e 100644 --- a/include/SDL_bits.h +++ b/include/SDL_bits.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_blendmode.h b/include/SDL_blendmode.h index 8c257be9c..c7fa09f72 100644 --- a/include/SDL_blendmode.h +++ b/include/SDL_blendmode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -58,6 +58,6 @@ typedef enum #endif #include "close_code.h" -#endif /* _SDL_video_h */ +#endif /* _SDL_blendmode_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/include/SDL_clipboard.h b/include/SDL_clipboard.h index 74e2b32fe..3ad20548b 100644 --- a/include/SDL_clipboard.h +++ b/include/SDL_clipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_config_android.h b/include/SDL_config_android.h index 569ff1d5e..8d5f1e5f2 100644 --- a/include/SDL_config_android.h +++ b/include/SDL_config_android.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -43,7 +43,6 @@ #define HAVE_STDINT_H 1 #define HAVE_CTYPE_H 1 #define HAVE_MATH_H 1 -#define HAVE_SIGNAL_H 1 /* C library functions */ #define HAVE_MALLOC 1 @@ -76,7 +75,6 @@ #define HAVE_STRTOULL 1 #define HAVE_STRTOD 1 #define HAVE_ATOI 1 -#define HAVE_ATOF 1 #define HAVE_STRCMP 1 #define HAVE_STRNCMP 1 #define HAVE_STRCASECMP 1 @@ -103,10 +101,10 @@ #define HAVE_SQRTF 1 #define HAVE_TAN 1 #define HAVE_TANF 1 -#define HAVE_SIGACTION 1 #define HAVE_SETJMP 1 #define HAVE_NANOSLEEP 1 #define HAVE_SYSCONF 1 +#define HAVE_CLOCK_GETTIME 1 #define SIZEOF_VOIDP 4 diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index 4e3eb2c92..a605b707c 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_macosx.h b/include/SDL_config_macosx.h index b6af492d4..e4ce82fc2 100644 --- a/include/SDL_config_macosx.h +++ b/include/SDL_config_macosx.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -139,6 +139,7 @@ #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib" #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib" #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib" +#define SDL_VIDEO_DRIVER_X11_XDBE 1 #define SDL_VIDEO_DRIVER_X11_XINERAMA 1 #define SDL_VIDEO_DRIVER_X11_XRANDR 1 #define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1 diff --git a/include/SDL_config_minimal.h b/include/SDL_config_minimal.h index 1bddafea7..7721abc92 100644 --- a/include/SDL_config_minimal.h +++ b/include/SDL_config_minimal.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_config_pandora.h b/include/SDL_config_pandora.h index aead1ff9f..530e78f11 100644 --- a/include/SDL_config_pandora.h +++ b/include/SDL_config_pandora.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_config_psp.h b/include/SDL_config_psp.h index 617d691f2..26bf9d1a2 100644 --- a/include/SDL_config_psp.h +++ b/include/SDL_config_psp.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_config_windows.h b/include/SDL_config_windows.h index 8bc7ffe09..067d7f310 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_config_winrt.h b/include/SDL_config_winrt.h index d70a0bcd6..0a33993f6 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-2015 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 @@ -173,10 +173,8 @@ typedef unsigned int uintptr_t; #define SDL_VIDEO_DRIVER_DUMMY 1 /* Enable OpenGL ES 2.0 (via a modified ANGLE library) */ -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP /* TODO, WinRT: try adding OpenGL ES 2 support for Windows Phone 8 */ #define SDL_VIDEO_OPENGL_ES2 1 #define SDL_VIDEO_OPENGL_EGL 1 -#endif /* Enable appropriate renderer(s) */ #define SDL_VIDEO_RENDER_D3D11 1 diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h index 9204567c6..4b3c5a2a2 100644 --- a/include/SDL_config_wiz.h +++ b/include/SDL_config_wiz.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_copying.h b/include/SDL_copying.h index 0964da84f..6fd65219c 100644 --- a/include/SDL_copying.h +++ b/include/SDL_copying.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_cpuinfo.h b/include/SDL_cpuinfo.h index 5b2c7a459..30d09cce8 100644 --- a/include/SDL_cpuinfo.h +++ b/include/SDL_cpuinfo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_egl.h b/include/SDL_egl.h index ed49a92fd..2d78c382f 100644 --- a/include/SDL_egl.h +++ b/include/SDL_egl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_endian.h b/include/SDL_endian.h index 161c418de..ec7841c48 100644 --- a/include/SDL_endian.h +++ b/include/SDL_endian.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -42,7 +42,7 @@ #ifdef __linux__ #include #define SDL_BYTEORDER __BYTE_ORDER -#else /* __linux __ */ +#else /* __linux__ */ #if defined(__hppa__) || \ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ (defined(__MIPS__) && defined(__MISPEB__)) || \ @@ -52,7 +52,7 @@ #else #define SDL_BYTEORDER SDL_LIL_ENDIAN #endif -#endif /* __linux __ */ +#endif /* __linux__ */ #endif /* !SDL_BYTEORDER */ diff --git a/include/SDL_error.h b/include/SDL_error.h index 001abb0f9..1720c43f8 100644 --- a/include/SDL_error.h +++ b/include/SDL_error.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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..2ccb10132 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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.*) @@ -393,8 +412,8 @@ typedef struct SDL_TouchFingerEvent SDL_FingerID fingerId; float x; /**< Normalized in the range 0...1 */ float y; /**< Normalized in the range 0...1 */ - float dx; /**< Normalized in the range 0...1 */ - float dy; /**< Normalized in the range 0...1 */ + float dx; /**< Normalized in the range -1...1 */ + float dy; /**< Normalized in the range -1...1 */ float pressure; /**< Normalized in the range 0...1 */ } SDL_TouchFingerEvent; @@ -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; @@ -434,8 +453,8 @@ typedef struct SDL_DollarGestureEvent /** * \brief An event used to request a file open by the system (event.drop.*) - * This event is disabled by default, you can enable it with SDL_EventState() - * \note If you enable this event, you must free the filename in the event. + * This event is enabled by default, you can disable it with SDL_EventState(). + * \note If this event is enabled, you must free the filename in the event. */ typedef struct SDL_DropEvent { @@ -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_filesystem.h b/include/SDL_filesystem.h index de3e227d4..15bda498a 100644 --- a/include/SDL_filesystem.h +++ b/include/SDL_filesystem.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -131,6 +131,6 @@ extern DECLSPEC char *SDLCALL SDL_GetPrefPath(const char *org, const char *app); #endif #include "close_code.h" -#endif /* _SDL_system_h */ +#endif /* _SDL_filesystem_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index b00ad713d..72fba60bf 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -43,7 +43,7 @@ extern "C" { * \file SDL_gamecontroller.h * * In order to use these functions, SDL_Init() must have been called - * with the ::SDL_INIT_JOYSTICK flag. This causes SDL to scan the system + * with the ::SDL_INIT_GAMECONTROLLER flag. This causes SDL to scan the system * for game controllers, and load appropriate drivers. * * If you would like to receive controller updates while the application @@ -163,8 +163,9 @@ extern DECLSPEC const char *SDLCALL SDL_GameControllerNameForIndex(int joystick_ /** * Open a game controller for use. * The index passed as an argument refers to the N'th game controller on the system. - * This index is the value which will identify this controller in future controller - * events. + * This index is not the value which will identify this controller in future + * controller events. The joystick's instance id (::SDL_JoystickID) will be + * used there instead. * * \return A controller identifier, or NULL if an error occurred. */ @@ -241,7 +242,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_gesture.h b/include/SDL_gesture.h index dbc169242..44983486d 100644 --- a/include/SDL_gesture.h +++ b/include/SDL_gesture.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_haptic.h b/include/SDL_haptic.h index 569c635ed..0e6f523b0 100644 --- a/include/SDL_haptic.h +++ b/include/SDL_haptic.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -102,11 +102,6 @@ * return 0; // Success * } * \endcode - * - * You can also find out more information on my blog: - * http://bobbens.dyndns.org/journal/2010/sdl_haptic/ - * - * \author Edgar Simo Serra */ #ifndef _SDL_haptic_h @@ -347,6 +342,9 @@ typedef struct _SDL_Haptic SDL_Haptic; /** * \brief Structure that represents a haptic direction. * + * This is the direction where the force comes from, + * instead of the direction in which the force is exerted. + * * Directions can be specified by: * - ::SDL_HAPTIC_POLAR : Specified by polar coordinates. * - ::SDL_HAPTIC_CARTESIAN : Specified by cartesian coordinates. @@ -555,7 +553,7 @@ typedef struct SDL_HapticPeriodic Uint16 period; /**< Period of the wave. */ Sint16 magnitude; /**< Peak value; if negative, equivalent to 180 degrees extra phase shift. */ Sint16 offset; /**< Mean value of the wave. */ - Uint16 phase; /**< Horizontal shift given by hundredth of a degree. */ + Uint16 phase; /**< Positive phase shift given by hundredth of a degree. */ /* Envelope */ Uint16 attack_length; /**< Duration of the attack. */ @@ -897,7 +895,7 @@ extern DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick * joystick); /** * \brief Opens a Haptic device for usage from a Joystick device. * - * You must still close the haptic device seperately. It will not be closed + * You must still close the haptic device separately. It will not be closed * with the joystick. * * When opening from a joystick you should first close the haptic device before @@ -954,7 +952,7 @@ extern DECLSPEC int SDLCALL SDL_HapticNumEffects(SDL_Haptic * haptic); extern DECLSPEC int SDLCALL SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic); /** - * \brief Gets the haptic devices supported features in bitwise matter. + * \brief Gets the haptic device's supported features in bitwise manner. * * Example: * \code diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 673d347eb..4e3089bf3 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -243,6 +243,9 @@ extern "C" { * this is problematic. This functionality can be disabled by setting this * hint. * + * As of SDL 2.0.4, SDL_EnableScreenSaver and SDL_DisableScreenSaver accomplish + * the same thing on iOS. They should be preferred over this hint. + * * This variable can be set to the following values: * "0" - Enable idle timer * "1" - Disable idle timer @@ -261,8 +264,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 @@ -344,8 +348,19 @@ extern "C" { #define SDL_HINT_TIMER_RESOLUTION "SDL_TIMER_RESOLUTION" + +/** +* \brief A string specifying SDL's threads stack size in bytes or "0" for the backend's default size +* +* Use this hint in case you need to set SDL's threads stack size to other than the default. +* This is specially useful if you build SDL against a non glibc libc library (such as musl) which +* provides a relatively small default thread stack size (a few kilobytes versus the default 8MB glibc uses). +* Support for this hint is currently available only in the pthread backend. +*/ +#define SDL_HINT_THREAD_STACK_SIZE "SDL_THREAD_STACK_SIZE" + /** - * \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" @@ -510,6 +525,14 @@ extern "C" { */ #define SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES "SDL_VIDEO_MAC_FULLSCREEN_SPACES" +/** +* \brief When set don't force the SDL app to become a foreground process +* +* This hint only applies to Mac OS X. +* +*/ +#define SDL_HINT_MAC_BACKGROUND_APP "SDL_MAC_BACKGROUND_APP" + /** * \brief Android APK expansion main file version. Should be a string number like "1", "2" etc. */ @@ -532,6 +555,53 @@ 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 Tell SDL not to generate window-close events for Alt+F4 on Windows. + * + * The variable can be set to the following values: + * "0" - SDL will generate a window-close event when it sees Alt+F4. + * "1" - SDL will only do normal key handling for Alt+F4. + */ +#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4" + /** * \brief An enumeration of hint priorities */ diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h index b0b1c6673..cad06a86c 100644 --- a/include/SDL_joystick.h +++ b/include/SDL_joystick.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -87,9 +87,10 @@ extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index); /** * Open a joystick for use. - * The index passed as an argument refers tothe N'th joystick on the system. - * This index is the value which will identify this joystick in future joystick - * events. + * The index passed as an argument refers to the N'th joystick on the system. + * This index is not the value which will identify this joystick in future + * joystick events. The joystick's instance id (::SDL_JoystickID) will be used + * there instead. * * \return A joystick identifier, or NULL if an error occurred. */ @@ -189,7 +190,7 @@ extern DECLSPEC Sint16 SDLCALL SDL_JoystickGetAxis(SDL_Joystick * joystick, */ /* @{ */ #define SDL_HAT_CENTERED 0x00 -#define SDL_HAT_UP 0x01 +#define SDL_HAT_UP 0x01 #define SDL_HAT_RIGHT 0x02 #define SDL_HAT_DOWN 0x04 #define SDL_HAT_LEFT 0x08 diff --git a/include/SDL_keyboard.h b/include/SDL_keyboard.h index 586a26cff..1ad58ee37 100644 --- a/include/SDL_keyboard.h +++ b/include/SDL_keyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_keycode.h b/include/SDL_keycode.h index d5f5dd0ae..66980cef0 100644 --- a/include/SDL_keycode.h +++ b/include/SDL_keycode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_loadso.h b/include/SDL_loadso.h index 0359eae17..db7493ad7 100644 --- a/include/SDL_loadso.h +++ b/include/SDL_loadso.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_log.h b/include/SDL_log.h index ef4d443c5..6ffbfc99f 100644 --- a/include/SDL_log.h +++ b/include/SDL_log.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_main.h b/include/SDL_main.h index 5dd73a9f5..c5168ba6b 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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). - * \ret 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more + * \param reserved Reserved for future use; should be NULL + * \return 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_messagebox.h b/include/SDL_messagebox.h index 6004da0f5..44d458f46 100644 --- a/include/SDL_messagebox.h +++ b/include/SDL_messagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_mouse.h b/include/SDL_mouse.h index e71a0c9e5..1ae312698 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 */ /** @@ -128,10 +137,11 @@ extern DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window, * * \param x The x coordinate * \param y The y coordinate + * \return 0 on success, -1 on error (usually: unsupported by a platform). * * \note This function generates a mouse motion event */ -extern DECLSPEC void SDLCALL SDL_WarpMouseGlobal(int x, int y); +extern DECLSPEC int SDLCALL SDL_WarpMouseGlobal(int x, int y); /** * \brief Set relative mouse mode. diff --git a/include/SDL_mutex.h b/include/SDL_mutex.h index 3e8b4dbed..2765210a4 100644 --- a/include/SDL_mutex.h +++ b/include/SDL_mutex.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_name.h b/include/SDL_name.h index 719666ff1..b6a413a2c 100644 --- a/include/SDL_name.h +++ b/include/SDL_name.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_opengl.h b/include/SDL_opengl.h index 35e9f308e..aebe30ebb 100644 --- a/include/SDL_opengl.h +++ b/include/SDL_opengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_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_opengles.h b/include/SDL_opengles.h index d88e1573f..49c709c1d 100644 --- a/include/SDL_opengles.h +++ b/include/SDL_opengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_opengles2.h b/include/SDL_opengles2.h index d245b8eb4..13ebd9dc2 100644 --- a/include/SDL_opengles2.h +++ b/include/SDL_opengles2.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_pixels.h b/include/SDL_pixels.h index 61e97c8d2..ba24a47dd 100644 --- a/include/SDL_pixels.h +++ b/include/SDL_pixels.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -86,6 +86,8 @@ enum }; /** Array component order, low byte -> high byte. */ +/* !!! FIXME: in 2.1, make these not overlap differently with + !!! FIXME: SDL_PACKEDORDER_*, so we can simplify SDL_ISPIXELFORMAT_ALPHA */ enum { SDL_ARRAYORDER_NONE, @@ -134,12 +136,31 @@ enum (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX4) || \ (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_INDEX8))) -#define SDL_ISPIXELFORMAT_ALPHA(format) \ +#define SDL_ISPIXELFORMAT_PACKED(format) \ + (!SDL_ISPIXELFORMAT_FOURCC(format) && \ + ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED8) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED16) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_PACKED32))) + +#define SDL_ISPIXELFORMAT_ARRAY(format) \ (!SDL_ISPIXELFORMAT_FOURCC(format) && \ + ((SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU8) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU16) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYU32) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYF16) || \ + (SDL_PIXELTYPE(format) == SDL_PIXELTYPE_ARRAYF32))) + +#define SDL_ISPIXELFORMAT_ALPHA(format) \ + ((SDL_ISPIXELFORMAT_PACKED(format) && \ ((SDL_PIXELORDER(format) == SDL_PACKEDORDER_ARGB) || \ (SDL_PIXELORDER(format) == SDL_PACKEDORDER_RGBA) || \ (SDL_PIXELORDER(format) == SDL_PACKEDORDER_ABGR) || \ - (SDL_PIXELORDER(format) == SDL_PACKEDORDER_BGRA))) + (SDL_PIXELORDER(format) == SDL_PACKEDORDER_BGRA))) || \ + (SDL_ISPIXELFORMAT_ARRAY(format) && \ + ((SDL_PIXELORDER(format) == SDL_ARRAYORDER_ARGB) || \ + (SDL_PIXELORDER(format) == SDL_ARRAYORDER_RGBA) || \ + (SDL_PIXELORDER(format) == SDL_ARRAYORDER_ABGR) || \ + (SDL_PIXELORDER(format) == SDL_ARRAYORDER_BGRA)))) /* The flag is set to 1 because 0x1? is not in the printable ASCII range */ #define SDL_ISPIXELFORMAT_FOURCC(format) \ diff --git a/include/SDL_platform.h b/include/SDL_platform.h index adafde520..75e4c6535 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_power.h b/include/SDL_power.h index cf71c9824..89eb1718f 100644 --- a/include/SDL_power.h +++ b/include/SDL_power.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_quit.h b/include/SDL_quit.h index 8a786445d..0108ff044 100644 --- a/include/SDL_quit.h +++ b/include/SDL_quit.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_rect.h b/include/SDL_rect.h index 6bfce3115..ebe516740 100644 --- a/include/SDL_rect.h +++ b/include/SDL_rect.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_render.h b/include/SDL_render.h index 192e502eb..b73d6e687 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; /** @@ -371,7 +371,7 @@ extern DECLSPEC int SDLCALL SDL_GetTextureBlendMode(SDL_Texture * texture, * \param rect A pointer to the rectangle of pixels to update, or NULL to * update the entire texture. * \param pixels The raw pixel data. - * \param pitch The number of bytes between rows of pixel data. + * \param pitch The number of bytes in a row of pixel data, including padding between lines. * * \return 0 on success, or -1 if the texture is not valid. * @@ -552,7 +552,7 @@ extern DECLSPEC void SDLCALL SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect); /** - * \brief Get wether clipping is enabled on the given renderer + * \brief Get whether clipping is enabled on the given renderer. * * \param renderer The renderer from which clip state should be queried. * @@ -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_revision.h b/include/SDL_revision.h index 63e670b17..6eacc8df2 100644 --- a/include/SDL_revision.h +++ b/include/SDL_revision.h @@ -1,2 +1,2 @@ -#define SDL_REVISION "hg-9174:f9244b2a1511" -#define SDL_REVISION_NUMBER 9174 +#define SDL_REVISION "hg-9859:2ec928ff921c" +#define SDL_REVISION_NUMBER 9859 diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h index b007fb632..c8b024be3 100644 --- a/include/SDL_rwops.h +++ b/include/SDL_rwops.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_scancode.h b/include/SDL_scancode.h index 4b3be28fb..4bf861804 100644 --- a/include/SDL_scancode.h +++ b/include/SDL_scancode.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_shape.h b/include/SDL_shape.h index 53029306e..157d61279 100644 --- a/include/SDL_shape.h +++ b/include/SDL_shape.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_stdinc.h b/include/SDL_stdinc.h index 78d3402e7..c1f2b6dd7 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_surface.h b/include/SDL_surface.h index aa8d82174..3634f7d38 100644 --- a/include/SDL_surface.h +++ b/include/SDL_surface.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_system.h b/include/SDL_system.h index 78d5b0d0a..bdc4f9684 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -42,20 +42,32 @@ extern "C" { /* Platform specific functions for Windows */ #ifdef __WIN32__ + +/** + \brief Set a function that is called for every windows message, before TranslateMessage() +*/ +typedef void (SDLCALL * SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam); +extern DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata); + +/** + \brief Returns the D3D9 adapter index that matches the specified display index. -/* 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 +79,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 +91,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 +108,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 +177,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 +194,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..a3441fdc9 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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) @@ -162,6 +163,7 @@ struct SDL_SysWMmsg #if defined(SDL_VIDEO_DRIVER_UIKIT) struct { + int dummy; /* No UIKit window events yet */ } uikit; #endif @@ -186,6 +188,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 +230,9 @@ 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. */ + GLuint resolveFramebuffer; /* The Framebuffer Object which holds the resolve color Renderbuffer, when MSAA is used. */ } uikit; #endif #if defined(SDL_VIDEO_DRIVER_WAYLAND) diff --git a/include/SDL_test.h b/include/SDL_test.h index ae649a420..77b350bd0 100644 --- a/include/SDL_test.h +++ b/include/SDL_test.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -52,7 +52,7 @@ extern "C" { /* Global definitions */ /* - * Note: Maximum size of SDLTest log message is less than SDLs limit + * Note: Maximum size of SDLTest log message is less than SDL's limit * to ensure we can fit additional information such as the timestamp. */ #define SDLTEST_MAX_LOGMESSAGE_LENGTH 3584 diff --git a/include/SDL_test_assert.h b/include/SDL_test_assert.h index 5b38f7ee6..a800a3840 100644 --- a/include/SDL_test_assert.h +++ b/include/SDL_test_assert.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -71,7 +71,7 @@ void SDLTest_Assert(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *as int SDLTest_AssertCheck(int assertCondition, SDL_PRINTF_FORMAT_STRING const char *assertDescription, ...) SDL_PRINTF_VARARG_FUNC(2); /** - * \brief Explicitely pass without checking an assertion condition. Updates assertion counter. + * \brief Explicitly pass without checking an assertion condition. Updates assertion counter. * * \param assertDescription Message to log with the assert describing it. */ diff --git a/include/SDL_test_common.h b/include/SDL_test_common.h index 45c9edafd..bb671fa50 100644 --- a/include/SDL_test_common.h +++ b/include/SDL_test_common.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_test_compare.h b/include/SDL_test_compare.h index f1353a8d2..bc1213363 100644 --- a/include/SDL_test_compare.h +++ b/include/SDL_test_compare.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -51,9 +51,9 @@ extern "C" { * * \param surface Surface used in comparison * \param referenceSurface Test Surface used in comparison - * \param allowable_error Allowable difference (squared) in blending accuracy. + * \param allowable_error Allowable difference (=sum of squared difference for each RGB component) in blending accuracy. * - * \returns 0 if comparison succeeded, >0 (=number of pixels where comparison failed) if comparison failed, -1 if any of the surfaces were NULL, -2 if the surface sizes differ. + * \returns 0 if comparison succeeded, >0 (=number of pixels for which the comparison failed) if comparison failed, -1 if any of the surfaces were NULL, -2 if the surface sizes differ. */ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int allowable_error); diff --git a/include/SDL_test_crc32.h b/include/SDL_test_crc32.h index a180fe3bb..cf9ea23db 100644 --- a/include/SDL_test_crc32.h +++ b/include/SDL_test_crc32.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -70,27 +70,27 @@ extern "C" { /* ---------- Function Prototypes ------------- */ /** - * /brief Initialize the CRC context + * \brief Initialize the CRC context * * Note: The function initializes the crc table required for all crc calculations. * - * /param crcContext pointer to context variable + * \param crcContext pointer to context variable * - * /returns 0 for OK, -1 on error + * \returns 0 for OK, -1 on error * */ int SDLTest_Crc32Init(SDLTest_Crc32Context * crcContext); /** - * /brief calculate a crc32 from a data block + * \brief calculate a crc32 from a data block * - * /param crcContext pointer to context variable - * /param inBuf input buffer to checksum - * /param inLen length of input buffer - * /param crc32 pointer to Uint32 to store the final CRC into + * \param crcContext pointer to context variable + * \param inBuf input buffer to checksum + * \param inLen length of input buffer + * \param crc32 pointer to Uint32 to store the final CRC into * - * /returns 0 for OK, -1 on error + * \returns 0 for OK, -1 on error * */ int SDLTest_crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32); @@ -102,11 +102,11 @@ int SDLTest_Crc32CalcBuffer(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, /** - * /brief clean up CRC context + * \brief clean up CRC context * - * /param crcContext pointer to context variable + * \param crcContext pointer to context variable * - * /returns 0 for OK, -1 on error + * \returns 0 for OK, -1 on error * */ diff --git a/include/SDL_test_font.h b/include/SDL_test_font.h index 8d51d4a9b..42696d74c 100644 --- a/include/SDL_test_font.h +++ b/include/SDL_test_font.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_test_fuzzer.h b/include/SDL_test_fuzzer.h index 640180397..59c89a501 100644 --- a/include/SDL_test_fuzzer.h +++ b/include/SDL_test_fuzzer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -57,7 +57,7 @@ extern "C" { /** * Initializes the fuzzer for a test * - * /param execKey Execution "Key" that initializes the random number generator uniquely for the test. + * \param execKey Execution "Key" that initializes the random number generator uniquely for the test. * */ void SDLTest_FuzzerInit(Uint64 execKey); @@ -318,7 +318,7 @@ Sint64 SDLTest_RandomSint64BoundaryValue(Sint64 boundary1, Sint64 boundary2, SDL /** * Returns integer in range [min, max] (inclusive). * Min and max values can be negative values. - * If Max in smaller tham min, then the values are swapped. + * If Max in smaller than min, then the values are swapped. * Min and max are the same value, that value will be returned. * * \param min Minimum inclusive value of returned random number diff --git a/include/SDL_test_harness.h b/include/SDL_test_harness.h index 2c1e2ade8..b33893157 100644 --- a/include/SDL_test_harness.h +++ b/include/SDL_test_harness.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_test_images.h b/include/SDL_test_images.h index 056279961..9b9f979b3 100644 --- a/include/SDL_test_images.h +++ b/include/SDL_test_images.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_test_log.h b/include/SDL_test_log.h index 2157954b8..968d9b32a 100644 --- a/include/SDL_test_log.h +++ b/include/SDL_test_log.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_test_md5.h b/include/SDL_test_md5.h index 029e164bf..52ea2c9a4 100644 --- a/include/SDL_test_md5.h +++ b/include/SDL_test_md5.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -78,9 +78,9 @@ extern "C" { /* ---------- Function Prototypes ------------- */ /** - * /brief initialize the context + * \brief initialize the context * - * /param mdContext pointer to context variable + * \param mdContext pointer to context variable * * Note: The function initializes the message-digest context * mdContext. Call before each new use of the context - @@ -90,11 +90,11 @@ extern "C" { /** - * /brief update digest from variable length data + * \brief update digest from variable length data * - * /param mdContext pointer to context variable - * /param inBuf pointer to data array/string - * /param inLen length of data array/string + * \param mdContext pointer to context variable + * \param inBuf pointer to data array/string + * \param inLen length of data array/string * * Note: The function updates the message-digest context to account * for the presence of each of the characters inBuf[0..inLen-1] @@ -105,10 +105,10 @@ extern "C" { unsigned int inLen); -/* - * /brief complete digest computation +/** + * \brief complete digest computation * - * /param mdContext pointer to context variable + * \param mdContext pointer to context variable * * Note: The function terminates the message-digest computation and * ends with the desired message digest in mdContext.digest[0..15]. diff --git a/include/SDL_test_random.h b/include/SDL_test_random.h index 6c5660d80..925205dfb 100644 --- a/include/SDL_test_random.h +++ b/include/SDL_test_random.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_thread.h b/include/SDL_thread.h index 9e5341410..797767f8b 100644 --- a/include/SDL_thread.h +++ b/include/SDL_thread.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_timer.h b/include/SDL_timer.h index a48e0466e..83cd1b3a8 100644 --- a/include/SDL_timer.h +++ b/include/SDL_timer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_touch.h b/include/SDL_touch.h index 017deb28b..68ff17149 100644 --- a/include/SDL_touch.h +++ b/include/SDL_touch.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_types.h b/include/SDL_types.h index cd3ba33cd..1a1877fa9 100644 --- a/include/SDL_types.h +++ b/include/SDL_types.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_version.h b/include/SDL_version.h index b74e24c94..0b364d073 100644 --- a/include/SDL_version.h +++ b/include/SDL_version.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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_video.h b/include/SDL_video.h index 4a2fb0458..f466165b4 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 */ @@ -289,6 +296,18 @@ extern DECLSPEC const char * SDLCALL SDL_GetDisplayName(int displayIndex); */ extern DECLSPEC int SDLCALL SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect); +/** + * \brief Get the dots/pixels-per-inch for a display + * + * \note Diagonal, horizontal and vertical DPI can all be optionally + * returned if the parameter is non-NULL. + * + * \return 0 on success, or -1 if no DPI information is available or the index is out of range. + * + * \sa SDL_GetNumVideoDisplays() + */ +extern DECLSPEC int SDLCALL SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi); + /** * \brief Returns the number of available display modes. * @@ -715,6 +734,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 +751,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/include/begin_code.h b/include/begin_code.h index b058bf369..c032400f7 100644 --- a/include/begin_code.h +++ b/include/begin_code.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -64,8 +64,6 @@ # else # if defined(__GNUC__) && __GNUC__ >= 4 # define DECLSPEC __attribute__ ((visibility("default"))) -# elif defined(__GNUC__) && __GNUC__ >= 2 -# define DECLSPEC __declspec(dllexport) # else # define DECLSPEC # endif diff --git a/include/close_code.h b/include/close_code.h index 9826f1478..73f6c8186 100644 --- a/include/close_code.h +++ b/include/close_code.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/configs/default/SDL_config.h b/include/configs/default/SDL_config.h index 9a2e51c55..eda766024 100644 --- a/include/configs/default/SDL_config.h +++ b/include/configs/default/SDL_config.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/SDL.c b/src/SDL.c index 1e2707d9c..6318bbe6f 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -405,6 +405,8 @@ SDL_GetPlatform() return "BSDI"; #elif __DREAMCAST__ return "Dreamcast"; +#elif __EMSCRIPTEN__ + return "Emscripten"; #elif __FREEBSD__ return "FreeBSD"; #elif __HAIKU__ @@ -439,6 +441,8 @@ SDL_GetPlatform() return "Solaris"; #elif __WIN32__ return "Windows"; +#elif __WINRT__ + return "WinRT"; #elif __IPHONEOS__ return "iOS"; #elif __PSP__ diff --git a/src/SDL_assert.c b/src/SDL_assert.c index 98e758447..e1d267a94 100644 --- a/src/SDL_assert.c +++ b/src/SDL_assert.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/SDL_assert_c.h b/src/SDL_assert_c.h index f94b24c29..6f05c925d 100644 --- a/src/SDL_assert_c.h +++ b/src/SDL_assert_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/SDL_error.c b/src/SDL_error.c index 2df29aa13..79e9347a4 100644 --- a/src/SDL_error.c +++ b/src/SDL_error.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -111,7 +111,7 @@ SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) va_end(ap); /* If we are in debug mode, print out an error message */ - SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError()); + SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError()); return -1; } @@ -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/SDL_error_c.h b/src/SDL_error_c.h index 98c20c492..946281d21 100644 --- a/src/SDL_error_c.h +++ b/src/SDL_error_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/SDL_hints.c b/src/SDL_hints.c index 365459ec7..7026ac5df 100644 --- a/src/SDL_hints.c +++ b/src/SDL_hints.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -137,6 +137,10 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) SDL_DelHintCallback(name, callback, userdata); entry = (SDL_HintWatch *)SDL_malloc(sizeof(*entry)); + if (!entry) { + SDL_OutOfMemory(); + return; + } entry->callback = callback; entry->userdata = userdata; @@ -149,6 +153,8 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) /* Need to add a hint entry for this watcher */ hint = (SDL_Hint *)SDL_malloc(sizeof(*hint)); if (!hint) { + SDL_OutOfMemory(); + SDL_free(entry); return; } hint->name = SDL_strdup(name); diff --git a/src/SDL_internal.h b/src/SDL_internal.h index cb66abd8e..a3ccb3630 100644 --- a/src/SDL_internal.h +++ b/src/SDL_internal.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/SDL_log.c b/src/SDL_log.c index 5ebab0152..b5ab601e9 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -371,9 +371,9 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, if (consoleAttached == 1) { if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) { OutputDebugString(TEXT("Error calling WriteConsole\r\n")); - } - if (charsWritten == ERROR_NOT_ENOUGH_MEMORY) { - OutputDebugString(TEXT("Insufficient heap memory to write message\r\n")); + if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) { + OutputDebugString(TEXT("Insufficient heap memory to write message\r\n")); + } } } #endif /* ifndef __WINRT__ */ diff --git a/src/atomic/SDL_atomic.c b/src/atomic/SDL_atomic.c index c6029c2ca..30b4ccca9 100644 --- a/src/atomic/SDL_atomic.c +++ b/src/atomic/SDL_atomic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index 29b5190e5..1681aa781 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 7559d6ca4..04f1e7ec2 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; +/* device hotplug support... */ + +static int +add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount) +{ + int retval = -1; + const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1; + SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size); + if (item == NULL) { + return -1; } + + SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */ + + item->handle = handle; + SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem)); + + SDL_LockMutex(current_audio.detectionLock); + item->next = *devices; + *devices = item; + retval = (*devCount)++; + SDL_UnlockMutex(current_audio.detectionLock); + + return retval; } -/* Read [length] bytes out of the streamer into buf */ -static void -SDL_StreamRead(SDL_AudioStreamer * stream, Uint8 * buf, int length) +static SDL_INLINE int +add_capture_device(const char *name, void *handle) { - int i; + /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/ + return add_audio_device(name, handle, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); +} - for (i = 0; i < length; ++i) { - buf[i] = stream->buffer[stream->read_pos]; - ++stream->read_pos; - } +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 int -SDL_StreamLength(SDL_AudioStreamer * stream) +static void +free_device_list(SDL_AudioDeviceItem **devices, int *devCount) { - return (stream->write_pos - stream->read_pos) % stream->max_len; + 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; } -/* 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) + +/* The audio backends call this when a new device is plugged in. */ +void +SDL_AddAudioDevice(const int iscapture, const char *name, void *handle) { - /* First try to allocate the buffer */ - stream->buffer = (Uint8 *) SDL_malloc(max_len); - if (stream->buffer == NULL) { - return -1; + 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); + } } +} - stream->max_len = max_len; - stream->read_pos = 0; - stream->write_pos = 0; +/* 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); - /* Zero out the buffer */ - SDL_memset(stream->buffer, silence, max_len); + if (!device->enabled) { + return; + } - return 0; + /* Ends the audio callback and mark the device as STOPPED, but the + app still needs to close the device to free resources. */ + current_audio.impl.LockDevice(device); + device->enabled = 0; + current_audio.impl.UnlockDevice(device); + + /* Post the event, if desired */ + if (SDL_GetEventState(SDL_AUDIODEVICEREMOVED) == SDL_ENABLE) { + SDL_Event event; + SDL_zero(event); + event.adevice.type = SDL_AUDIODEVICEREMOVED; + event.adevice.which = device->id; + event.adevice.iscapture = device->iscapture ? 1 : 0; + SDL_PushEvent(&event); + } } -#endif -/* Deinitialize the stream simply by freeing the buffer */ static void -SDL_StreamDeinit(SDL_AudioStreamer * stream) +mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *removedFlag) { - SDL_free(stream->buffer); + SDL_AudioDeviceItem *item; + SDL_assert(handle != NULL); + for (item = devices; item != NULL; item = item->next) { + if (item->handle == handle) { + item->handle = NULL; + *removedFlag = SDL_TRUE; + return; + } + } +} + +/* 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); } -#endif + /* 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; + } + /* !!! FIXME: this should be LockDevice. */ + SDL_LockMutex(device->mixer_lock); + if (device->paused) { + SDL_memset(stream, silence, stream_len); + } else { + (*fill) (udata, stream, stream_len); } - } else -#endif - { - /* Otherwise, do not use the streamer. This is the old code. */ - const int silence = (int) device->spec.silence; - - /* Loop, filling the audio buffers */ - while (device->enabled) { - - /* Fill the current buffer with sound */ - 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; - } - } + SDL_UnlockMutex(device->mixer_lock); - SDL_LockMutex(device->mixer_lock); - if (device->paused) { - SDL_memset(stream, silence, stream_len); + /* 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 { - (*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 ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { - if (index > 0) { - goto no_such_device; - } - return DEFAULT_INPUT_DEVNAME; - } + if (index >= 0) { + SDL_AudioDeviceItem *item; + int i; - if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) { - if (index > 0) { - goto no_such_device; + SDL_LockMutex(current_audio.detectionLock); + item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; + i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + if (index < i) { + for (i--; i > index; i--, item = item->next) { + SDL_assert(item != NULL); + } + SDL_assert(item != NULL); + retval = item->name; } - return DEFAULT_OUTPUT_DEVNAME; + SDL_UnlockMutex(current_audio.detectionLock); } - 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]; + if (retval == NULL) { + SDL_SetError("No such device"); } -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_audio_c.h b/src/audio/SDL_audio_c.h index 2ea4e148c..b1fab65ff 100644 --- a/src/audio/SDL_audio_c.h +++ b/src/audio/SDL_audio_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 518735bfc..092839b8e 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_audiodev.c b/src/audio/SDL_audiodev.c index e9af62119..dd89af743 100644 --- a/src/audio/SDL_audiodev.c +++ b/src/audio/SDL_audiodev.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..2208d9c49 100644 --- a/src/audio/SDL_audiodev_c.h +++ b/src/audio/SDL_audiodev_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_audiomem.h b/src/audio/SDL_audiomem.h index 3711ac945..a65b44b79 100644 --- a/src/audio/SDL_audiomem.h +++ b/src/audio/SDL_audiomem.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_audiotypecvt.c b/src/audio/SDL_audiotypecvt.c index 6f07d6280..1e3a64470 100644 --- a/src/audio/SDL_audiotypecvt.c +++ b/src/audio/SDL_audiotypecvt.c @@ -1,7 +1,7 @@ /* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_mixer.c b/src/audio/SDL_mixer.c index 42a1c6873..38fda0bf7 100644 --- a/src/audio/SDL_mixer.c +++ b/src/audio/SDL_mixer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 4f933205d..c220f5821 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/SDL_wave.c b/src/audio/SDL_wave.c index 988e4b72a..e898115ce 100644 --- a/src/audio/SDL_wave.c +++ b/src/audio/SDL_wave.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/SDL_wave.h b/src/audio/SDL_wave.h index 6c20c60fb..ccfa04480 100644 --- a/src/audio/SDL_wave.h +++ b/src/audio/SDL_wave.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 1f3def3f6..fac51978b 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/alsa/SDL_alsa_audio.h b/src/audio/alsa/SDL_alsa_audio.h index 45353883d..c5d3aeeef 100644 --- a/src/audio/alsa/SDL_alsa_audio.h +++ b/src/audio/alsa/SDL_alsa_audio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index fe66763b8..f35878cd6 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/android/SDL_androidaudio.h b/src/audio/android/SDL_androidaudio.h index 77bb219da..38bb19054 100644 --- a/src/audio/android/SDL_androidaudio.h +++ b/src/audio/android/SDL_androidaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 72fba70cc..ca97c0af1 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/arts/SDL_artsaudio.h b/src/audio/arts/SDL_artsaudio.h index fb7706fcf..54b86f6b0 100644 --- a/src/audio/arts/SDL_artsaudio.h +++ b/src/audio/arts/SDL_artsaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/bsd/SDL_bsdaudio.c b/src/audio/bsd/SDL_bsdaudio.c index f415fe040..b684f9eb3 100644 --- a/src/audio/bsd/SDL_bsdaudio.c +++ b/src/audio/bsd/SDL_bsdaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/bsd/SDL_bsdaudio.h b/src/audio/bsd/SDL_bsdaudio.h index 625bdb549..7eee944f9 100644 --- a/src/audio/bsd/SDL_bsdaudio.h +++ b/src/audio/bsd/SDL_bsdaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c index 7fc9ea94b..f75bc7846 100644 --- a/src/audio/coreaudio/SDL_coreaudio.c +++ b/src/audio/coreaudio/SDL_coreaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; -typedef struct +static SDL_bool +add_to_internal_dev_list(const int iscapture, AudioDeviceID devId) { - const char *findname; - AudioDeviceID devId; - int found; -} FindDevIdData; + 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; +} 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; - - addr.mScope = iscapture ? kAudioDevicePropertyScopeInput : - kAudioDevicePropertyScopeOutput; - addr.mSelector = kAudioDevicePropertyStreamConfiguration; + const AudioObjectPropertyAddress addr = { + kAudioDevicePropertyStreamConfiguration, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + 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; - - AudioObjectPropertyAddress addr = { - 0, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + build_device_list(SDL_TRUE, addToDevList, NULL); + build_device_list(SDL_FALSE, addToDevList, NULL); +} - 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; - - size = sizeof (alive); - result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive); - CHECK_RESULT - ("AudioDeviceGetProperty (kAudioDevicePropertyDeviceIsAlive)"); + add_to_internal_dev_list(iscapture, devId); /* new device, add it. */ + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); +} - 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); - - /* 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; + build_device_list(iscapture, build_device_change_list, list); + + /* 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/coreaudio/SDL_coreaudio.h b/src/audio/coreaudio/SDL_coreaudio.h index 41e8cea2b..119d25826 100644 --- a/src/audio/coreaudio/SDL_coreaudio.h +++ b/src/audio/coreaudio/SDL_coreaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index 067683ccc..10c32f83f 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/directsound/SDL_directsound.h b/src/audio/directsound/SDL_directsound.h index ae7faa451..718cbab34 100644 --- a/src/audio/directsound/SDL_directsound.h +++ b/src/audio/directsound/SDL_directsound.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index cc4e3efc6..ef8bc0dcb 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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,10 +100,11 @@ DISKAUD_CloseDevice(_THIS) } static int -DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture) +DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { + /* handle != NULL means "user specified the placeholder name on the fake detected device list" */ + const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname); const char *envr = SDL_getenv(DISKENVR_WRITEDELAY); - const char *fname = DISKAUD_GetOutputFilename(devname); this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); @@ -141,6 +142,13 @@ DISKAUD_OpenDevice(_THIS, const char *devname, int iscapture) return 0; } +static void +DISKAUD_DetectDevices(void) +{ + /* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */ + SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1); +} + static int DISKAUD_Init(SDL_AudioDriverImpl * impl) { @@ -150,6 +158,9 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = DISKAUD_PlayDevice; impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; impl->CloseDevice = DISKAUD_CloseDevice; + impl->DetectDevices = DISKAUD_DetectDevices; + + impl->AllowsArbitraryDeviceNames = 1; return 1; /* this audio target is available. */ } diff --git a/src/audio/disk/SDL_diskaudio.h b/src/audio/disk/SDL_diskaudio.h index 9c5a7afaf..0c1af3a54 100644 --- a/src/audio/disk/SDL_diskaudio.h +++ b/src/audio/disk/SDL_diskaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index eea5a5f86..678c74fe8 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/dsp/SDL_dspaudio.h b/src/audio/dsp/SDL_dspaudio.h index 5cbb563b9..054c4d9a0 100644 --- a/src/audio/dsp/SDL_dspaudio.h +++ b/src/audio/dsp/SDL_dspaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index 671e222cf..ec9c40fa1 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/dummy/SDL_dummyaudio.h b/src/audio/dummy/SDL_dummyaudio.h index 185401113..9415c122a 100644 --- a/src/audio/dummy/SDL_dummyaudio.h +++ b/src/audio/dummy/SDL_dummyaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c new file mode 100644 index 000000000..792f12c11 --- /dev/null +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -0,0 +1,279 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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; + }); + + if (!available) { + SDL_SetError("No audio context available"); + } + + 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..c3da6a025 --- /dev/null +++ b/src/audio/emscripten/SDL_emscriptenaudio.h @@ -0,0 +1,42 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..906728cb7 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/esd/SDL_esdaudio.h b/src/audio/esd/SDL_esdaudio.h index e0d5d4cdf..ad8159ee8 100644 --- a/src/audio/esd/SDL_esdaudio.h +++ b/src/audio/esd/SDL_esdaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index b8367715f..6bab5a786 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/fusionsound/SDL_fsaudio.h b/src/audio/fusionsound/SDL_fsaudio.h index 1f9d6bd27..aa2ae192b 100644 --- a/src/audio/fusionsound/SDL_fsaudio.h +++ b/src/audio/fusionsound/SDL_fsaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index dddb77922..c4765e370 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/haiku/SDL_haikuaudio.h b/src/audio/haiku/SDL_haikuaudio.h index c6c019e9c..21418618f 100644 --- a/src/audio/haiku/SDL_haikuaudio.h +++ b/src/audio/haiku/SDL_haikuaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index d9179f272..5c5b0bcf8 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/nacl/SDL_naclaudio.h b/src/audio/nacl/SDL_naclaudio.h index 4683c7850..c2636f0c2 100644 --- a/src/audio/nacl/SDL_naclaudio.h +++ b/src/audio/nacl/SDL_naclaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index a41a480f2..596ca7529 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/nas/SDL_nasaudio.h b/src/audio/nas/SDL_nasaudio.h index e1ee6a521..715f1fb2f 100644 --- a/src/audio/nas/SDL_nasaudio.h +++ b/src/audio/nas/SDL_nasaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index 032d8d2cd..79c71645c 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -111,7 +111,7 @@ OpenAudioPath(char *path, int maxlen, int flags, int classic) if (stat(audiopath, &sb) == 0) { fd = open(audiopath, flags, 0); - if (fd > 0) { + if (fd >= 0) { if (path != NULL) { SDL_strlcpy(path, audiopath, maxlen); } @@ -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/paudio/SDL_paudio.h b/src/audio/paudio/SDL_paudio.h index 5a1a64884..2bcb706cb 100644 --- a/src/audio/paudio/SDL_paudio.h +++ b/src/audio/paudio/SDL_paudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 5b1705926..60b7993ac 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..c63327444 100644 --- a/src/audio/psp/SDL_pspaudio.h +++ b/src/audio/psp/SDL_pspaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..30ca984e2 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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,39 +216,120 @@ load_pulseaudio_syms(void) return 0; } +static SDL_INLINE int +squashVersion(const int major, const int minor, const int patch) +{ + return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF); +} -/* Check to see if we can connect to PulseAudio */ -static SDL_bool -CheckPulseAudioAvailable() +/* Workaround for older pulse: pa_context_new() must have non-NULL appname */ +static const char * +getAppName(void) { - pa_simple *s; - pa_sample_spec ss; + const char *verstr = PULSEAUDIO_pa_get_library_version(); + if (verstr != NULL) { + int maj, min, patch; + if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) { + if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) { + return NULL; /* 0.9.15+ handles NULL correctly. */ + } + } + } + return "SDL Application"; /* oh well. */ +} - ss.format = PA_SAMPLE_S16NE; - ss.channels = 1; - ss.rate = 22050; +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); + } +} - 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; +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 +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(1) { + 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) { - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); return; } if (PULSEAUDIO_pa_stream_writable_size(h->stream) >= h->mixlen) { @@ -252,9 +343,10 @@ 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; + if (this->enabled) { + if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + } } } @@ -267,24 +359,21 @@ stream_drain_complete(pa_stream *s, int success, void *userdata) 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; + 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); } } - - PULSEAUDIO_pa_operation_unref(o); } @@ -301,51 +390,41 @@ PULSEAUDIO_CloseDevice(_THIS) { if (this->hidden != NULL) { SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; + SDL_free(this->hidden->device_name); 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; } + DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); SDL_free(this->hidden); this->hidden = NULL; } } - -static SDL_INLINE int -squashVersion(const int major, const int minor, const int patch) +static void +DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) { - return ((major & 0xFF) << 16) | ((minor & 0xFF) << 8) | (patch & 0xFF); + if (i) { + char **devname = (char **) data; + *devname = SDL_strdup(i->name); + } } -/* Workaround for older pulse: pa_context_new() must have non-NULL appname */ -static const char * -getAppName(void) +static SDL_bool +FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) { - const char *verstr = PULSEAUDIO_pa_get_library_version(); - if (verstr != NULL) { - int maj, min, patch; - if (SDL_sscanf(verstr, "%d.%d.%d", &maj, &min, &patch) == 3) { - if (squashVersion(maj, min, patch) >= squashVersion(0, 9, 15)) { - return NULL; /* 0.9.15+ handles NULL correctly. */ - } - } + const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; + + if (handle == NULL) { /* NULL == default device. */ + return SDL_TRUE; } - return "SDL Application"; /* oh well. */ + + 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, const char *devname, int iscapture) +PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { struct SDL_PrivateAudioData *h = NULL; Uint16 test_format = 0; @@ -442,41 +521,20 @@ PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) paattr.minreq = h->mixlen; #endif - /* 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) { + if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) { PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_context_new() failed"); + return SDL_SetError("Could not connect to PulseAudio server"); } - /* Connect to the PulseAudio server */ - if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) { + if (!FindDeviceName(h, handle)) { PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not setup connection to PulseAudio"); + return SDL_SetError("Requested PulseAudio sink missing?"); } - 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); + /* 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); h->stream = PULSEAUDIO_pa_stream_new( h->context, @@ -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..995c53c60 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.h +++ b/src/audio/pulseaudio/SDL_pulseaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..784466ca3 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/qsa/SDL_qsa_audio.h b/src/audio/qsa/SDL_qsa_audio.h index 66650d2a3..363feb47c 100644 --- a/src/audio/qsa/SDL_qsa_audio.h +++ b/src/audio/qsa/SDL_qsa_audio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/sdlgenaudiocvt.pl b/src/audio/sdlgenaudiocvt.pl index d4c2c502e..b012df801 100755 --- a/src/audio/sdlgenaudiocvt.pl +++ b/src/audio/sdlgenaudiocvt.pl @@ -38,7 +38,7 @@ sub outputHeader { /* DO NOT EDIT! This file is generated by sdlgenaudiocvt.pl */ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index 5c0636500..ba4fc4fa8 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/sndio/SDL_sndioaudio.h b/src/audio/sndio/SDL_sndioaudio.h index b8dadb7db..6956674be 100644 --- a/src/audio/sndio/SDL_sndioaudio.h +++ b/src/audio/sndio/SDL_sndioaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index 7efe30ece..9cdefbdb5 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/sun/SDL_sunaudio.h b/src/audio/sun/SDL_sunaudio.h index df05e6fca..02ac6cbd9 100644 --- a/src/audio/sun/SDL_sunaudio.h +++ b/src/audio/sun/SDL_sunaudio.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index 88a8154ec..37debb90c 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/winmm/SDL_winmm.h b/src/audio/winmm/SDL_winmm.h index 47996c1aa..a0dec0104 100644 --- a/src/audio/winmm/SDL_winmm.h +++ b/src/audio/winmm/SDL_winmm.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c index 85ac14602..9d6858337 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -65,6 +65,11 @@ The XAudio2 implementation available in the Windows 8 SDK targets Windows 8 and newer. If you want to build SDL with XAudio2 support you should install the DirectX SDK. */ +/* Disable compiling in the XAudio2 support pending fixes to dynamically load the XAudio2 + entry points so we can be robust to user configuration. Also needs to be fixed to build + with the Windows 10 SDK. +*/ +#if 0 /* See comment above */ #include #if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284)) # pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.") @@ -72,6 +77,7 @@ # define SDL_XAUDIO2_HAS_SDK 1 #endif #endif +#endif /* 0 */ #ifdef SDL_XAUDIO2_HAS_SDK @@ -126,16 +132,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 +152,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 +172,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 +224,7 @@ XAUDIO2_PlayDevice(_THIS) if (result != S_OK) { /* uhoh, panic! */ IXAudio2SourceVoice_FlushSourceBuffers(source); - this->enabled = 0; + SDL_OpenedAudioDeviceDisconnected(this); } } @@ -289,7 +292,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 +318,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 +343,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 +509,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/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp index 69eb5ad12..e4fb8e84d 100644 --- a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp +++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h index 3db04cf96..6f14f17ae 100644 --- a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h +++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 24442fd22..cac0872c8 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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) { @@ -141,12 +141,22 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!"); } +/* Drop file */ +void Java_org_libsdl_app_SDLActivity_onNativeDropFile( + JNIEnv* env, jclass jcls, + jstring filename) +{ + const char *path = (*env)->GetStringUTFChars(env, filename, NULL); + SDL_SendDropFile(path); + (*env)->ReleaseStringUTFChars(env, filename, path); +} + /* 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 +304,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 +320,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 +404,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); @@ -442,7 +460,7 @@ static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) } } -static SDL_bool LocalReferenceHolder_IsActive() +static SDL_bool LocalReferenceHolder_IsActive(void) { return s_active > 0; } @@ -460,7 +478,7 @@ ANativeWindow* Android_JNI_GetNativeWindow(void) return anw; } -void Android_JNI_SwapWindow() +void Android_JNI_SwapWindow(void) { JNIEnv *mEnv = Android_JNI_GetEnv(); (*mEnv)->CallStaticVoidMethod(mEnv, mActivityClass, midFlipBuffers); @@ -487,7 +505,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 +567,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(); @@ -612,12 +630,12 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i return audioBufferFrames; } -void * Android_JNI_GetAudioBuffer() +void * Android_JNI_GetAudioBuffer(void) { return audioBufferPinned; } -void Android_JNI_WriteAudioBuffer() +void Android_JNI_WriteAudioBuffer(void) { JNIEnv *mAudioEnv = Android_JNI_GetEnv(); @@ -632,7 +650,7 @@ void Android_JNI_WriteAudioBuffer() /* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */ } -void Android_JNI_CloseAudioDevice() +void Android_JNI_CloseAudioDevice(void) { JNIEnv *env = Android_JNI_GetEnv(); @@ -647,7 +665,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 +699,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 +746,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 +772,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 +784,13 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) 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 +808,7 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) 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 +819,7 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) "(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 +832,7 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) ctx->hidden.androidio.readMethod = mid; } - if (false) { + if (0) { failure: result = -1; @@ -907,7 +925,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 +950,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 +973,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 +986,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 +1077,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 +1089,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 */ @@ -1134,7 +1152,7 @@ int Android_JNI_SetClipboardText(const char* text) return 0; } -char* Android_JNI_GetClipboardText() +char* Android_JNI_GetClipboardText(void) { SETUP_CLIPBOARD(SDL_strdup("")) @@ -1160,7 +1178,7 @@ char* Android_JNI_GetClipboardText() return SDL_strdup(""); } -SDL_bool Android_JNI_HasClipboardText() +SDL_bool Android_JNI_HasClipboardText(void) { SETUP_CLIPBOARD(SDL_FALSE) @@ -1296,7 +1314,7 @@ int Android_JNI_GetTouchDeviceIds(int **ids) { return number; } -void Android_JNI_PollInputDevices() +void Android_JNI_PollInputDevices(void) { JNIEnv *env = Android_JNI_GetEnv(); (*env)->CallStaticVoidMethod(env, mActivityClass, midPollInputDevices); @@ -1343,7 +1361,7 @@ void Android_JNI_ShowTextInput(SDL_Rect *inputRect) inputRect->h ); } -void Android_JNI_HideTextInput() +void Android_JNI_HideTextInput(void) { /* has to match Activity constant */ const int COMMAND_TEXTEDIT_HIDE = 3; @@ -1353,6 +1371,7 @@ void Android_JNI_HideTextInput() int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) { JNIEnv *env; + jclass clazz; jmethodID mid; jobject context; jstring title; @@ -1361,6 +1380,7 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu jintArray button_ids; jobjectArray button_texts; jintArray colors; + jobject text; jint temp; int i; @@ -1368,19 +1388,23 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu /* convert parameters */ + clazz = (*env)->FindClass(env, "java/lang/String"); + title = (*env)->NewStringUTF(env, messageboxdata->title); message = (*env)->NewStringUTF(env, messageboxdata->message); button_flags = (*env)->NewIntArray(env, messageboxdata->numbuttons); button_ids = (*env)->NewIntArray(env, messageboxdata->numbuttons); button_texts = (*env)->NewObjectArray(env, messageboxdata->numbuttons, - (*env)->FindClass(env, "java/lang/String"), NULL); + clazz, NULL); for (i = 0; i < messageboxdata->numbuttons; ++i) { temp = messageboxdata->buttons[i].flags; (*env)->SetIntArrayRegion(env, button_flags, i, 1, &temp); temp = messageboxdata->buttons[i].buttonid; (*env)->SetIntArrayRegion(env, button_ids, i, 1, &temp); - (*env)->SetObjectArrayElement(env, button_texts, i, (*env)->NewStringUTF(env, messageboxdata->buttons[i].text)); + text = (*env)->NewStringUTF(env, messageboxdata->buttons[i].text); + (*env)->SetObjectArrayElement(env, button_texts, i, text); + (*env)->DeleteLocalRef(env, text); } if (messageboxdata->colorScheme) { @@ -1396,13 +1420,17 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu colors = NULL; } + (*env)->DeleteLocalRef(env, clazz); + /* call function */ mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext","()Landroid/content/Context;"); context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid); - mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context), + clazz = (*env)->GetObjectClass(env, context); + + mid = (*env)->GetMethodID(env, clazz, "messageboxShowMessageBox", "(ILjava/lang/String;Ljava/lang/String;[I[I[Ljava/lang/String;[I)I"); *buttonid = (*env)->CallIntMethod(env, context, mid, messageboxdata->flags, @@ -1413,16 +1441,15 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu button_texts, colors); + (*env)->DeleteLocalRef(env, context); + (*env)->DeleteLocalRef(env, clazz); + /* delete parameters */ (*env)->DeleteLocalRef(env, title); (*env)->DeleteLocalRef(env, message); (*env)->DeleteLocalRef(env, button_flags); (*env)->DeleteLocalRef(env, button_ids); - for (i = 0; i < messageboxdata->numbuttons; ++i) { - (*env)->DeleteLocalRef(env, (*env)->GetObjectArrayElement(env, button_texts, i)); - (*env)->SetObjectArrayElement(env, button_texts, i, NULL); - } (*env)->DeleteLocalRef(env, button_texts); (*env)->DeleteLocalRef(env, colors); @@ -1593,6 +1620,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..378fa0582 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -35,18 +35,18 @@ extern "C" { /* Interface from the SDL library into the Android Java activity */ /* extern SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion, int red, int green, int blue, int alpha, int buffer, int depth, int stencil, int buffers, int samples); extern SDL_bool Android_JNI_DeleteContext(void); */ -extern void Android_JNI_SwapWindow(); +extern void Android_JNI_SwapWindow(void); extern void Android_JNI_SetActivityTitle(const char *title); extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]); extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect); -extern void Android_JNI_HideTextInput(); +extern void Android_JNI_HideTextInput(void); extern ANativeWindow* Android_JNI_GetNativeWindow(void); /* Audio support */ extern int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames); -extern void* Android_JNI_GetAudioBuffer(); -extern void Android_JNI_WriteAudioBuffer(); -extern void Android_JNI_CloseAudioDevice(); +extern void* Android_JNI_GetAudioBuffer(void); +extern void Android_JNI_WriteAudioBuffer(void); +extern void Android_JNI_CloseAudioDevice(void); #include "SDL_rwops.h" @@ -59,14 +59,14 @@ int Android_JNI_FileClose(SDL_RWops* ctx); /* Clipboard support */ int Android_JNI_SetClipboardText(const char* text); -char* Android_JNI_GetClipboardText(); -SDL_bool Android_JNI_HasClipboardText(); +char* Android_JNI_GetClipboardText(void); +SDL_bool Android_JNI_HasClipboardText(void); /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); /* Joystick support */ -void Android_JNI_PollInputDevices(); +void Android_JNI_PollInputDevices(void); /* Video */ void Android_JNI_SuspendScreenSaver(SDL_bool suspend); @@ -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_dbus.c b/src/core/linux/SDL_dbus.c index d9dbd9613..cc7b3d374 100644 --- a/src/core/linux/SDL_dbus.c +++ b/src/core/linux/SDL_dbus.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -30,7 +30,7 @@ static unsigned int screensaver_cookie = 0; static SDL_DBusContext dbus = {0}; static int -load_dbus_syms(void) +LoadDBUSSyms(void) { #define SDL_DBUS_SYM2(x, y) \ if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1 @@ -45,6 +45,7 @@ load_dbus_syms(void) SDL_DBUS_SYM(connection_set_exit_on_disconnect); SDL_DBUS_SYM(connection_get_is_connected); SDL_DBUS_SYM(connection_add_filter); + SDL_DBUS_SYM(connection_try_register_object_path); SDL_DBUS_SYM(connection_send); SDL_DBUS_SYM(connection_send_with_reply_and_block); SDL_DBUS_SYM(connection_close); @@ -94,7 +95,7 @@ LoadDBUSLibrary(void) retval = -1; /* Don't call SDL_SetError(): SDL_LoadObject already did. */ } else { - retval = load_dbus_syms(); + retval = LoadDBUSSyms(); if (retval < 0) { UnloadDBUSLibrary(); } diff --git a/src/core/linux/SDL_dbus.h b/src/core/linux/SDL_dbus.h index 0fbb21422..dcfec77ef 100644 --- a/src/core/linux/SDL_dbus.h +++ b/src/core/linux/SDL_dbus.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -41,6 +41,8 @@ typedef struct SDL_DBusContext { dbus_bool_t (*connection_get_is_connected)(DBusConnection *); dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction, void *, DBusFreeFunction); + dbus_bool_t (*connection_try_register_object_path)(DBusConnection *, const char *, + const DBusObjectPathVTable *, void *, DBusError *); dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *); DBusMessage *(*connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *); void (*connection_close)(DBusConnection *); diff --git a/src/core/linux/SDL_evdev.c b/src/core/linux/SDL_evdev.c index c4a7d05ce..b9246745d 100644 --- a/src/core/linux/SDL_evdev.c +++ b/src/core/linux/SDL_evdev.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -341,7 +341,7 @@ static Uint8 EVDEV_MouseButtons[] = { SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */ }; -static char* EVDEV_consoles[] = { +static const char* EVDEV_consoles[] = { "/proc/self/fd/0", "/dev/tty", "/dev/tty0", @@ -364,7 +364,7 @@ static int SDL_EVDEV_get_console_fd(void) /* Try a few consoles to see which one we have read access to */ - for( i = 0; i < SDL_arraysize(EVDEV_consoles); i++) { + for(i = 0; i < SDL_arraysize(EVDEV_consoles); i++) { fd = open(EVDEV_consoles[i], O_RDONLY); if (fd >= 0) { if (IS_CONSOLE(fd)) return fd; @@ -374,7 +374,7 @@ static int SDL_EVDEV_get_console_fd(void) /* Try stdin, stdout, stderr */ - for( fd = 0; fd < 3; fd++) { + for(fd = 0; fd < 3; fd++) { if (IS_CONSOLE(fd)) return fd; } @@ -468,7 +468,7 @@ SDL_EVDEV_Init(void) } /* Set up the udev callback */ - if ( SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) { + if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) { SDL_EVDEV_Quit(); return -1; } @@ -547,12 +547,11 @@ void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, con return; } - if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) { - return; - } - - switch( udev_type ) { + switch(udev_type) { case SDL_UDEV_DEVICEADDED: + if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) { + return; + } SDL_EVDEV_device_added(devpath); break; @@ -615,7 +614,7 @@ SDL_EVDEV_Poll(void) if (scan_code != SDL_SCANCODE_UNKNOWN) { if (events[i].value == 0) { SDL_SendKeyboardKey(SDL_RELEASED, scan_code); - } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */ ) { + } else if (events[i].value == 1 || events[i].value == 2 /* Key repeated */) { SDL_SendKeyboardKey(SDL_PRESSED, scan_code); #ifdef SDL_INPUT_LINUXKD if (_this->console_fd >= 0) { @@ -626,12 +625,12 @@ SDL_EVDEV_Poll(void) kbe.kb_table = 0; /* Ref: http://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching */ - kbe.kb_table |= -( (modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL); - kbe.kb_table |= -( (modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL); - kbe.kb_table |= -( (modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT); - kbe.kb_table |= -( (modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT); - kbe.kb_table |= -( (modstate & KMOD_LALT) != 0) & (1 << KG_ALT); - kbe.kb_table |= -( (modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); + kbe.kb_table |= -((modstate & KMOD_LCTRL) != 0) & (1 << KG_CTRLL | 1 << KG_CTRL); + kbe.kb_table |= -((modstate & KMOD_RCTRL) != 0) & (1 << KG_CTRLR | 1 << KG_CTRL); + kbe.kb_table |= -((modstate & KMOD_LSHIFT) != 0) & (1 << KG_SHIFTL | 1 << KG_SHIFT); + kbe.kb_table |= -((modstate & KMOD_RSHIFT) != 0) & (1 << KG_SHIFTR | 1 << KG_SHIFT); + kbe.kb_table |= -((modstate & KMOD_LALT) != 0) & (1 << KG_ALT); + kbe.kb_table |= -((modstate & KMOD_RALT) != 0) & (1 << KG_ALTGR); if (ioctl(_this->console_fd, KDGKBENT, (unsigned long)&kbe) == 0 && ((KTYP(kbe.kb_value) == KT_LATIN) || (KTYP(kbe.kb_value) == KT_ASCII) || (KTYP(kbe.kb_value) == KT_LETTER))) @@ -642,8 +641,8 @@ SDL_EVDEV_Poll(void) * because 1 << KG_CAPSSHIFT overflows the 8 bits of kb_table * So, we do the CAPS LOCK logic here. Note that isalpha depends on the locale! */ - if ( modstate & KMOD_CAPS && isalpha(kval) ) { - if ( isupper(kval) ) { + if (modstate & KMOD_CAPS && isalpha(kval)) { + if (isupper(kval)) { kval = tolower(kval); } else { kval = toupper(kval); @@ -651,7 +650,7 @@ SDL_EVDEV_Poll(void) } /* Convert to UTF-8 and send */ - end = SDL_UCS4ToUTF8( kval, keysym); + end = SDL_UCS4ToUTF8(kval, keysym); *end = '\0'; SDL_SendKeyboardText(keysym); } @@ -681,10 +680,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; @@ -733,7 +732,7 @@ SDL_EVDEV_device_added(const char *devpath) /* Check to make sure it's not already in list. */ for (item = _this->first; item != NULL; item = item->next) { - if (strcmp(devpath, item->path) == 0) { + if (SDL_strcmp(devpath, item->path) == 0) { return -1; /* already have this one */ } } @@ -780,7 +779,7 @@ SDL_EVDEV_device_removed(const char *devpath) for (item = _this->first; item != NULL; item = item->next) { /* found it, remove it. */ - if ( strcmp(devpath, item->path) ==0 ) { + if (SDL_strcmp(devpath, item->path) == 0) { if (prev != NULL) { prev->next = item->next; } else { diff --git a/src/core/linux/SDL_evdev.h b/src/core/linux/SDL_evdev.h index f6398ea58..670a5cb26 100644 --- a/src/core/linux/SDL_evdev.h +++ b/src/core/linux/SDL_evdev.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index 1a0729f26..46d602af8 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -123,7 +123,7 @@ IBus_utf8_strlen(const char *str) } static DBusHandlerResult -IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data) +IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data) { SDL_DBusContext *dbus = (SDL_DBusContext *)user_data; @@ -156,12 +156,12 @@ IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data) dbus->message_iter_init(msg, &iter); text = IBus_GetVariantText(conn, &iter, dbus); - if (text && *text) { + if (text) { char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; size_t text_bytes = SDL_strlen(text), i = 0; size_t cursor = 0; - while (i < text_bytes) { + do { size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf)); size_t chars = IBus_utf8_strlen(buf); @@ -169,7 +169,7 @@ IBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *user_data) i += sz; cursor += chars; - } + } while (i < text_bytes); } SDL_IBus_UpdateTextRect(NULL); @@ -341,6 +341,8 @@ IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr) const char *path = NULL; SDL_bool result = SDL_FALSE; DBusMessage *msg; + DBusObjectPathVTable ibus_vtable = {0}; + ibus_vtable.message_function = &IBus_MessageHandler; ibus_conn = dbus->connection_open_private(addr, NULL); @@ -388,7 +390,7 @@ IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr) SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &IBus_SetCapabilities, NULL); dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL); - dbus->connection_add_filter(ibus_conn, &IBus_MessageFilter, dbus, NULL); + dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL); dbus->connection_flush(ibus_conn); } @@ -459,9 +461,14 @@ SDL_IBus_Init(void) return SDL_FALSE; } + /* !!! FIXME: if ibus_addr_file != NULL, this will overwrite it and leak (twice!) */ ibus_addr_file = SDL_strdup(addr_file); addr = IBus_ReadAddressFromFile(addr_file); + if (!addr) { + SDL_free(addr_file); + return SDL_FALSE; + } if (inotify_fd < 0) { inotify_fd = inotify_init(); @@ -476,8 +483,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; @@ -663,7 +672,7 @@ SDL_IBus_PumpEvents(void) dbus->connection_read_write(ibus_conn, 0); while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) { - /* Do nothing, actual work happens in IBus_MessageFilter */ + /* Do nothing, actual work happens in IBus_MessageHandler */ } } } diff --git a/src/core/linux/SDL_ibus.h b/src/core/linux/SDL_ibus.h index d982e6846..247652231 100644 --- a/src/core/linux/SDL_ibus.h +++ b/src/core/linux/SDL_ibus.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c index 585018381..cf66331e7 100644 --- a/src/core/linux/SDL_udev.c +++ b/src/core/linux/SDL_udev.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -33,7 +33,7 @@ #include "SDL.h" -static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" }; +static const char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" }; #define _THIS SDL_UDEV_PrivateData *_this static _THIS = NULL; @@ -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; @@ -467,6 +469,9 @@ SDL_UDEV_Poll(void) action = _this->udev_device_get_action(dev); if (SDL_strcmp(action, "add") == 0) { + /* Wait for the device to finish initialization */ + SDL_Delay(100); + device_event(SDL_UDEV_DEVICEADDED, dev); } else if (SDL_strcmp(action, "remove") == 0) { device_event(SDL_UDEV_DEVICEREMOVED, dev); diff --git a/src/core/linux/SDL_udev.h b/src/core/linux/SDL_udev.h index 5ec86de2a..9242870c4 100644 --- a/src/core/linux/SDL_udev.h +++ b/src/core/linux/SDL_udev.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/windows/SDL_directx.h b/src/core/windows/SDL_directx.h index f37bccef2..106926438 100644 --- a/src/core/windows/SDL_directx.h +++ b/src/core/windows/SDL_directx.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index 1e5d0ff49..aff6e6d28 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -124,6 +124,6 @@ BOOL WIN_IsWindowsVistaOrGreater() #endif } -#endif /* __WIN32__ */ +#endif /* __WIN32__ || __WINRT__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index bb563ccd0..863971b61 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/windows/SDL_xinput.c b/src/core/windows/SDL_xinput.c index 9dcac3644..49d4ecbeb 100644 --- a/src/core/windows/SDL_xinput.c +++ b/src/core/windows/SDL_xinput.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/windows/SDL_xinput.h b/src/core/windows/SDL_xinput.h index 721c3811b..5c5773763 100644 --- a/src/core/windows/SDL_xinput.h +++ b/src/core/windows/SDL_xinput.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/winrt/SDL_winrtapp_common.cpp b/src/core/winrt/SDL_winrtapp_common.cpp index 0758ad922..c8ac48133 100644 --- a/src/core/winrt/SDL_winrtapp_common.cpp +++ b/src/core/winrt/SDL_winrtapp_common.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/winrt/SDL_winrtapp_common.h b/src/core/winrt/SDL_winrtapp_common.h index e49e615e8..e905139c0 100644 --- a/src/core/winrt/SDL_winrtapp_common.h +++ b/src/core/winrt/SDL_winrtapp_common.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index fc5909aae..267ce4eda 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; @@ -365,6 +375,9 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window) window->KeyUp += ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyUp); + window->CharacterReceived += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnCharacterReceived); + #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP HardwareButtons::BackPressed += ref new EventHandler(this, &SDL_WinRTApp::OnBackButtonPressed); @@ -703,6 +716,11 @@ void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::C WINRT_ProcessKeyUpEvent(args); } +void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args) +{ + WINRT_ProcessCharacterReceivedEvent(args); +} + #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args) { diff --git a/src/core/winrt/SDL_winrtapp_direct3d.h b/src/core/winrt/SDL_winrtapp_direct3d.h index 714d41c7e..6a8838ec8 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.h +++ b/src/core/winrt/SDL_winrtapp_direct3d.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -69,6 +69,7 @@ ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFramewo void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args); void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); + void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args); #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args); diff --git a/src/core/winrt/SDL_winrtapp_xaml.cpp b/src/core/winrt/SDL_winrtapp_xaml.cpp index 38694e11e..9f943309c 100644 --- a/src/core/winrt/SDL_winrtapp_xaml.cpp +++ b/src/core/winrt/SDL_winrtapp_xaml.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/core/winrt/SDL_winrtapp_xaml.h b/src/core/winrt/SDL_winrtapp_xaml.h index 2296475b0..7537710e3 100644 --- a/src/core/winrt/SDL_winrtapp_xaml.h +++ b/src/core/winrt/SDL_winrtapp_xaml.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..ed839cccb 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 @@ CPU_haveCPUID(void) "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..02e5c787b 100644 --- a/src/dynapi/SDL_dynapi.c +++ b/src/dynapi/SDL_dynapi.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..fa9a0c7f9 100644 --- a/src/dynapi/SDL_dynapi.h +++ b/src/dynapi/SDL_dynapi.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..3ae3ed89e 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -505,6 +505,7 @@ #define SDL_GetNumVideoDisplays SDL_GetNumVideoDisplays_REAL #define SDL_GetDisplayName SDL_GetDisplayName_REAL #define SDL_GetDisplayBounds SDL_GetDisplayBounds_REAL +#define SDL_GetDisplayDPI SDL_GetDisplayDPI_REAL #define SDL_GetNumDisplayModes SDL_GetNumDisplayModes_REAL #define SDL_GetDisplayMode SDL_GetDisplayMode_REAL #define SDL_GetDesktopDisplayMode SDL_GetDesktopDisplayMode_REAL @@ -591,3 +592,5 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL +#define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index c41cdc9f0..d085fe5e1 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -612,7 +612,7 @@ SDL_DYNAPI_PROC(int,SDL_WinRTRunApp,(int a, char **b, void *c),(a,b,c),return) SDL_DYNAPI_PROC(const wchar_t*,SDL_WinRTGetFSPathUNICODE,(SDL_WinRT_Path a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_WinRTGetFSPathUTF8,(SDL_WinRT_Path a),(a),return) #endif -SDL_DYNAPI_PROC(void,SDL_WarpMouseGlobal,(int a, int b),(a,b),) +SDL_DYNAPI_PROC(int,SDL_WarpMouseGlobal,(int a, int b),(a,b),return) SDL_DYNAPI_PROC(float,SDL_sqrtf,(float a),(a),return) SDL_DYNAPI_PROC(double,SDL_tan,(double a),(a),return) SDL_DYNAPI_PROC(float,SDL_tanf,(float a),(a),return) @@ -623,3 +623,8 @@ 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) +#ifdef __WIN32__ +SDL_DYNAPI_PROC(void,SDL_SetWindowsMessageHook,(SDL_WindowsMessageHook a, void *b),(a,b),) +#endif +SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b,c,d),return) diff --git a/src/dynapi/gendynapi.pl b/src/dynapi/gendynapi.pl index 091a08c7a..192889fd8 100755 --- a/src/dynapi/gendynapi.pl +++ b/src/dynapi/gendynapi.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -w # Simple DirectMedia Layer -# Copyright (C) 1997-2014 Sam Lantinga +# Copyright (C) 1997-2015 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/src/events/SDL_clipboardevents.c b/src/events/SDL_clipboardevents.c index 3ef7bed26..5df8aa1c0 100644 --- a/src/events/SDL_clipboardevents.c +++ b/src/events/SDL_clipboardevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_clipboardevents_c.h b/src/events/SDL_clipboardevents_c.h index c71da2a47..6c58ee431 100644 --- a/src/events/SDL_clipboardevents_c.h +++ b/src/events/SDL_clipboardevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_dropevents.c b/src/events/SDL_dropevents.c index 4830d14f8..0c8c7bea0 100644 --- a/src/events/SDL_dropevents.c +++ b/src/events/SDL_dropevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_dropevents_c.h b/src/events/SDL_dropevents_c.h index cb5e1dc57..3e8615e84 100644 --- a/src/events/SDL_dropevents_c.h +++ b/src/events/SDL_dropevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_events.c b/src/events/SDL_events.c index 963b9bd7c..4f5bb2d9a 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; } @@ -393,6 +406,8 @@ SDL_PumpEvents(void) SDL_JoystickUpdate(); } #endif + + SDL_SendPendingQuit(); /* in case we had a signal handler fire, etc. */ } /* Public functions */ diff --git a/src/events/SDL_events_c.h b/src/events/SDL_events_c.h index 11d6e304d..ebd983d36 100644 --- a/src/events/SDL_events_c.h +++ b/src/events/SDL_events_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -43,6 +43,8 @@ extern int SDL_QuitInit(void); extern int SDL_SendQuit(void); extern void SDL_QuitQuit(void); +extern void SDL_SendPendingQuit(void); + /* The event filter function */ extern SDL_EventFilter SDL_EventOK; extern void *SDL_EventOKParam; diff --git a/src/events/SDL_gesture.c b/src/events/SDL_gesture.c index 46a554635..b7980ede6 100644 --- a/src/events/SDL_gesture.c +++ b/src/events/SDL_gesture.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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"); */ @@ -612,8 +649,7 @@ void SDL_GestureProcessEvent(SDL_Event* event) break; pressure? */ } - - if (event->type == SDL_FINGERDOWN) { + else if (event->type == SDL_FINGERDOWN) { inTouch->numDownFingers++; inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ diff --git a/src/events/SDL_gesture_c.h b/src/events/SDL_gesture_c.h index 3f1ed9b15..f94dc715e 100644 --- a/src/events/SDL_gesture_c.h +++ b/src/events/SDL_gesture_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index ed4043e9c..d4dc0e7bc 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -662,6 +662,8 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) { SDL_Keyboard *keyboard = &SDL_keyboard; int posted; + SDL_Keymod modifier; + SDL_Keycode keycode; Uint16 modstate; Uint32 type; Uint8 repeat; @@ -673,82 +675,6 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode), state == SDL_PRESSED ? "pressed" : "released"); #endif - if (state == SDL_PRESSED) { - modstate = keyboard->modstate; - switch (scancode) { - case SDL_SCANCODE_NUMLOCKCLEAR: - keyboard->modstate ^= KMOD_NUM; - break; - case SDL_SCANCODE_CAPSLOCK: - keyboard->modstate ^= KMOD_CAPS; - break; - case SDL_SCANCODE_LCTRL: - keyboard->modstate |= KMOD_LCTRL; - break; - case SDL_SCANCODE_RCTRL: - keyboard->modstate |= KMOD_RCTRL; - break; - case SDL_SCANCODE_LSHIFT: - keyboard->modstate |= KMOD_LSHIFT; - break; - case SDL_SCANCODE_RSHIFT: - keyboard->modstate |= KMOD_RSHIFT; - break; - case SDL_SCANCODE_LALT: - keyboard->modstate |= KMOD_LALT; - break; - case SDL_SCANCODE_RALT: - keyboard->modstate |= KMOD_RALT; - break; - case SDL_SCANCODE_LGUI: - keyboard->modstate |= KMOD_LGUI; - break; - case SDL_SCANCODE_RGUI: - keyboard->modstate |= KMOD_RGUI; - break; - case SDL_SCANCODE_MODE: - keyboard->modstate |= KMOD_MODE; - break; - default: - break; - } - } else { - switch (scancode) { - case SDL_SCANCODE_NUMLOCKCLEAR: - case SDL_SCANCODE_CAPSLOCK: - break; - case SDL_SCANCODE_LCTRL: - keyboard->modstate &= ~KMOD_LCTRL; - break; - case SDL_SCANCODE_RCTRL: - keyboard->modstate &= ~KMOD_RCTRL; - break; - case SDL_SCANCODE_LSHIFT: - keyboard->modstate &= ~KMOD_LSHIFT; - break; - case SDL_SCANCODE_RSHIFT: - keyboard->modstate &= ~KMOD_RSHIFT; - break; - case SDL_SCANCODE_LALT: - keyboard->modstate &= ~KMOD_LALT; - break; - case SDL_SCANCODE_RALT: - keyboard->modstate &= ~KMOD_RALT; - break; - case SDL_SCANCODE_LGUI: - keyboard->modstate &= ~KMOD_LGUI; - break; - case SDL_SCANCODE_RGUI: - keyboard->modstate &= ~KMOD_RGUI; - break; - case SDL_SCANCODE_MODE: - keyboard->modstate &= ~KMOD_MODE; - break; - default: - break; - } - modstate = keyboard->modstate; - } /* Figure out what type of event this is */ switch (state) { @@ -775,6 +701,59 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) /* Update internal keyboard state */ keyboard->keystate[scancode] = state; + keycode = keyboard->keymap[scancode]; + + /* Update modifiers state if applicable */ + switch (keycode) { + case SDLK_LCTRL: + modifier = KMOD_LCTRL; + break; + case SDLK_RCTRL: + modifier = KMOD_RCTRL; + break; + case SDLK_LSHIFT: + modifier = KMOD_LSHIFT; + break; + case SDLK_RSHIFT: + modifier = KMOD_RSHIFT; + break; + case SDLK_LALT: + modifier = KMOD_LALT; + break; + case SDLK_RALT: + modifier = KMOD_RALT; + break; + case SDLK_LGUI: + modifier = KMOD_LGUI; + break; + case SDLK_RGUI: + modifier = KMOD_RGUI; + break; + case SDLK_MODE: + modifier = KMOD_MODE; + break; + default: + modifier = KMOD_NONE; + break; + } + if (SDL_KEYDOWN == type) { + modstate = keyboard->modstate; + switch (keycode) { + case SDLK_NUMLOCKCLEAR: + keyboard->modstate ^= KMOD_NUM; + break; + case SDLK_CAPSLOCK: + keyboard->modstate ^= KMOD_CAPS; + break; + default: + keyboard->modstate |= modifier; + break; + } + } else { + keyboard->modstate &= ~modifier; + modstate = keyboard->modstate; + } + /* Post the event, if desired */ posted = 0; if (SDL_GetEventState(type) == SDL_ENABLE) { @@ -783,7 +762,7 @@ SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) event.key.state = state; event.key.repeat = repeat; event.key.keysym.scancode = scancode; - event.key.keysym.sym = keyboard->keymap[scancode]; + event.key.keysym.sym = keycode; event.key.keysym.mod = modstate; event.key.windowID = keyboard->focus ? keyboard->focus->id : 0; posted = (SDL_PushEvent(&event) > 0); diff --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h index 05b525382..50fb06da7 100644 --- a/src/events/SDL_keyboard_c.h +++ b/src/events/SDL_keyboard_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 21fb87771..716384a10 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; @@ -528,14 +535,16 @@ SDL_WarpMouseInWindow(SDL_Window * window, int x, int y) } } -void +int SDL_WarpMouseGlobal(int x, int y) { SDL_Mouse *mouse = SDL_GetMouse(); if (mouse->WarpMouseGlobal) { - mouse->WarpMouseGlobal(x, y); + return mouse->WarpMouseGlobal(x, y); } + + return SDL_Unsupported(); } static SDL_bool diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index df95e1e52..b12bec351 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -61,7 +61,7 @@ typedef struct void (*WarpMouse) (SDL_Window * window, int x, int y); /* Warp the mouse to (x,y) in screen space */ - void (*WarpMouseGlobal) (int x, int y); + int (*WarpMouseGlobal) (int x, int y); /* Set relative mode */ int (*SetRelativeMouseMode) (SDL_bool enabled); @@ -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..d2b215bc4 100644 --- a/src/events/SDL_quit.c +++ b/src/events/SDL_quit.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -19,6 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../SDL_internal.h" +#include "SDL_hints.h" +#include "SDL_assert.h" /* General quit handling code for SDL */ @@ -29,6 +31,8 @@ #include "SDL_events.h" #include "SDL_events_c.h" +static SDL_bool disable_signals = SDL_FALSE; +static SDL_bool send_quit_pending = SDL_FALSE; #ifdef HAVE_SIGNAL_H static void @@ -37,14 +41,15 @@ SDL_HandleSIG(int sig) /* Reset the signal handler */ signal(sig, SDL_HandleSIG); - /* Signal a quit interrupt */ - SDL_SendQuit(); + /* Send a quit event next time the event loop pumps. */ + /* We can't send it in signal handler; malloc() might be interrupted! */ + send_quit_pending = SDL_TRUE; } #endif /* HAVE_SIGNAL_H */ /* Public functions */ -int -SDL_QuitInit(void) +static int +SDL_QuitInit_Internal(void) { #ifdef HAVE_SIGACTION struct sigaction action; @@ -80,11 +85,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,11 +126,29 @@ 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) { + send_quit_pending = SDL_FALSE; return SDL_SendAppEvent(SDL_QUIT); } +void +SDL_SendPendingQuit(void) +{ + if (send_quit_pending) { + SDL_SendQuit(); + SDL_assert(!send_quit_pending); + } +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/events/SDL_sysevents.h b/src/events/SDL_sysevents.h index a5be7bc31..f1d460d8b 100644 --- a/src/events/SDL_sysevents.h +++ b/src/events/SDL_sysevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_touch.c b/src/events/SDL_touch.c index 14a337a9a..1b477ea7d 100644 --- a/src/events/SDL_touch.c +++ b/src/events/SDL_touch.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -145,13 +145,16 @@ SDL_AddTouch(SDL_TouchID touchID, const char *name) } SDL_touchDevices = touchDevices; - index = SDL_num_touch++; + index = SDL_num_touch; SDL_touchDevices[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchDevices[index])); if (!SDL_touchDevices[index]) { return SDL_OutOfMemory(); } + /* Added touch to list */ + ++SDL_num_touch; + /* we're setting the touch properties */ SDL_touchDevices[index]->id = touchID; SDL_touchDevices[index]->num_fingers = 0; diff --git a/src/events/SDL_touch_c.h b/src/events/SDL_touch_c.h index f9781789c..3e4b8bbfa 100644 --- a/src/events/SDL_touch_c.h +++ b/src/events/SDL_touch_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_windowevents.c b/src/events/SDL_windowevents.c index 146cbc540..0e480f276 100644 --- a/src/events/SDL_windowevents.c +++ b/src/events/SDL_windowevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/SDL_windowevents_c.h b/src/events/SDL_windowevents_c.h index 9ad34a342..140b38c3f 100644 --- a/src/events/SDL_windowevents_c.h +++ b/src/events/SDL_windowevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/blank_cursor.h b/src/events/blank_cursor.h index 423fa1386..175012936 100644 --- a/src/events/blank_cursor.h +++ b/src/events/blank_cursor.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/default_cursor.h b/src/events/default_cursor.h index 6e09380ef..e292cbf5a 100644 --- a/src/events/default_cursor.h +++ b/src/events/default_cursor.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -110,5 +110,5 @@ static const unsigned char default_cmask[] = { 0x03, 0x00 }; -#endif /* TRUE_MACINTOSH_CURSOR */ +#endif /* USE_MACOS_CURSOR */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/events/scancodes_darwin.h b/src/events/scancodes_darwin.h index 42fcbdfa2..5677a894a 100644 --- a/src/events/scancodes_darwin.h +++ b/src/events/scancodes_darwin.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/scancodes_linux.h b/src/events/scancodes_linux.h index dbf7a7a5b..532a2a984 100644 --- a/src/events/scancodes_linux.h +++ b/src/events/scancodes_linux.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/events/scancodes_windows.h b/src/events/scancodes_windows.h index fa894e481..f712d5a01 100644 --- a/src/events/scancodes_windows.h +++ b/src/events/scancodes_windows.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -49,7 +49,7 @@ static const SDL_Scancode windows_scancode_table[] = SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_F16, /* 6 */ SDL_SCANCODE_F17, SDL_SCANCODE_F18, SDL_SCANCODE_F19, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, /* 6 */ - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, /* 7 */ - SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN /* 7 */ + SDL_SCANCODE_INTERNATIONAL2, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_INTERNATIONAL1, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, /* 7 */ + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_INTERNATIONAL4, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_INTERNATIONAL5, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_INTERNATIONAL3, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN /* 7 */ }; /* *INDENT-ON* */ diff --git a/src/events/scancodes_xfree86.h b/src/events/scancodes_xfree86.h index 8b10c3d90..e61555259 100644 --- a/src/events/scancodes_xfree86.h +++ b/src/events/scancodes_xfree86.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -141,15 +141,15 @@ static const SDL_Scancode xfree86_scancode_table[] = { /* 112 */ SDL_SCANCODE_F15, /* 113 */ SDL_SCANCODE_F16, /* 114 */ SDL_SCANCODE_F17, - /* 115 */ SDL_SCANCODE_UNKNOWN, + /* 115 */ SDL_SCANCODE_INTERNATIONAL1, /* \_ */ /* 116 */ SDL_SCANCODE_UNKNOWN, /* is translated to XK_ISO_Level3_Shift by my X server, but I have no keyboard that generates this code, so I don't know what the correct SDL_SCANCODE_* for it is */ /* 117 */ SDL_SCANCODE_UNKNOWN, /* 118 */ SDL_SCANCODE_KP_EQUALS, /* 119 */ SDL_SCANCODE_UNKNOWN, /* 120 */ SDL_SCANCODE_UNKNOWN, - /* 121 */ SDL_SCANCODE_UNKNOWN, + /* 121 */ SDL_SCANCODE_INTERNATIONAL4, /* Henkan_Mode */ /* 122 */ SDL_SCANCODE_UNKNOWN, - /* 123 */ SDL_SCANCODE_UNKNOWN, + /* 123 */ SDL_SCANCODE_INTERNATIONAL5, /* Muhenkan */ /* 124 */ SDL_SCANCODE_UNKNOWN, /* 125 */ SDL_SCANCODE_INTERNATIONAL3, /* Yen */ /* 126 */ SDL_SCANCODE_UNKNOWN, @@ -266,12 +266,12 @@ static const SDL_Scancode xfree86_scancode_table2[] = { /* 86 */ SDL_SCANCODE_NONUSBACKSLASH, /* 87 */ SDL_SCANCODE_F11, /* 88 */ SDL_SCANCODE_F12, - /* 89 */ SDL_SCANCODE_UNKNOWN, + /* 89 */ SDL_SCANCODE_INTERNATIONAL1, /* \_ */ /* 90 */ SDL_SCANCODE_UNKNOWN, /* Katakana */ /* 91 */ SDL_SCANCODE_UNKNOWN, /* Hiragana */ - /* 92 */ SDL_SCANCODE_UNKNOWN, /* Henkan_Mode */ - /* 93 */ SDL_SCANCODE_UNKNOWN, /* Hiragana_Katakana */ - /* 94 */ SDL_SCANCODE_UNKNOWN, /* Muhenkan */ + /* 92 */ SDL_SCANCODE_INTERNATIONAL4, /* Henkan_Mode */ + /* 93 */ SDL_SCANCODE_INTERNATIONAL2, /* Hiragana_Katakana */ + /* 94 */ SDL_SCANCODE_INTERNATIONAL5, /* Muhenkan */ /* 95 */ SDL_SCANCODE_UNKNOWN, /* 96 */ SDL_SCANCODE_KP_ENTER, /* 97 */ SDL_SCANCODE_RCTRL, @@ -301,7 +301,7 @@ static const SDL_Scancode xfree86_scancode_table2[] = { /* 121 */ SDL_SCANCODE_UNKNOWN, /* KP_Decimal */ /* 122 */ SDL_SCANCODE_UNKNOWN, /* Hangul */ /* 123 */ SDL_SCANCODE_UNKNOWN, /* Hangul_Hanja */ - /* 124 */ SDL_SCANCODE_UNKNOWN, + /* 124 */ SDL_SCANCODE_INTERNATIONAL3, /* Yen */ /* 125 */ SDL_SCANCODE_LGUI, /* 126 */ SDL_SCANCODE_RGUI, /* 127 */ SDL_SCANCODE_APPLICATION, diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index 41f6c6d0c..b3b445d2d 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/file/cocoa/SDL_rwopsbundlesupport.h b/src/file/cocoa/SDL_rwopsbundlesupport.h index 9a8a9662c..387428f39 100644 --- a/src/file/cocoa/SDL_rwopsbundlesupport.h +++ b/src/file/cocoa/SDL_rwopsbundlesupport.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/file/cocoa/SDL_rwopsbundlesupport.m b/src/file/cocoa/SDL_rwopsbundlesupport.m index 1ae399c2d..1d665edb2 100644 --- a/src/file/cocoa/SDL_rwopsbundlesupport.m +++ b/src/file/cocoa/SDL_rwopsbundlesupport.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -50,14 +50,13 @@ 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/android/SDL_sysfilesystem.c b/src/filesystem/android/SDL_sysfilesystem.c index b3937449a..0401773e4 100644 --- a/src/filesystem/android/SDL_sysfilesystem.c +++ b/src/filesystem/android/SDL_sysfilesystem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/filesystem/cocoa/SDL_sysfilesystem.m b/src/filesystem/cocoa/SDL_sysfilesystem.m index dab51c501..1e6a20678 100644 --- a/src/filesystem/cocoa/SDL_sysfilesystem.m +++ b/src/filesystem/cocoa/SDL_sysfilesystem.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -41,6 +41,7 @@ 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 @@ /* 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 @@ 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/dummy/SDL_sysfilesystem.c b/src/filesystem/dummy/SDL_sysfilesystem.c index 7e860939a..2cb9e21e1 100644 --- a/src/filesystem/dummy/SDL_sysfilesystem.c +++ b/src/filesystem/dummy/SDL_sysfilesystem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/filesystem/emscripten/SDL_sysfilesystem.c b/src/filesystem/emscripten/SDL_sysfilesystem.c new file mode 100644 index 000000000..e9ded6754 --- /dev/null +++ b/src/filesystem/emscripten/SDL_sysfilesystem.c @@ -0,0 +1,69 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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/haiku/SDL_sysfilesystem.cc b/src/filesystem/haiku/SDL_sysfilesystem.cc index b83d4d0a1..3a0ea3484 100644 --- a/src/filesystem/haiku/SDL_sysfilesystem.cc +++ b/src/filesystem/haiku/SDL_sysfilesystem.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/filesystem/nacl/SDL_sysfilesystem.c b/src/filesystem/nacl/SDL_sysfilesystem.c index ff55b2ba9..4efda46e5 100644 --- a/src/filesystem/nacl/SDL_sysfilesystem.c +++ b/src/filesystem/nacl/SDL_sysfilesystem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/filesystem/unix/SDL_sysfilesystem.c b/src/filesystem/unix/SDL_sysfilesystem.c index cd11a67d3..b32649490 100644 --- a/src/filesystem/unix/SDL_sysfilesystem.c +++ b/src/filesystem/unix/SDL_sysfilesystem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/filesystem/windows/SDL_sysfilesystem.c b/src/filesystem/windows/SDL_sysfilesystem.c index 2791fb39a..2d1c78198 100644 --- a/src/filesystem/windows/SDL_sysfilesystem.c +++ b/src/filesystem/windows/SDL_sysfilesystem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -36,13 +36,51 @@ char * SDL_GetBasePath(void) { - TCHAR path[MAX_PATH]; - const DWORD len = GetModuleFileName(NULL, path, SDL_arraysize(path)); - size_t i; + typedef DWORD (WINAPI *GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD); + GetModuleFileNameExW_t pGetModuleFileNameExW; + DWORD buflen = 128; + WCHAR *path = NULL; + HANDLE psapi = LoadLibrary(L"psapi.dll"); + char *retval = NULL; + DWORD len = 0; + int i; + + if (!psapi) { + WIN_SetError("Couldn't load psapi.dll"); + return NULL; + } + + pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW"); + if (!pGetModuleFileNameExW) { + WIN_SetError("Couldn't find GetModuleFileNameExW"); + FreeLibrary(psapi); + return NULL; + } + + while (SDL_TRUE) { + void *ptr = SDL_realloc(path, buflen * sizeof (WCHAR)); + if (!ptr) { + SDL_free(path); + FreeLibrary(psapi); + SDL_OutOfMemory(); + return NULL; + } - SDL_assert(len < SDL_arraysize(path)); + path = (WCHAR *) ptr; + + len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen); + if (len != buflen) { + break; + } + + /* buffer too small? Try again. */ + buflen *= 2; + } + + FreeLibrary(psapi); if (len == 0) { + SDL_free(path); WIN_SetError("Couldn't locate our .exe"); return NULL; } @@ -55,7 +93,11 @@ SDL_GetBasePath(void) SDL_assert(i > 0); /* Should have been an absolute path. */ path[i+1] = '\0'; /* chop off filename. */ - return WIN_StringToUTF8(path); + + retval = WIN_StringToUTF8(path); + SDL_free(path); + + return retval; } char * diff --git a/src/filesystem/winrt/SDL_sysfilesystem.cpp b/src/filesystem/winrt/SDL_sysfilesystem.cpp index 48c21e10b..a70c7fe44 100644 --- a/src/filesystem/winrt/SDL_sysfilesystem.cpp +++ b/src/filesystem/winrt/SDL_sysfilesystem.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -20,8 +20,7 @@ */ #include "../../SDL_internal.h" -/* TODO, WinRT: include copyright info in SDL_winrtpaths.cpp - TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all +/* TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all */ #ifdef __WINRT__ @@ -29,6 +28,7 @@ extern "C" { #include "SDL_filesystem.h" #include "SDL_error.h" +#include "SDL_hints.h" #include "SDL_stdinc.h" #include "SDL_system.h" #include "../../core/windows/SDL_windows.h" @@ -62,7 +62,7 @@ SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType) return path.c_str(); } -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP +#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8) case SDL_WINRT_PATH_ROAMING_FOLDER: { static wstring path; @@ -144,31 +144,78 @@ SDL_GetPrefPath(const char *org, const char *app) * without violating Microsoft's app-store requirements. */ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - /* A 'Roaming' folder is not available in Windows Phone 8, however a 'Local' folder is. */ - const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_LOCAL_FOLDER); -#else - /* A 'Roaming' folder is available on Windows 8 and 8.1. Use that. */ - const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_ROAMING_FOLDER); -#endif + const WCHAR * srcPath = NULL; + WCHAR path[MAX_PATH]; + char *retval = NULL; + WCHAR* worg = NULL; + WCHAR* wapp = NULL; + size_t new_wpath_len = 0; + BOOL api_result = FALSE; + + srcPath = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_LOCAL_FOLDER); + if ( ! srcPath) { + SDL_SetError("Unable to find a source path"); + return NULL; + } - size_t destPathLen; - char * destPath = NULL; + if (SDL_wcslen(srcPath) >= MAX_PATH) { + SDL_SetError("Path too long."); + return NULL; + } + SDL_wcslcpy(path, srcPath, SDL_arraysize(path)); - if (!srcPath) { - SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); + worg = WIN_UTF8ToString(org); + if (worg == NULL) { + SDL_OutOfMemory(); return NULL; } - destPathLen = SDL_strlen(srcPath) + SDL_strlen(org) + SDL_strlen(app) + 4; - destPath = (char *) SDL_malloc(destPathLen); - if (!destPath) { + wapp = WIN_UTF8ToString(app); + if (wapp == NULL) { + SDL_free(worg); SDL_OutOfMemory(); return NULL; } - SDL_snprintf(destPath, destPathLen, "%s\\%s\\%s\\", srcPath, org, app); - return destPath; + new_wpath_len = SDL_wcslen(worg) + SDL_wcslen(wapp) + SDL_wcslen(path) + 3; + + if ((new_wpath_len + 1) > MAX_PATH) { + SDL_free(worg); + SDL_free(wapp); + SDL_SetError("Path too long."); + return NULL; + } + + SDL_wcslcat(path, L"\\", new_wpath_len + 1); + SDL_wcslcat(path, worg, new_wpath_len + 1); + SDL_free(worg); + + api_result = CreateDirectoryW(path, NULL); + if (api_result == FALSE) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + SDL_free(wapp); + WIN_SetError("Couldn't create a prefpath."); + return NULL; + } + } + + SDL_wcslcat(path, L"\\", new_wpath_len + 1); + SDL_wcslcat(path, wapp, new_wpath_len + 1); + SDL_free(wapp); + + api_result = CreateDirectoryW(path, NULL); + if (api_result == FALSE) { + if (GetLastError() != ERROR_ALREADY_EXISTS) { + WIN_SetError("Couldn't create a prefpath."); + return NULL; + } + } + + SDL_wcslcat(path, L"\\", new_wpath_len + 1); + + retval = WIN_StringToUTF8(path); + + return retval; } #endif /* __WINRT__ */ diff --git a/src/haptic/SDL_haptic.c b/src/haptic/SDL_haptic.c index 596b26e6e..0d5c0ef54 100644 --- a/src/haptic/SDL_haptic.c +++ b/src/haptic/SDL_haptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -845,3 +845,4 @@ SDL_HapticRumbleStop(SDL_Haptic * haptic) return SDL_HapticStopEffect(haptic, haptic->rumble_id); } +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/haptic/SDL_haptic_c.h b/src/haptic/SDL_haptic_c.h index b318fff11..24389c7e5 100644 --- a/src/haptic/SDL_haptic_c.h +++ b/src/haptic/SDL_haptic_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/haptic/SDL_syshaptic.h b/src/haptic/SDL_syshaptic.h index c808adc30..a364f8a8a 100644 --- a/src/haptic/SDL_syshaptic.h +++ b/src/haptic/SDL_syshaptic.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 */ @@ -212,4 +206,3 @@ extern int SDL_SYS_HapticStopAll(SDL_Haptic * haptic); #endif /* _SDL_syshaptic_h */ /* vi: set ts=4 sw=4 expandtab: */ - diff --git a/src/haptic/darwin/SDL_syshaptic.c b/src/haptic/darwin/SDL_syshaptic.c index 6d85bf0ed..152f779d0 100644 --- a/src/haptic/darwin/SDL_syshaptic.c +++ b/src/haptic/darwin/SDL_syshaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; @@ -683,7 +683,10 @@ SDL_SYS_HapticQuit(void) IOObjectRelease(item->dev); SDL_free(item); } + numhaptics = -1; + SDL_hapticlist = NULL; + SDL_hapticlist_tail = NULL; } @@ -771,18 +774,18 @@ static int SDL_SYS_ToFFEFFECT(SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src) { int i; - FFCONSTANTFORCE *constant; - FFPERIODIC *periodic; - FFCONDITION *condition; /* Actually an array of conditions - one per axis. */ - FFRAMPFORCE *ramp; - FFCUSTOMFORCE *custom; - FFENVELOPE *envelope; - SDL_HapticConstant *hap_constant; - SDL_HapticPeriodic *hap_periodic; - SDL_HapticCondition *hap_condition; - SDL_HapticRamp *hap_ramp; - SDL_HapticCustom *hap_custom; - DWORD *axes; + FFCONSTANTFORCE *constant = NULL; + FFPERIODIC *periodic = NULL; + FFCONDITION *condition = NULL; /* Actually an array of conditions - one per axis. */ + FFRAMPFORCE *ramp = NULL; + FFCUSTOMFORCE *custom = NULL; + FFENVELOPE *envelope = NULL; + SDL_HapticConstant *hap_constant = NULL; + SDL_HapticPeriodic *hap_periodic = NULL; + SDL_HapticCondition *hap_condition = NULL; + SDL_HapticRamp *hap_ramp = NULL; + SDL_HapticCustom *hap_custom = NULL; + DWORD *axes = NULL; /* Set global stuff. */ SDL_memset(dest, 0, sizeof(FFEFFECT)); @@ -912,25 +915,28 @@ SDL_SYS_ToFFEFFECT(SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src) case SDL_HAPTIC_INERTIA: case SDL_HAPTIC_FRICTION: hap_condition = &src->condition; - condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes); - if (condition == NULL) { - return SDL_OutOfMemory(); + if (dest->cAxes > 0) { + condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes); + if (condition == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(condition, 0, sizeof(FFCONDITION)); + + /* Specifics */ + for (i = 0; i < dest->cAxes; i++) { + condition[i].lOffset = CONVERT(hap_condition->center[i]); + condition[i].lPositiveCoefficient = + CONVERT(hap_condition->right_coeff[i]); + condition[i].lNegativeCoefficient = + CONVERT(hap_condition->left_coeff[i]); + condition[i].dwPositiveSaturation = + CCONVERT(hap_condition->right_sat[i] / 2); + condition[i].dwNegativeSaturation = + CCONVERT(hap_condition->left_sat[i] / 2); + condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2); + } } - SDL_memset(condition, 0, sizeof(FFCONDITION)); - /* Specifics */ - for (i = 0; i < dest->cAxes; i++) { - condition[i].lOffset = CONVERT(hap_condition->center[i]); - condition[i].lPositiveCoefficient = - CONVERT(hap_condition->right_coeff[i]); - condition[i].lNegativeCoefficient = - CONVERT(hap_condition->left_coeff[i]); - condition[i].dwPositiveSaturation = - CCONVERT(hap_condition->right_sat[i] / 2); - condition[i].dwNegativeSaturation = - CCONVERT(hap_condition->left_sat[i] / 2); - condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2); - } dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes; dest->lpvTypeSpecificParams = condition; @@ -1406,5 +1412,6 @@ SDL_SYS_HapticStopAll(SDL_Haptic * haptic) return 0; } - #endif /* SDL_HAPTIC_IOKIT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/haptic/darwin/SDL_syshaptic_c.h b/src/haptic/darwin/SDL_syshaptic_c.h index f80720717..0af044871 100644 --- a/src/haptic/darwin/SDL_syshaptic_c.h +++ b/src/haptic/darwin/SDL_syshaptic_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/haptic/dummy/SDL_syshaptic.c b/src/haptic/dummy/SDL_syshaptic.c index 09839c6de..ebff7daee 100644 --- a/src/haptic/dummy/SDL_syshaptic.c +++ b/src/haptic/dummy/SDL_syshaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -182,3 +182,5 @@ SDL_SYS_HapticStopAll(SDL_Haptic * haptic) } #endif /* SDL_HAPTIC_DUMMY || SDL_HAPTIC_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c index 459d0ab24..ab0a57077 100644 --- a/src/haptic/linux/SDL_syshaptic.c +++ b/src/haptic/linux/SDL_syshaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -59,6 +59,7 @@ typedef struct SDL_hapticlist_item { char *fname; /* Dev path name (like /dev/input/event1) */ SDL_Haptic *haptic; /* Associated haptic. */ + dev_t dev_num; struct SDL_hapticlist_item *next; } SDL_hapticlist_item; @@ -236,15 +237,11 @@ void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const static int MaybeAddDevice(const char *path) { - dev_t dev_nums[MAX_HAPTICS]; struct stat sb; int fd; - int k; - int duplicate; int success; SDL_hapticlist_item *item; - if (path == NULL) { return -1; } @@ -255,15 +252,11 @@ MaybeAddDevice(const char *path) } /* check for duplicates */ - duplicate = 0; - for (k = 0; (k < numhaptics) && !duplicate; ++k) { - if (sb.st_rdev == dev_nums[k]) { - duplicate = 1; + for (item = SDL_hapticlist; item != NULL; item = item->next) { + if (item->dev_num == sb.st_rdev) { + return -1; /* duplicate. */ } } - if (duplicate) { - return -1; - } /* try to open */ fd = open(path, O_RDWR, 0); @@ -288,12 +281,13 @@ 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; } + item->dev_num = sb.st_rdev; + /* TODO: should we add instance IDs? */ if (SDL_hapticlist_tail == NULL) { SDL_hapticlist = SDL_hapticlist_tail = item; @@ -302,8 +296,6 @@ MaybeAddDevice(const char *path) SDL_hapticlist_tail = item; } - dev_nums[numhaptics] = sb.st_rdev; - ++numhaptics; /* !!! TODO: Send a haptic add event? */ @@ -391,8 +383,8 @@ SDL_SYS_HapticName(int index) /* No name found, return device character device */ name = item->fname; } + close(fd); } - close(fd); return name; } @@ -441,7 +433,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; @@ -547,7 +539,6 @@ SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) int ret; SDL_hapticlist_item *item; - /* Find the joystick in the haptic list. */ for (item = SDL_hapticlist; item; item = item->next) { if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) { @@ -669,6 +660,8 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src) 90 deg -> 0x4000 (left) 180 deg -> 0x8000 (up) 270 deg -> 0xC000 (right) + The force pulls into the direction specified by Linux directions, + i.e. the opposite convention of SDL directions. */ tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */ *dest = (Uint16) tmp; @@ -727,7 +720,6 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src) static int SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src) { - Uint32 tmp; SDL_HapticConstant *constant; SDL_HapticPeriodic *periodic; SDL_HapticCondition *condition; @@ -805,9 +797,8 @@ SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src) dest->u.periodic.period = CLAMP(periodic->period); dest->u.periodic.magnitude = periodic->magnitude; dest->u.periodic.offset = periodic->offset; - /* Phase is calculated based of offset from period and then clamped. */ - tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000; - dest->u.periodic.phase = CLAMP(tmp); + /* Linux phase is defined in interval "[0x0000, 0x10000[", corresponds with "[0deg, 360deg[" phase shift. */ + dest->u.periodic.phase = ((Uint32)periodic->phase * 0x10000U) / 36000; /* Envelope */ dest->u.periodic.envelope.attack_length = @@ -959,7 +950,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; } @@ -1163,5 +1154,6 @@ SDL_SYS_HapticStopAll(SDL_Haptic * haptic) return 0; } - #endif /* SDL_HAPTIC_LINUX */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/haptic/windows/SDL_dinputhaptic.c b/src/haptic/windows/SDL_dinputhaptic.c index 9ff46a9d4..1cd704259 100644 --- a/src/haptic/windows/SDL_dinputhaptic.c +++ b/src/haptic/windows/SDL_dinputhaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -21,17 +21,17 @@ #include "../../SDL_internal.h" #include "SDL_error.h" -#include "SDL_stdinc.h" #include "SDL_haptic.h" +#include "../SDL_syshaptic.h" + +#if SDL_HAPTIC_DINPUT + +#include "SDL_stdinc.h" #include "SDL_timer.h" #include "SDL_windowshaptic_c.h" #include "SDL_dinputhaptic_c.h" -#include "../SDL_syshaptic.h" #include "../../joystick/windows/SDL_windowsjoystick_c.h" - -#if SDL_HAPTIC_DINPUT - /* * External stuff. */ @@ -1181,6 +1181,8 @@ SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic) #else /* !SDL_HAPTIC_DINPUT */ +typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE; +typedef struct SDL_hapticlist_item SDL_hapticlist_item; int SDL_DINPUT_HapticInit(void) diff --git a/src/haptic/windows/SDL_dinputhaptic_c.h b/src/haptic/windows/SDL_dinputhaptic_c.h index 9801fe272..d587ab72a 100644 --- a/src/haptic/windows/SDL_dinputhaptic_c.h +++ b/src/haptic/windows/SDL_dinputhaptic_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/haptic/windows/SDL_windowshaptic.c b/src/haptic/windows/SDL_windowshaptic.c index 26095dc58..a0b6c5541 100644 --- a/src/haptic/windows/SDL_windowshaptic.c +++ b/src/haptic/windows/SDL_windowshaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -272,6 +272,10 @@ SDL_SYS_HapticQuit(void) SDL_XINPUT_HapticQuit(); SDL_DINPUT_HapticQuit(); + + numhaptics = 0; + SDL_hapticlist = NULL; + SDL_hapticlist_tail = NULL; } /* diff --git a/src/haptic/windows/SDL_windowshaptic_c.h b/src/haptic/windows/SDL_windowshaptic_c.h index e715339d6..e3de13365 100644 --- a/src/haptic/windows/SDL_windowshaptic_c.h +++ b/src/haptic/windows/SDL_windowshaptic_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/haptic/windows/SDL_xinputhaptic.c b/src/haptic/windows/SDL_xinputhaptic.c index 2e76a9592..b5fb2e344 100644 --- a/src/haptic/windows/SDL_xinputhaptic.c +++ b/src/haptic/windows/SDL_xinputhaptic.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -20,20 +20,20 @@ */ #include "../../SDL_internal.h" -#include "SDL_assert.h" #include "SDL_error.h" #include "SDL_haptic.h" +#include "../SDL_syshaptic.h" + +#if SDL_HAPTIC_XINPUT + +#include "SDL_assert.h" #include "SDL_hints.h" #include "SDL_timer.h" #include "SDL_windowshaptic_c.h" #include "SDL_xinputhaptic_c.h" -#include "../SDL_syshaptic.h" #include "../../core/windows/SDL_xinput.h" #include "../../joystick/windows/SDL_windowsjoystick_c.h" - -#if SDL_HAPTIC_XINPUT - /* * Internal stuff. */ @@ -375,6 +375,9 @@ SDL_XINPUT_HapticStopAll(SDL_Haptic * haptic) #else /* !SDL_HAPTIC_XINPUT */ +#include "../../core/windows/SDL_windows.h" + +typedef struct SDL_hapticlist_item SDL_hapticlist_item; int SDL_XINPUT_HapticInit(void) @@ -488,4 +491,5 @@ SDL_XINPUT_HapticStopAll(SDL_Haptic * haptic) } #endif /* SDL_HAPTIC_XINPUT */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/haptic/windows/SDL_xinputhaptic_c.h b/src/haptic/windows/SDL_xinputhaptic_c.h index c3062b6ea..7917128d6 100644 --- a/src/haptic/windows/SDL_xinputhaptic_c.h +++ b/src/haptic/windows/SDL_xinputhaptic_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index c60f39189..bfa8abeaf 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 @@ -258,16 +259,29 @@ ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *gu */ ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) { + SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index); + ControllerMapping_t *mapping; + + mapping = SDL_PrivateGetControllerMappingForGUID(&jGUID); #if SDL_JOYSTICK_XINPUT - if (SDL_SYS_IsXInputGamepad_DeviceIndex(device_index) && s_pXInputMapping) { - return s_pXInputMapping; + if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) { + mapping = s_pXInputMapping; + } +#endif +#if defined(SDL_JOYSTICK_EMSCRIPTEN) + if (!mapping && s_pEmscriptenMapping) { + mapping = s_pEmscriptenMapping; } - else -#endif /* SDL_JOYSTICK_XINPUT */ - { - SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID(device_index); - return SDL_PrivateGetControllerMappingForGUID(&jGUID); +#endif + if (!mapping) { + const char *name = SDL_JoystickNameForIndex(device_index); + if (name) { + if (SDL_strstr(name, "Xbox") || SDL_strstr(name, "X-Box")) { + mapping = s_pXInputMapping; + } + } } + return mapping; } static const char* map_StringForControllerAxis[] = { @@ -606,7 +620,7 @@ SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw) if (freerw) { SDL_RWclose(rw); } - return SDL_SetError("Could allocate space to not read DB into memory"); + return SDL_SetError("Could not allocate space to read DB into memory"); } if (SDL_RWread(rw, buf, db_size, 1) != 1) { @@ -668,6 +682,11 @@ 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"); + } pchGUID = SDL_PrivateGetControllerGUIDFromMappingString(mappingString); if (!pchGUID) { @@ -676,6 +695,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); @@ -711,6 +733,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; @@ -735,6 +760,10 @@ SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid) /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */ needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1; pMappingString = SDL_malloc(needed); + if (!pMappingString) { + SDL_OutOfMemory(); + return NULL; + } SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping); } return pMappingString; @@ -746,6 +775,10 @@ SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid) char * SDL_GameControllerMapping(SDL_GameController * gamecontroller) { + if (!gamecontroller) { + return NULL; + } + return SDL_GameControllerMappingForGUID(gamecontroller->mapping.guid); } @@ -992,9 +1025,6 @@ SDL_GameControllerGetAttached(SDL_GameController * gamecontroller) } -/* - * Get the number of multi-dimensional axis controls on a joystick - */ const char * SDL_GameControllerName(SDL_GameController * gamecontroller) { @@ -1066,9 +1096,6 @@ SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameControll } -/* - * Close a joystick previously opened with SDL_JoystickOpen() - */ void SDL_GameControllerClose(SDL_GameController * gamecontroller) { diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index fe3a1671a..d6c23a832 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -63,19 +63,27 @@ 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,", + "03000000341a00003608000011010000,PS3 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "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,", + "03000000321500000009000011010000,Razer Serval,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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", + "050000003215000000090000163a0000,Razer Serval,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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", "03000000de280000fc11000001000000,Steam 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,", "03000000de280000ff11000001000000,Valve Streaming Gamepad,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,", - "030000005e0400008e02000014010000,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,", - "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,", + "xinput,XInput 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,", + "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_gamecontrollerdb.h.new b/src/joystick/SDL_gamecontrollerdb.h.new deleted file mode 100644 index 7f6c7b29f..000000000 --- a/src/joystick/SDL_gamecontrollerdb.h.new +++ /dev/null @@ -1,65 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2013 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_config.h" - - -/* Default mappings we support - - The easiest way to generate a new mapping is to start Steam in Big Picture - mode, configure your joystick and then look in config/config.vdf in your - Steam installation directory for the "SDL_GamepadBind" entry. - */ -static const char *s_ControllerMappings [] = -{ -#ifdef SDL_JOYSTICK_DINPUT - "341a3608000000000000504944564944,Afterglow PS3 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", - "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,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,", - "6d0416c2000000000000504944564944,Generic DirectInput Controller,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,", - "6d0419c2000000000000504944564944,Logitech F710 Gamepad,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. */ - "88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,", - "4c056802000000000000504944564944,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,", - "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,", - "xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,", -#elif defined(__MACOSX__) - "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,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,", - "6d0400000000000016c2000000000000,Logitech F310 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. */ - "6d0400000000000018c2000000000000,Logitech F510 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,", - "6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", - "6d0400000000000019c2000000000000,Logitech Wireless 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,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */ - "4c050000000000006802000000000000,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,", - "5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", -#elif defined(__LINUX__) - "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,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,", - "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,", - "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,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,", - "030000006d0400001dc2000014400000,Logitech F310 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,", - "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,", - "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,", - "030000005e0400008e02000014010000,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,", - "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,", -#endif - NULL -}; - -/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 2a60c0036..192e0539c 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_joystick_c.h b/src/joystick/SDL_joystick_c.h index 064fb8a39..ee4a14a37 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index a39869575..7c104b500 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..8ab682d45 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -191,8 +191,8 @@ Android_OnPadDown(int device_id, int keycode) item = JoystickByDeviceId(device_id); if (item && item->joystick) { SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED); + return 0; } - return 0; } return -1; @@ -207,8 +207,8 @@ Android_OnPadUp(int device_id, int keycode) item = JoystickByDeviceId(device_id); if (item && item->joystick) { SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED); + return 0; } - return 0; } return -1; @@ -311,7 +311,9 @@ Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, } #endif /* !SDL_EVENTS_DISABLED */ +#ifdef DEBUG_JOYSTICK SDL_Log("Added joystick %s with device_id %d", name, device_id); +#endif return numjoysticks; } @@ -368,7 +370,9 @@ Android_RemoveJoystick(int device_id) } #endif /* !SDL_EVENTS_DISABLED */ +#ifdef DEBUG_JOYSTICK SDL_Log("Removed joystick with device_id %d", device_id); +#endif SDL_free(item->name); SDL_free(item); @@ -467,7 +471,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 +499,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 @@ -514,6 +518,12 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) if (item->joystick) { if (Android_JNI_GetAccelerometerValues(values)) { for ( i = 0; i < 3; i++ ) { + if (values[i] > 1.0f) { + values[i] = 1.0f; + } else if (values[i] < -1.0f) { + values[i] = -1.0f; + } + value = (Sint16)(values[i] * 32767.0f); SDL_PrivateJoystickAxis(item->joystick, i, value); } @@ -529,11 +539,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..2137e33c1 100644 --- a/src/joystick/android/SDL_sysjoystick_c.h +++ b/src/joystick/android/SDL_sysjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..a6fe2f735 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..2b5f59150 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -46,13 +46,23 @@ static IOHIDManagerRef hidman = NULL; /* Linked list of all available devices */ static recDevice *gpDeviceList = NULL; -/* if SDL_TRUE then a device was added since the last update call */ -static SDL_bool s_bDeviceAdded = SDL_FALSE; -static SDL_bool s_bDeviceRemoved = SDL_FALSE; - /* static incrementing counter for new joystick devices seen on the system. Devices should start with index 0 */ static int s_joystick_instance_id = -1; +static recDevice *GetDeviceForIndex(int device_index) +{ + recDevice *device = gpDeviceList; + while (device) { + if (!device->removed) { + if (device_index == 0) + break; + + --device_index; + } + device = device->pNext; + } + return device; +} static void FreeElementList(recElement *pElement) @@ -138,12 +148,27 @@ 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); #endif - s_bDeviceRemoved = SDL_TRUE; + +/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceRemoved()? */ +#if !SDL_EVENTS_DISABLED + { + SDL_Event event; + event.type = SDL_JOYDEVICEREMOVED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = device->instance_id; + if ((SDL_EventOK == NULL) + || (*SDL_EventOK) (SDL_EventOKParam, &event)) { + SDL_PushEvent(&event); + } + } + } +#endif /* !SDL_EVENTS_DISABLED */ } @@ -381,6 +406,7 @@ static void JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDeviceRef ioHIDDeviceObject) { recDevice *device; + int device_index = 0; if (res != kIOReturnSuccess) { return; @@ -410,18 +436,22 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic device->instance_id = ++s_joystick_instance_id; /* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */ + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 if (IOHIDDeviceGetService != NULL) { /* weak reference: available in 10.6 and later. */ +#endif + 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; - s_bDeviceAdded = SDL_TRUE; +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + } +#endif /* Add device to the end of the list */ if ( !gpDeviceList ) { @@ -431,10 +461,27 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic curdevice = gpDeviceList; while ( curdevice->pNext ) { + ++device_index; curdevice = curdevice->pNext; } curdevice->pNext = device; } + +/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceAdded()? */ +#if !SDL_EVENTS_DISABLED + { + SDL_Event event; + event.type = SDL_JOYDEVICEADDED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = device_index; + if ((SDL_EventOK == NULL) + || (*SDL_EventOK) (SDL_EventOKParam, &event)) { + SDL_PushEvent(&event); + } + } + } +#endif /* !SDL_EVENTS_DISABLED */ } static SDL_bool @@ -446,9 +493,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,72 +607,28 @@ 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; - s_bDeviceRemoved = SDL_FALSE; - int device_index = 0; - /* send notifications */ - while (device) { - if (device->send_open_event) { - device->send_open_event = 0; -/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceAdded()? */ -#if !SDL_EVENTS_DISABLED - SDL_Event event; - event.type = SDL_JOYDEVICEADDED; - - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = device_index; - if ((SDL_EventOK == NULL) - || (*SDL_EventOK) (SDL_EventOKParam, &event)) { - SDL_PushEvent(&event); - } - } -#endif /* !SDL_EVENTS_DISABLED */ - - } - - if (device->removed) { - const int instance_id = device->instance_id; - device = FreeDevice(device); - -/* !!! FIXME: why isn't there an SDL_PrivateJoyDeviceRemoved()? */ -#if !SDL_EVENTS_DISABLED - SDL_Event event; - event.type = SDL_JOYDEVICEREMOVED; - - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = instance_id; - if ((SDL_EventOK == NULL) - || (*SDL_EventOK) (SDL_EventOKParam, &event)) { - SDL_PushEvent(&event); - } - } -#endif /* !SDL_EVENTS_DISABLED */ - - } else { - device = device->pNext; - device_index++; - } + recDevice *device = gpDeviceList; + while (device) { + if (device->removed) { + device = FreeDevice(device); + } else { + device = device->pNext; } } + + // 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 */ const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index) { - recDevice *device = gpDeviceList; - - while (device_index-- > 0) { - device = device->pNext; - } - - return device->product; + recDevice *device = GetDeviceForIndex(device_index); + return device ? device->product : "UNKNOWN"; } /* Function to return the instance id of the joystick at device_index @@ -633,30 +636,19 @@ SDL_SYS_JoystickNameForDeviceIndex(int device_index) SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) { - recDevice *device = gpDeviceList; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } - - return device->instance_id; + recDevice *device = GetDeviceForIndex(device_index); + return device ? device->instance_id : 0; } /* Function to open a joystick for use. - * The joystick to open is specified by the index field of the joystick. + * The joystick to open is specified by the device index. * This should fill the nbuttons and naxes fields of the joystick structure. * It returns 0, or -1 if there is an error. */ int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) { - recDevice *device = gpDeviceList; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; - } + recDevice *device = GetDeviceForIndex(device_index); joystick->instance_id = device->instance_id; joystick->hwdata = device; @@ -670,21 +662,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 +688,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 +779,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 */ @@ -812,21 +795,19 @@ SDL_SYS_JoystickQuit(void) CFRelease(hidman); hidman = NULL; } - - s_bDeviceAdded = s_bDeviceRemoved = SDL_FALSE; } SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) { - recDevice *device = gpDeviceList; - int index; - - for (index = device_index; index > 0; index--) { - device = device->pNext; + recDevice *device = GetDeviceForIndex(device_index); + SDL_JoystickGUID guid; + if (device) { + guid = device->guid; + } else { + SDL_zero(guid); } - - return device->guid; + return guid; } SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick) diff --git a/src/joystick/darwin/SDL_sysjoystick_c.h b/src/joystick/darwin/SDL_sysjoystick_c.h index 0a15ba18d..7bc20d065 100644 --- a/src/joystick/darwin/SDL_sysjoystick_c.h +++ b/src/joystick/darwin/SDL_sysjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -58,12 +58,10 @@ struct joystick_hwdata recElement *firstButton; recElement *firstHat; - int removed; - int uncentered; + SDL_bool removed; int instance_id; SDL_JoystickGUID guid; - Uint8 send_open_event; /* 1 if we need to send an Added event for this device */ struct joystick_hwdata *pNext; /* next device */ }; diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c index 9baa79500..6212c0e55 100644 --- a/src/joystick/dummy/SDL_sysjoystick.c +++ b/src/joystick/dummy/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..df963e5d4 --- /dev/null +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -0,0 +1,430 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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) { + SDL_SetError("Gamepads 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(); + SDL_SetError("Could not set gamepad connect callback"); + return -1; + } + + retval = emscripten_set_gamepaddisconnected_callback(NULL, + 0, + Emscripten_JoyStickDisconnected); + if(retval != EMSCRIPTEN_RESULT_SUCCESS) { + SDL_SYS_JoystickQuit(); + SDL_SetError("Could not set gamepad disconnect callback"); + 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..82b4e13b7 --- /dev/null +++ b/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..612f3849d 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..d7a7fcbce 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(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 @@ static void SDL_SYS_AccelerometerUpdate(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..c6f7911ca 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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"); } @@ -491,7 +492,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) ++joystick->nbuttons; } } - for (i = 0; i < ABS_MISC; ++i) { + for (i = 0; i < ABS_MAX; ++i) { /* Skip hats */ if (i == ABS_HAT0X) { i = ABS_HAT3Y; @@ -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 @@ -752,10 +753,6 @@ HandleInputEvents(SDL_Joystick * joystick) } break; case EV_ABS: - if (code >= ABS_MISC) { - break; - } - switch (code) { case ABS_HAT0X: case ABS_HAT0Y: @@ -840,9 +837,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/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h index 16d16e26b..0d7e65d2c 100644 --- a/src/joystick/linux/SDL_sysjoystick_c.h +++ b/src/joystick/linux/SDL_sysjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/joystick/psp/SDL_sysjoystick.c b/src/joystick/psp/SDL_sysjoystick.c index 9a2362e1d..9d20f90dd 100644 --- a/src/joystick/psp/SDL_sysjoystick.c +++ b/src/joystick/psp/SDL_sysjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/sort_controllers.py b/src/joystick/sort_controllers.py index 03b857a02..af95d6513 100755 --- a/src/joystick/sort_controllers.py +++ b/src/joystick/sort_controllers.py @@ -30,9 +30,9 @@ def write_controllers(): for entry in sorted(controllers, key=lambda entry: entry[2]): line = "".join(entry) + "\n" if not line.endswith(",\n") and not line.endswith("*/\n"): - print "Warning: '%s' is missing a comma at the end of the line" % (line) + print("Warning: '%s' is missing a comma at the end of the line" % (line)) if (entry[1] in controller_guids): - print "Warning: entry '%s' is duplicate of entry '%s'" % (entry[2], controller_guids[entry[1]][2]) + print("Warning: entry '%s' is duplicate of entry '%s'" % (entry[2], controller_guids[entry[1]][2])) controller_guids[entry[1]] = entry output.write(line) @@ -40,15 +40,17 @@ def write_controllers(): controller_guids = {} for line in input: - if ( parsing_controllers ): + if (parsing_controllers): if (line.startswith("{")): output.write(line) - elif (line.startswith("#endif")): + elif (line.startswith(" NULL")): parsing_controllers = False write_controllers() output.write(line) - elif (line.startswith("#")): - print "Parsing " + line.strip() + elif (line.startswith("#if")): + print("Parsing " + line.strip()) + output.write(line) + elif (line.startswith("#endif")): write_controllers() output.write(line) else: @@ -60,4 +62,4 @@ def write_controllers(): output.write(line) output.close() -print "Finished writing %s.new" % filename +print("Finished writing %s.new" % filename) diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c index 179f99283..61d5b3862 100644 --- a/src/joystick/windows/SDL_dinputjoystick.c +++ b/src/joystick/windows/SDL_dinputjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -21,13 +21,13 @@ #include "../../SDL_internal.h" #include "../SDL_sysjoystick.h" + +#if SDL_JOYSTICK_DINPUT + #include "SDL_windowsjoystick_c.h" #include "SDL_dinputjoystick_c.h" #include "SDL_xinputjoystick_c.h" - -#if SDL_JOYSTICK_DINPUT - #ifndef DIDFT_OPTIONAL #define DIDFT_OPTIONAL 0x80000000 #endif @@ -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_SUPPLEMENTAL) { + return DIENUM_CONTINUE; /* Ignore touchpads, etc. */ + } if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) { return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */ @@ -862,6 +867,7 @@ SDL_DINPUT_JoystickQuit(void) #else /* !SDL_JOYSTICK_DINPUT */ +typedef struct JoyStick_DeviceData JoyStick_DeviceData; int SDL_DINPUT_JoystickInit(void) diff --git a/src/joystick/windows/SDL_dinputjoystick_c.h b/src/joystick/windows/SDL_dinputjoystick_c.h index 3facf0e5d..f93b12090 100644 --- a/src/joystick/windows/SDL_dinputjoystick_c.h +++ b/src/joystick/windows/SDL_dinputjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/joystick/windows/SDL_mmjoystick.c b/src/joystick/windows/SDL_mmjoystick.c index 0f3b6decc..65b16ab98 100644 --- a/src/joystick/windows/SDL_mmjoystick.c +++ b/src/joystick/windows/SDL_mmjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..c06fad0d8 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/joystick/windows/SDL_windowsjoystick_c.h b/src/joystick/windows/SDL_windowsjoystick_c.h index 9b09e6568..5f991dc2c 100644 --- a/src/joystick/windows/SDL_windowsjoystick_c.h +++ b/src/joystick/windows/SDL_windowsjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index 12bf98855..b1c22ab1f 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -20,15 +20,15 @@ */ #include "../../SDL_internal.h" +#include "../SDL_sysjoystick.h" + +#if SDL_JOYSTICK_XINPUT + #include "SDL_assert.h" #include "SDL_hints.h" -#include "../SDL_sysjoystick.h" #include "SDL_windowsjoystick_c.h" #include "SDL_xinputjoystick_c.h" - -#if SDL_JOYSTICK_XINPUT - /* * Internal stuff. */ @@ -339,6 +339,7 @@ SDL_SYS_IsXInputGamepad_DeviceIndex(int device_index) #else /* !SDL_JOYSTICK_XINPUT */ +typedef struct JoyStick_DeviceData JoyStick_DeviceData; SDL_bool SDL_XINPUT_Enabled(void) { diff --git a/src/joystick/windows/SDL_xinputjoystick_c.h b/src/joystick/windows/SDL_xinputjoystick_c.h index 825c29209..ed6087bcd 100644 --- a/src/joystick/windows/SDL_xinputjoystick_c.h +++ b/src/joystick/windows/SDL_xinputjoystick_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/libm/math_libm.h b/src/libm/math_libm.h index 6b479f44d..9e91073e9 100644 --- a/src/libm/math_libm.h +++ b/src/libm/math_libm.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/loadso/dlopen/SDL_sysloadso.c b/src/loadso/dlopen/SDL_sysloadso.c index db8422221..f3dffefd0 100644 --- a/src/loadso/dlopen/SDL_sysloadso.c +++ b/src/loadso/dlopen/SDL_sysloadso.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/loadso/dummy/SDL_sysloadso.c b/src/loadso/dummy/SDL_sysloadso.c index 0dfb90b0c..a38b56970 100644 --- a/src/loadso/dummy/SDL_sysloadso.c +++ b/src/loadso/dummy/SDL_sysloadso.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/loadso/haiku/SDL_sysloadso.c b/src/loadso/haiku/SDL_sysloadso.c index c8bba670f..a5f129505 100644 --- a/src/loadso/haiku/SDL_sysloadso.c +++ b/src/loadso/haiku/SDL_sysloadso.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/loadso/windows/SDL_sysloadso.c b/src/loadso/windows/SDL_sysloadso.c index 4d32b0985..1c1d8cfa5 100644 --- a/src/loadso/windows/SDL_sysloadso.c +++ b/src/loadso/windows/SDL_sysloadso.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/main/android/SDL_android_main.c b/src/main/android/SDL_android_main.c index 8189050d8..4173bcb1d 100644 --- a/src/main/android/SDL_android_main.c +++ b/src/main/android/SDL_android_main.c @@ -47,6 +47,7 @@ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jc arg = SDL_strdup(utf); (*env)->ReleaseStringUTFChars(env, string, utf); } + (*env)->DeleteLocalRef(env, string); } if (!arg) { arg = SDL_strdup(""); diff --git a/src/main/haiku/SDL_BApp.h b/src/main/haiku/SDL_BApp.h index 1e4a0f550..1c5dbb844 100644 --- a/src/main/haiku/SDL_BApp.h +++ b/src/main/haiku/SDL_BApp.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -254,7 +254,7 @@ class SDL_BApp : public BApplication { 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/haiku/SDL_BeApp.cc b/src/main/haiku/SDL_BeApp.cc index d471887fa..f09afb2ed 100644 --- a/src/main/haiku/SDL_BeApp.cc +++ b/src/main/haiku/SDL_BeApp.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/main/haiku/SDL_BeApp.h b/src/main/haiku/SDL_BeApp.h index f4399c819..b1cb95016 100644 --- a/src/main/haiku/SDL_BeApp.h +++ b/src/main/haiku/SDL_BeApp.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/main/nacl/SDL_nacl_main.c b/src/main/nacl/SDL_nacl_main.c index 40a29ddf5..378db7afb 100644 --- a/src/main/nacl/SDL_nacl_main.c +++ b/src/main/nacl/SDL_nacl_main.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -90,4 +90,4 @@ nacl_main(int argc, char *argv[]) /* ppapi_simple will start nacl_main in a worker thread */ PPAPI_SIMPLE_REGISTER_MAIN(nacl_main); -#endif /* SDL_VIDEO_DRIVER_NACL */ \ No newline at end of file +#endif /* SDL_VIDEO_DRIVER_NACL */ 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 f7cdbdbc2..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) @@ -134,8 +168,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* Grab the command line */ TCHAR *text = GetCommandLine(); #if UNICODE - cmdline = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char *)(text), (SDL_wcslen(text)+1)*sizeof(WCHAR)); + 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/main/windows/version.rc b/src/main/windows/version.rc index 3a461276e..d9fbffc71 100644 --- a/src/main/windows/version.rc +++ b/src/main/windows/version.rc @@ -25,7 +25,7 @@ BEGIN VALUE "FileDescription", "SDL\0" VALUE "FileVersion", "2, 0, 4, 0\0" VALUE "InternalName", "SDL\0" - VALUE "LegalCopyright", "Copyright © 2014 Sam Lantinga\0" + VALUE "LegalCopyright", "Copyright © 2015 Sam Lantinga\0" VALUE "OriginalFilename", "SDL2.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" VALUE "ProductVersion", "2, 0, 4, 0\0" diff --git a/src/power/SDL_power.c b/src/power/SDL_power.c index cc9ba396d..8f919f2eb 100644 --- a/src/power/SDL_power.c +++ b/src/power/SDL_power.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -29,6 +29,7 @@ typedef SDL_bool (*SDL_GetPowerInfo_Impl) (SDL_PowerState * state, int *seconds, int *percent); +SDL_bool SDL_GetPowerInfo_Linux_sys_class_power_supply(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState *, int *, int *); SDL_bool SDL_GetPowerInfo_Windows(SDL_PowerState *, int *, int *); @@ -38,6 +39,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 @@ -57,6 +59,7 @@ SDL_GetPowerInfo_Hardwired(SDL_PowerState * state, int *seconds, int *percent) static SDL_GetPowerInfo_Impl implementations[] = { #ifndef SDL_POWER_DISABLED #ifdef SDL_POWER_LINUX /* in order of preference. More than could work. */ + SDL_GetPowerInfo_Linux_sys_class_power_supply, SDL_GetPowerInfo_Linux_proc_acpi, SDL_GetPowerInfo_Linux_proc_apm, #endif @@ -81,6 +84,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/android/SDL_syspower.c b/src/power/android/SDL_syspower.c index e363731d3..94a4ff4cb 100644 --- a/src/power/android/SDL_syspower.c +++ b/src/power/android/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/power/emscripten/SDL_syspower.c b/src/power/emscripten/SDL_syspower.c new file mode 100644 index 000000000..3a2b4ed8d --- /dev/null +++ b/src/power/emscripten/SDL_syspower.c @@ -0,0 +1,62 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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/haiku/SDL_syspower.c b/src/power/haiku/SDL_syspower.c index aaf61e8b7..2d87806af 100644 --- a/src/power/haiku/SDL_syspower.c +++ b/src/power/haiku/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/power/linux/SDL_syspower.c b/src/power/linux/SDL_syspower.c index 05eb200b4..3986489f7 100644 --- a/src/power/linux/SDL_syspower.c +++ b/src/power/linux/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -36,8 +36,10 @@ static const char *proc_apm_path = "/proc/apm"; static const char *proc_acpi_battery_path = "/proc/acpi/battery"; static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter"; +static const char *sys_class_power_supply_path = "/sys/class/power_supply"; -static int open_acpi_file(const char *base, const char *node, const char *key) +static int +open_power_file(const char *base, const char *node, const char *key) { const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3; char *path = (char *) alloca(pathlen); @@ -51,11 +53,11 @@ static int open_acpi_file(const char *base, const char *node, const char *key) static SDL_bool -load_acpi_file(const char *base, const char *node, const char *key, - char *buf, size_t buflen) +read_power_file(const char *base, const char *node, const char *key, + char *buf, size_t buflen) { ssize_t br = 0; - const int fd = open_acpi_file(base, node, key); + const int fd = open_power_file(base, node, key); if (fd == -1) { return SDL_FALSE; } @@ -133,9 +135,9 @@ check_proc_acpi_battery(const char * node, SDL_bool * have_battery, int secs = -1; int pct = -1; - if (!load_acpi_file(base, node, "state", state, sizeof (state))) { + if (!read_power_file(base, node, "state", state, sizeof (state))) { return; - } else if (!load_acpi_file(base, node, "info", info, sizeof (info))) { + } else if (!read_power_file(base, node, "info", info, sizeof (info))) { return; } @@ -214,7 +216,7 @@ check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac) char *key = NULL; char *val = NULL; - if (!load_acpi_file(base, node, "state", state, sizeof (state))) { + if (!read_power_file(base, node, "state", state, sizeof (state))) { return; } @@ -423,6 +425,94 @@ SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState * state, return SDL_TRUE; } +/* !!! FIXME: implement d-bus queries to org.freedesktop.UPower. */ + +SDL_bool +SDL_GetPowerInfo_Linux_sys_class_power_supply(SDL_PowerState *state, int *seconds, int *percent) +{ + const char *base = sys_class_power_supply_path; + struct dirent *dent; + DIR *dirp; + + dirp = opendir(base); + if (!dirp) { + return SDL_FALSE; + } + + *state = SDL_POWERSTATE_NO_BATTERY; /* assume we're just plugged in. */ + *seconds = -1; + *percent = -1; + + while ((dent = readdir(dirp)) != NULL) { + const char *name = dent->d_name; + SDL_bool choose = SDL_FALSE; + char str[64]; + SDL_PowerState st; + int secs; + int pct; + + if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) { + continue; /* skip these, of course. */ + } else if (!read_power_file(base, name, "type", str, sizeof (str))) { + continue; /* Don't know _what_ we're looking at. Give up on it. */ + } else if (SDL_strcmp(str, "Battery\n") != 0) { + continue; /* we don't care about UPS and such. */ + } + + /* some drivers don't offer this, so if it's not explicitly reported assume it's present. */ + if (read_power_file(base, name, "present", str, sizeof (str)) && (SDL_strcmp(str, "0\n") == 0)) { + st = SDL_POWERSTATE_NO_BATTERY; + } else if (!read_power_file(base, name, "status", str, sizeof (str))) { + st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ + } else if (SDL_strcmp(str, "Charging\n") == 0) { + st = SDL_POWERSTATE_CHARGING; + } else if (SDL_strcmp(str, "Discharging\n") == 0) { + st = SDL_POWERSTATE_ON_BATTERY; + } else if ((SDL_strcmp(str, "Full\n") == 0) || (SDL_strcmp(str, "Not charging\n") == 0)) { + st = SDL_POWERSTATE_CHARGED; + } else { + st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ + } + + if (!read_power_file(base, name, "capacity", str, sizeof (str))) { + pct = -1; + } else { + pct = SDL_atoi(str); + pct = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */ + } + + if (!read_power_file(base, name, "time_to_empty_now", str, sizeof (str))) { + secs = -1; + } else { + secs = SDL_atoi(str); + secs = (secs <= 0) ? -1 : secs; /* 0 == unknown */ + } + + /* + * We pick the battery that claims to have the most minutes left. + * (failing a report of minutes, we'll take the highest percent.) + */ + if ((secs < 0) && (*seconds < 0)) { + if ((pct < 0) && (*percent < 0)) { + choose = SDL_TRUE; /* at least we know there's a battery. */ + } else if (pct > *percent) { + choose = SDL_TRUE; + } + } else if (secs > *seconds) { + choose = SDL_TRUE; + } + + if (choose) { + *seconds = secs; + *percent = pct; + *state = st; + } + } + + closedir(dirp); + return SDL_TRUE; /* don't look any further. */ +} + #endif /* SDL_POWER_LINUX */ #endif /* SDL_POWER_DISABLED */ diff --git a/src/power/macosx/SDL_syspower.c b/src/power/macosx/SDL_syspower.c index 9bcacafde..d029de5d9 100644 --- a/src/power/macosx/SDL_syspower.c +++ b/src/power/macosx/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -23,13 +23,13 @@ #ifndef SDL_POWER_DISABLED #if SDL_POWER_MACOSX -#include +#include #include #include #include "SDL_power.h" -/* Carbon is so verbose... */ +/* CoreFoundation is so verbose... */ #define STRMATCH(a,b) (CFStringCompare(a, b, 0) == kCFCompareEqualTo) #define GETVAL(k,v) \ CFDictionaryGetValueIfPresent(dict, CFSTR(k), (const void **) v) diff --git a/src/power/psp/SDL_syspower.c b/src/power/psp/SDL_syspower.c index b28a68cfc..55011080a 100644 --- a/src/power/psp/SDL_syspower.c +++ b/src/power/psp/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/power/uikit/SDL_syspower.h b/src/power/uikit/SDL_syspower.h index 581c358df..7b0e52421 100644 --- a/src/power/uikit/SDL_syspower.h +++ b/src/power/uikit/SDL_syspower.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/power/uikit/SDL_syspower.m b/src/power/uikit/SDL_syspower.m index 60c42745a..2851c109f 100644 --- a/src/power/uikit/SDL_syspower.m +++ b/src/power/uikit/SDL_syspower.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -50,24 +50,24 @@ 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 @@ 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/power/windows/SDL_syspower.c b/src/power/windows/SDL_syspower.c index 0a247ba02..5c9e02402 100644 --- a/src/power/windows/SDL_syspower.c +++ b/src/power/windows/SDL_syspower.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/power/winrt/SDL_syspower.cpp b/src/power/winrt/SDL_syspower.cpp index 8804aec77..cce6bede8 100644 --- a/src/power/winrt/SDL_syspower.cpp +++ b/src/power/winrt/SDL_syspower.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_d3dmath.c b/src/render/SDL_d3dmath.c index 7c358a1e0..058b3af28 100644 --- a/src/render/SDL_d3dmath.c +++ b/src/render/SDL_d3dmath.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_d3dmath.h b/src/render/SDL_d3dmath.h index aa6c3fff8..34a226d5d 100644 --- a/src/render/SDL_d3dmath.h +++ b/src/render/SDL_d3dmath.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_render.c b/src/render/SDL_render.c index 4480d7152..088fe7ce8 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -165,7 +165,8 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) } } } else if (event->type == SDL_MOUSEMOTION) { - if (renderer->logical_w) { + SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); + if (renderer->logical_w && window == renderer->window) { event->motion.x -= renderer->viewport.x; event->motion.y -= renderer->viewport.y; event->motion.x = (int)(event->motion.x / renderer->scale.x); @@ -183,7 +184,8 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) } } else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) { - if (renderer->logical_w) { + SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); + if (renderer->logical_w && window == renderer->window) { event->button.x -= renderer->viewport.x; event->button.y -= renderer->viewport.y; event->button.x = (int)(event->button.x / renderer->scale.x); @@ -820,7 +822,9 @@ SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, rect = &full_rect; } - if (texture->yuv) { + if ((rect->w == 0) || (rect->h == 0)) { + return 0; /* nothing to do. */ + } else if (texture->yuv) { return SDL_UpdateTextureYUV(texture, rect, pixels, pitch); } else if (texture->native) { return SDL_UpdateTextureNative(texture, rect, pixels, pitch); @@ -1730,6 +1734,10 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, SDL_FRect frect; SDL_FPoint fcenter; + if (flip == SDL_FLIP_NONE && angle == 0) { /* fast path when we don't need rotation or flipping */ + return SDL_RenderCopy(renderer, texture, srcrect, dstrect); + } + CHECK_RENDERER_MAGIC(renderer, -1); CHECK_TEXTURE_MAGIC(texture, -1); diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index aba4bbb45..9c74ebbef 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_yuv_mmx.c b/src/render/SDL_yuv_mmx.c index e4ae4acbd..f9320bfbf 100644 --- a/src/render/SDL_yuv_mmx.c +++ b/src/render/SDL_yuv_mmx.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c index 4bd1856f4..a9ad87aa9 100644 --- a/src/render/SDL_yuv_sw.c +++ b/src/render/SDL_yuv_sw.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/SDL_yuv_sw_c.h b/src/render/SDL_yuv_sw_c.h index 6b4044b6d..3b3a266f3 100644 --- a/src/render/SDL_yuv_sw_c.h +++ b/src/render/SDL_yuv_sw_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index d96522e71..910ceb37c 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -843,7 +843,7 @@ D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture) HRESULT result; if (texture->staging == NULL) { - result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage, + result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0, PixelFormatToD3DFMT(texture->format), D3DPOOL_SYSTEMMEM, &texture->staging, NULL); if (FAILED(result)) { @@ -1269,10 +1269,10 @@ D3D_UpdateClipRect(SDL_Renderer * renderer) HRESULT result; IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE); - r.left = rect->x; - r.top = rect->y; - r.right = rect->x + rect->w; - r.bottom = rect->y + rect->h; + r.left = renderer->viewport.x + rect->x; + r.top = renderer->viewport.y + rect->y; + r.right = renderer->viewport.x + rect->x + rect->w; + r.bottom = renderer->viewport.y + rect->y + rect->h; result = IDirect3DDevice9_SetScissorRect(data->device, &r); if (result != D3D_OK) { diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index f99fdb1d5..78d67144f 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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: @@ -1341,7 +1356,7 @@ D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer * renderer) } static int -D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRect, D3D11_RECT * outRect) +D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRect, D3D11_RECT * outRect, BOOL includeViewportOffset) { D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer); @@ -1351,6 +1366,12 @@ D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRec outRect->right = sdlRect->x + sdlRect->w; outRect->top = sdlRect->y; outRect->bottom = sdlRect->y + sdlRect->h; + if (includeViewportOffset) { + outRect->left += renderer->viewport.x; + outRect->right += renderer->viewport.x; + outRect->top += renderer->viewport.y; + outRect->bottom += renderer->viewport.y; + } break; case DXGI_MODE_ROTATION_ROTATE270: outRect->left = sdlRect->y; @@ -2265,7 +2286,7 @@ D3D11_UpdateClipRect(SDL_Renderer * renderer) ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 0, NULL); } else { D3D11_RECT scissorRect; - if (D3D11_GetViewportAlignedD3DRect(renderer, &renderer->clip_rect, &scissorRect) != 0) { + if (D3D11_GetViewportAlignedD3DRect(renderer, &renderer->clip_rect, &scissorRect, TRUE) != 0) { /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ return -1; } @@ -2854,7 +2875,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, } /* Copy the desired portion of the back buffer to the staging texture: */ - if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect) != 0) { + if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect, FALSE) != 0) { /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ goto done; } @@ -2901,7 +2922,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/direct3d11/SDL_render_winrt.cpp b/src/render/direct3d11/SDL_render_winrt.cpp index 19c060f1c..991366628 100644 --- a/src/render/direct3d11/SDL_render_winrt.cpp +++ b/src/render/direct3d11/SDL_render_winrt.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/direct3d11/SDL_render_winrt.h b/src/render/direct3d11/SDL_render_winrt.h index 66a3220d8..5c76b70f8 100644 --- a/src/render/direct3d11/SDL_render_winrt.h +++ b/src/render/direct3d11/SDL_render_winrt.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/opengl/SDL_glfuncs.h b/src/render/opengl/SDL_glfuncs.h index fefbdd268..a9f38c436 100644 --- a/src/render/opengl/SDL_glfuncs.h +++ b/src/render/opengl/SDL_glfuncs.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index ecd0d531f..f5ac96d01 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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); } } @@ -1044,7 +1046,14 @@ GL_UpdateClipRect(SDL_Renderer * renderer) if (renderer->clipping_enabled) { const SDL_Rect *rect = &renderer->clip_rect; data->glEnable(GL_SCISSOR_TEST); - data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h); + if (renderer->target) { + data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h); + } else { + int w, h; + + SDL_GetRendererOutputSize(renderer, &w, &h); + data->glScissor(renderer->viewport.x + rect->x, (h - renderer->viewport.y - renderer->viewport.h) + rect->y, rect->w, rect->h); + } } else { data->glDisable(GL_SCISSOR_TEST); } diff --git a/src/render/opengl/SDL_shaders_gl.c b/src/render/opengl/SDL_shaders_gl.c index a831890ca..f08855238 100644 --- a/src/render/opengl/SDL_shaders_gl.c +++ b/src/render/opengl/SDL_shaders_gl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/opengl/SDL_shaders_gl.h b/src/render/opengl/SDL_shaders_gl.h index 4604f05f7..1b2e4a5a3 100644 --- a/src/render/opengl/SDL_shaders_gl.h +++ b/src/render/opengl/SDL_shaders_gl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/opengles/SDL_glesfuncs.h b/src/render/opengles/SDL_glesfuncs.h index 6dc197a63..4eb72d6bc 100644 --- a/src/render/opengles/SDL_glesfuncs.h +++ b/src/render/opengles/SDL_glesfuncs.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/opengles/SDL_render_gles.c b/src/render/opengles/SDL_render_gles.c index 72cce305a..21c22bfd7 100644 --- a/src/render/opengles/SDL_render_gles.c +++ b/src/render/opengles/SDL_render_gles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -43,7 +43,7 @@ glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) return; } -#endif /* PANDORA */ +#endif /* SDL_VIDEO_DRIVER_PANDORA */ /* OpenGL ES 1.1 renderer implementation, based on the OpenGL renderer */ @@ -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, @@ -205,7 +206,7 @@ static int GLES_LoadFunctions(GLES_RenderData * data) do { \ data->func = SDL_GL_GetProcAddress(#func); \ } while ( 0 ); -#endif /* _SDL_NOGETPROCADDR_ */ +#endif /* __SDL_NOGETPROCADDR__ */ #include "SDL_glesfuncs.h" #undef SDL_PROC @@ -219,12 +220,10 @@ GLES_FBOList * GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h) { GLES_FBOList *result = data->framebuffers; - while ((result) && ((result->w != w) || (result->h != h)) ) - { + while ((result) && ((result->w != w) || (result->h != h)) ) { result = result->next; } - if (result == NULL) - { + if (result == NULL) { result = SDL_malloc(sizeof(GLES_FBOList)); result->w = w; result->h = h; @@ -321,6 +320,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 +438,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) { @@ -563,8 +570,9 @@ GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, GLES_ActivateRenderer(renderer); /* Bail out if we're supposed to update an empty rectangle */ - if (rect->w <= 0 || rect->h <= 0) + if (rect->w <= 0 || rect->h <= 0) { return 0; + } /* Reformat the texture data into a tightly packed array */ srcPitch = rect->w * SDL_BYTESPERPIXEL(texture->format); @@ -599,8 +607,7 @@ GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, src); SDL_free(blob); - if (renderdata->glGetError() != GL_NO_ERROR) - { + if (renderdata->glGetError() != GL_NO_ERROR) { return SDL_SetError("Failed to update texture"); } return 0; @@ -641,7 +648,7 @@ GLES_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) GLenum status; GLES_ActivateRenderer(renderer); - + if (!data->GL_OES_framebuffer_object_supported) { return SDL_SetError("Can't enable render target support in this renderer"); } @@ -673,8 +680,16 @@ GLES_UpdateViewport(SDL_Renderer * renderer) return 0; } - data->glViewport(renderer->viewport.x, renderer->viewport.y, - renderer->viewport.w, renderer->viewport.h); + if (renderer->target) { + data->glViewport(renderer->viewport.x, renderer->viewport.y, + renderer->viewport.w, renderer->viewport.h); + } else { + int w, h; + + SDL_GetRendererOutputSize(renderer, &w, &h); + data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h), + renderer->viewport.w, renderer->viewport.h); + } if (renderer->viewport.w && renderer->viewport.h) { data->glMatrixMode(GL_PROJECTION); @@ -700,7 +715,14 @@ GLES_UpdateClipRect(SDL_Renderer * renderer) if (renderer->clipping_enabled) { const SDL_Rect *rect = &renderer->clip_rect; data->glEnable(GL_SCISSOR_TEST); - data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h); + if (renderer->target) { + data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h); + } else { + int w, h; + + SDL_GetRendererOutputSize(renderer, &w, &h); + data->glScissor(renderer->viewport.x + rect->x, (h - renderer->viewport.y - renderer->viewport.h) + rect->y, rect->w, rect->h); + } } else { data->glDisable(GL_SCISSOR_TEST); } @@ -1197,8 +1219,12 @@ static int GLES_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, floa data->glEnable(GL_TEXTURE_2D); data->glBindTexture(texturedata->type, texturedata->texture); - if(texw) *texw = (float)texturedata->texw; - if(texh) *texh = (float)texturedata->texh; + if (texw) { + *texw = (float)texturedata->texw; + } + if (texh) { + *texh = (float)texturedata->texh; + } return 0; } diff --git a/src/render/opengles2/SDL_gles2funcs.h b/src/render/opengles2/SDL_gles2funcs.h index 2c02cdd13..36dcf7424 100644 --- a/src/render/opengles2/SDL_gles2funcs.h +++ b/src/render/opengles2/SDL_gles2funcs.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..7254cb7a3 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 @@ -206,8 +224,7 @@ GL_ClearErrors(SDL_Renderer *renderer) { GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; - if (!data->debug_enabled) - { + if (!data->debug_enabled) { return; } while (data->glGetError() != GL_NO_ERROR) { @@ -221,8 +238,7 @@ GL_CheckAllErrors (const char *prefix, SDL_Renderer *renderer, const char *file, GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata; int ret = 0; - if (!data->debug_enabled) - { + if (!data->debug_enabled) { return 0; } /* check gl errors (can return multiple errors) */ @@ -284,7 +300,7 @@ static int GLES2_LoadFunctions(GLES2_DriverContext * data) return SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \ } \ } while ( 0 ); -#endif /* _SDL_NOGETPROCADDR_ */ +#endif /* __SDL_NOGETPROCADDR__ */ #include "SDL_gles2funcs.h" #undef SDL_PROC @@ -295,12 +311,10 @@ GLES2_FBOList * GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h) { GLES2_FBOList *result = data->framebuffers; - while ((result) && ((result->w != w) || (result->h != h)) ) - { + while ((result) && ((result->w != w) || (result->h != h)) ) { result = result->next; } - if (result == NULL) - { + if (result == NULL) { result = SDL_malloc(sizeof(GLES2_FBOList)); result->w = w; result->h = h; @@ -351,6 +365,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) { @@ -361,8 +382,16 @@ GLES2_UpdateViewport(SDL_Renderer * renderer) return 0; } - data->glViewport(renderer->viewport.x, renderer->viewport.y, - renderer->viewport.w, renderer->viewport.h); + if (renderer->target) { + data->glViewport(renderer->viewport.x, renderer->viewport.y, + renderer->viewport.w, renderer->viewport.h); + } else { + int w, h; + + SDL_GetRendererOutputSize(renderer, &w, &h); + data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h), + renderer->viewport.w, renderer->viewport.h); + } if (data->current_program) { GLES2_SetOrthographicProjection(renderer); @@ -383,7 +412,14 @@ GLES2_UpdateClipRect(SDL_Renderer * renderer) if (renderer->clipping_enabled) { const SDL_Rect *rect = &renderer->clip_rect; data->glEnable(GL_SCISSOR_TEST); - data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h); + if (renderer->target) { + data->glScissor(renderer->viewport.x + rect->x, renderer->viewport.y + rect->y, rect->w, rect->h); + } else { + int w, h; + + SDL_GetRendererOutputSize(renderer, &w, &h); + data->glScissor(renderer->viewport.x + rect->x, (h - renderer->viewport.y - renderer->viewport.h) + rect->y, rect->w, rect->h); + } } else { data->glDisable(GL_SCISSOR_TEST); } @@ -403,8 +439,7 @@ GLES2_DestroyRenderer(SDL_Renderer *renderer) GLES2_ShaderCacheEntry *entry; GLES2_ShaderCacheEntry *next; entry = data->shader_cache.head; - while (entry) - { + while (entry) { data->glDeleteShader(entry->id); next = entry->next; SDL_free(entry); @@ -652,8 +687,9 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect GLES2_ActivateRenderer(renderer); /* Bail out if we're supposed to update an empty rectangle */ - if (rect->w <= 0 || rect->h <= 0) + if (rect->w <= 0 || rect->h <= 0) { return 0; + } /* Create a texture subimage with the supplied data */ data->glBindTexture(tdata->texture_type, tdata->texture); @@ -730,8 +766,9 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, GLES2_ActivateRenderer(renderer); /* Bail out if we're supposed to update an empty rectangle */ - if (rect->w <= 0 || rect->h <= 0) + if (rect->w <= 0 || rect->h <= 0) { return 0; + } data->glBindTexture(tdata->texture_type, tdata->texture_v); GLES2_TexSubImage2D(data, tdata->texture_type, @@ -827,8 +864,7 @@ GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) GLES2_ActivateRenderer(renderer); /* Destroy the texture */ - if (tdata) - { + if (tdata) { data->glDeleteTextures(1, &tdata->texture); if (tdata->texture_v) { data->glDeleteTextures(1, &tdata->texture_v); @@ -867,20 +903,20 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, /* Check if we've already cached this program */ entry = data->program_cache.head; - while (entry) - { - if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) + while (entry) { + if (entry->vertex_shader == vertex && entry->fragment_shader == fragment) { break; + } entry = entry->next; } - if (entry) - { - if (data->program_cache.head != entry) - { - if (entry->next) + if (entry) { + if (data->program_cache.head != entry) { + if (entry->next) { entry->next->prev = entry->prev; - if (entry->prev) + } + if (entry->prev) { entry->prev->next = entry->next; + } entry->prev = NULL; entry->next = data->program_cache.head; data->program_cache.head->prev = entry; @@ -891,8 +927,7 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, /* Create a program cache entry */ entry = (GLES2_ProgramCacheEntry *)SDL_calloc(1, sizeof(GLES2_ProgramCacheEntry)); - if (!entry) - { + if (!entry) { SDL_OutOfMemory(); return NULL; } @@ -910,8 +945,7 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, data->glBindAttribLocation(entry->id, GLES2_ATTRIBUTE_CENTER, "a_center"); data->glLinkProgram(entry->id); data->glGetProgramiv(entry->id, GL_LINK_STATUS, &linkSuccessful); - if (!linkSuccessful) - { + if (!linkSuccessful) { data->glDeleteProgram(entry->id); SDL_free(entry); SDL_SetError("Failed to link shader program"); @@ -944,13 +978,10 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, data->glUniform4f(entry->uniform_locations[GLES2_UNIFORM_COLOR], 1.0f, 1.0f, 1.0f, 1.0f); /* Cache the linked program */ - if (data->program_cache.head) - { + if (data->program_cache.head) { entry->next = data->program_cache.head; data->program_cache.head->prev = entry; - } - else - { + } else { data->program_cache.tail = entry; } data->program_cache.head = entry; @@ -961,14 +992,15 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex, ++fragment->references; /* Evict the last entry from the cache if we exceed the limit */ - if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) - { + if (data->program_cache.count > GLES2_MAX_CACHED_PROGRAMS) { shaderEntry = data->program_cache.tail->vertex_shader; - if (--shaderEntry->references <= 0) + if (--shaderEntry->references <= 0) { GLES2_EvictShader(renderer, shaderEntry); + } shaderEntry = data->program_cache.tail->fragment_shader; - if (--shaderEntry->references <= 0) + if (--shaderEntry->references <= 0) { GLES2_EvictShader(renderer, shaderEntry); + } data->glDeleteProgram(data->program_cache.tail->id); data->program_cache.tail = data->program_cache.tail->prev; SDL_free(data->program_cache.tail->next); @@ -990,47 +1022,43 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode b /* Find the corresponding shader */ shader = GLES2_GetShader(type, blendMode); - if (!shader) - { + if (!shader) { SDL_SetError("No shader matching the requested characteristics was found"); return NULL; } /* Find a matching shader instance that's supported on this hardware */ - for (i = 0; i < shader->instance_count && !instance; ++i) - { - for (j = 0; j < data->shader_format_count && !instance; ++j) - { - if (!shader->instances) - continue; - if (!shader->instances[i]) + for (i = 0; i < shader->instance_count && !instance; ++i) { + for (j = 0; j < data->shader_format_count && !instance; ++j) { + if (!shader->instances[i]) { continue; - if (shader->instances[i]->format != data->shader_formats[j]) + } + if (shader->instances[i]->format != data->shader_formats[j]) { continue; + } instance = shader->instances[i]; } } - if (!instance) - { + if (!instance) { SDL_SetError("The specified shader cannot be loaded on the current platform"); return NULL; } /* Check if we've already cached this shader */ entry = data->shader_cache.head; - while (entry) - { - if (entry->instance == instance) + while (entry) { + if (entry->instance == instance) { break; + } entry = entry->next; } - if (entry) + if (entry) { return entry; + } /* Create a shader cache entry */ entry = (GLES2_ShaderCacheEntry *)SDL_calloc(1, sizeof(GLES2_ShaderCacheEntry)); - if (!entry) - { + if (!entry) { SDL_OutOfMemory(); return NULL; } @@ -1039,19 +1067,15 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode b /* Compile or load the selected shader instance */ entry->id = data->glCreateShader(instance->type); - if (instance->format == (GLenum)-1) - { + if (instance->format == (GLenum)-1) { data->glShaderSource(entry->id, 1, (const char **)&instance->data, NULL); data->glCompileShader(entry->id); data->glGetShaderiv(entry->id, GL_COMPILE_STATUS, &compileSuccessful); - } - else - { + } else { data->glShaderBinary(1, &entry->id, instance->format, instance->data, instance->length); compileSuccessful = GL_TRUE; } - if (!compileSuccessful) - { + if (!compileSuccessful) { char *info = NULL; int length = 0; @@ -1074,8 +1098,7 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode b } /* Link the shader entry in at the front of the cache */ - if (data->shader_cache.head) - { + if (data->shader_cache.head) { entry->next = data->shader_cache.head; data->shader_cache.head->prev = entry; } @@ -1090,12 +1113,15 @@ GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry) GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; /* Unlink the shader from the cache */ - if (entry->next) + if (entry->next) { entry->next->prev = entry->prev; - if (entry->prev) + } + if (entry->prev) { entry->prev->next = entry->next; - if (data->shader_cache.head == entry) + } + if (data->shader_cache.head == entry) { data->shader_cache.head = entry->next; + } --data->shader_cache.count; /* Deallocate the shader */ @@ -1114,8 +1140,7 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendM /* Select an appropriate shader pair for the specified modes */ vtype = GLES2_SHADER_VERTEX_DEFAULT; - switch (source) - { + switch (source) { case GLES2_IMAGESOURCE_SOLID: ftype = GLES2_SHADER_FRAGMENT_SOLID_SRC; break; @@ -1146,22 +1171,26 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendM /* Load the requested shaders */ vertex = GLES2_CacheShader(renderer, vtype, blendMode); - if (!vertex) + if (!vertex) { goto fault; + } fragment = GLES2_CacheShader(renderer, ftype, blendMode); - if (!fragment) + if (!fragment) { goto fault; + } /* Check if we need to change programs at all */ if (data->current_program && data->current_program->vertex_shader == vertex && - data->current_program->fragment_shader == fragment) + data->current_program->fragment_shader == fragment) { return 0; + } /* Generate a matching program */ program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode); - if (!program) + if (!program) { goto fault; + } /* Select that program in OpenGL */ data->glUseProgram(program->id); @@ -1170,16 +1199,19 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendM data->current_program = program; /* Activate an orthographic projection */ - if (GLES2_SetOrthographicProjection(renderer) < 0) + if (GLES2_SetOrthographicProjection(renderer) < 0) { goto fault; + } /* Clean up and return */ return 0; fault: - if (vertex && vertex->references <= 0) + if (vertex && vertex->references <= 0) { GLES2_EvictShader(renderer, vertex); - if (fragment && fragment->references <= 0) + } + if (fragment && fragment->references <= 0) { GLES2_EvictShader(renderer, fragment); + } data->current_program = NULL; return -1; } @@ -1385,6 +1417,34 @@ 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 +1465,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 +1492,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 +1534,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); @@ -1493,58 +1556,53 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture) if (renderer->target) { /* Check if we need to do color mapping between the source and render target textures */ if (renderer->target->format != texture->format) { - switch (texture->format) - { + switch (texture->format) { case SDL_PIXELFORMAT_ARGB8888: - switch (renderer->target->format) - { - case SDL_PIXELFORMAT_ABGR8888: - case SDL_PIXELFORMAT_BGR888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; - break; - case SDL_PIXELFORMAT_RGB888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; - break; + switch (renderer->target->format) { + case SDL_PIXELFORMAT_ABGR8888: + case SDL_PIXELFORMAT_BGR888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; + break; + case SDL_PIXELFORMAT_RGB888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; + break; } break; case SDL_PIXELFORMAT_ABGR8888: - switch (renderer->target->format) - { - case SDL_PIXELFORMAT_ARGB8888: - case SDL_PIXELFORMAT_RGB888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; - break; - case SDL_PIXELFORMAT_BGR888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; - break; + switch (renderer->target->format) { + case SDL_PIXELFORMAT_ARGB8888: + case SDL_PIXELFORMAT_RGB888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; + break; + case SDL_PIXELFORMAT_BGR888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; + break; } break; case SDL_PIXELFORMAT_RGB888: - switch (renderer->target->format) - { - case SDL_PIXELFORMAT_ABGR8888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; - break; - case SDL_PIXELFORMAT_ARGB8888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; - break; - case SDL_PIXELFORMAT_BGR888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; - break; + switch (renderer->target->format) { + case SDL_PIXELFORMAT_ABGR8888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; + break; + case SDL_PIXELFORMAT_ARGB8888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; + break; + case SDL_PIXELFORMAT_BGR888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; + break; } break; case SDL_PIXELFORMAT_BGR888: - switch (renderer->target->format) - { - case SDL_PIXELFORMAT_ABGR8888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; - break; - case SDL_PIXELFORMAT_ARGB8888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; - break; - case SDL_PIXELFORMAT_RGB888: - sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; - break; + switch (renderer->target->format) { + case SDL_PIXELFORMAT_ABGR8888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; + break; + case SDL_PIXELFORMAT_ARGB8888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB; + break; + case SDL_PIXELFORMAT_RGB888: + sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; + break; } break; case SDL_PIXELFORMAT_IYUV: @@ -1560,11 +1618,11 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture) default: return SDL_SetError("Unsupported texture format"); } + } else { + sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */ } - else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; /* Texture formats match, use the non color mapping shader (even if the formats are not ABGR) */ } else { - switch (texture->format) - { + switch (texture->format) { case SDL_PIXELFORMAT_ARGB8888: sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB; break; @@ -1668,7 +1726,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 +1736,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 +1787,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 +1803,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); @@ -1822,8 +1887,12 @@ static int GLES2_BindTexture (SDL_Renderer * renderer, SDL_Texture *texture, flo data->glBindTexture(texturedata->texture_type, texturedata->texture); - if(texw) *texw = 1.0; - if(texh) *texh = 1.0; + if (texw) { + *texw = 1.0; + } + if (texh) { + *texh = 1.0; + } return 0; } @@ -1979,12 +2048,12 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) #else /* !ZUNE_HD */ data->glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &nFormats); data->glGetBooleanv(GL_SHADER_COMPILER, &hasCompiler); - if (hasCompiler) + if (hasCompiler) { ++nFormats; + } #endif /* ZUNE_HD */ data->shader_formats = (GLenum *)SDL_calloc(nFormats, sizeof(GLenum)); - if (!data->shader_formats) - { + if (!data->shader_formats) { GLES2_DestroyRenderer(renderer); SDL_OutOfMemory(); goto error; @@ -1994,8 +2063,9 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) data->shader_formats[0] = GL_NVIDIA_PLATFORM_BINARY_NV; #else /* !ZUNE_HD */ data->glGetIntegerv(GL_SHADER_BINARY_FORMATS, (GLint *)data->shader_formats); - if (hasCompiler) + if (hasCompiler) { data->shader_formats[nFormats - 1] = (GLenum)-1; + } #endif /* ZUNE_HD */ data->framebuffers = NULL; @@ -2004,6 +2074,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/opengles2/SDL_shaders_gles2.c b/src/render/opengles2/SDL_shaders_gles2.c index 48040f968..6f650811a 100644 --- a/src/render/opengles2/SDL_shaders_gles2.c +++ b/src/render/opengles2/SDL_shaders_gles2.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -810,13 +810,11 @@ static GLES2_Shader GLES2_FragmentShader_TextureNV21Src = { const GLES2_Shader *GLES2_GetShader(GLES2_ShaderType type, SDL_BlendMode blendMode) { - switch (type) - { + switch (type) { case GLES2_SHADER_VERTEX_DEFAULT: return &GLES2_VertexShader_Default; case GLES2_SHADER_FRAGMENT_SOLID_SRC: - switch (blendMode) - { + switch (blendMode) { case SDL_BLENDMODE_NONE: return &GLES2_FragmentShader_None_SolidSrc; case SDL_BLENDMODE_BLEND: @@ -829,8 +827,7 @@ const GLES2_Shader *GLES2_GetShader(GLES2_ShaderType type, SDL_BlendMode blendMo return NULL; } case GLES2_SHADER_FRAGMENT_TEXTURE_ABGR_SRC: - switch (blendMode) - { + switch (blendMode) { case SDL_BLENDMODE_NONE: return &GLES2_FragmentShader_None_TextureABGRSrc; case SDL_BLENDMODE_BLEND: @@ -843,8 +840,7 @@ const GLES2_Shader *GLES2_GetShader(GLES2_ShaderType type, SDL_BlendMode blendMo return NULL; } case GLES2_SHADER_FRAGMENT_TEXTURE_ARGB_SRC: - switch (blendMode) - { + switch (blendMode) { case SDL_BLENDMODE_NONE: return &GLES2_FragmentShader_None_TextureARGBSrc; case SDL_BLENDMODE_BLEND: @@ -858,8 +854,7 @@ const GLES2_Shader *GLES2_GetShader(GLES2_ShaderType type, SDL_BlendMode blendMo } case GLES2_SHADER_FRAGMENT_TEXTURE_RGB_SRC: - switch (blendMode) - { + switch (blendMode) { case SDL_BLENDMODE_NONE: return &GLES2_FragmentShader_None_TextureRGBSrc; case SDL_BLENDMODE_BLEND: @@ -873,8 +868,7 @@ const GLES2_Shader *GLES2_GetShader(GLES2_ShaderType type, SDL_BlendMode blendMo } case GLES2_SHADER_FRAGMENT_TEXTURE_BGR_SRC: - switch (blendMode) - { + switch (blendMode) { case SDL_BLENDMODE_NONE: return &GLES2_FragmentShader_None_TextureBGRSrc; case SDL_BLENDMODE_BLEND: diff --git a/src/render/opengles2/SDL_shaders_gles2.h b/src/render/opengles2/SDL_shaders_gles2.h index d68f7d05c..f22c8f56b 100644 --- a/src/render/opengles2/SDL_shaders_gles2.h +++ b/src/render/opengles2/SDL_shaders_gles2.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index cdd13e822..39a2eab6a 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/render/software/SDL_blendfillrect.c b/src/render/software/SDL_blendfillrect.c index cb184d634..669422f77 100644 --- a/src/render/software/SDL_blendfillrect.c +++ b/src/render/software/SDL_blendfillrect.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_blendfillrect.h b/src/render/software/SDL_blendfillrect.h index 297c839e1..b612db24c 100644 --- a/src/render/software/SDL_blendfillrect.h +++ b/src/render/software/SDL_blendfillrect.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_blendline.c b/src/render/software/SDL_blendline.c index 02d748d5f..b2090b137 100644 --- a/src/render/software/SDL_blendline.c +++ b/src/render/software/SDL_blendline.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_blendline.h b/src/render/software/SDL_blendline.h index 14a7c18a5..602cafd6c 100644 --- a/src/render/software/SDL_blendline.h +++ b/src/render/software/SDL_blendline.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_blendpoint.c b/src/render/software/SDL_blendpoint.c index dab135600..47243794b 100644 --- a/src/render/software/SDL_blendpoint.c +++ b/src/render/software/SDL_blendpoint.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_blendpoint.h b/src/render/software/SDL_blendpoint.h index 72eaf7b87..7045326a7 100644 --- a/src/render/software/SDL_blendpoint.h +++ b/src/render/software/SDL_blendpoint.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_draw.h b/src/render/software/SDL_draw.h index 2bd8f94c9..e2822427c 100644 --- a/src/render/software/SDL_draw.h +++ b/src/render/software/SDL_draw.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_drawline.c b/src/render/software/SDL_drawline.c index 1ff84a46d..e76c3f40e 100644 --- a/src/render/software/SDL_drawline.c +++ b/src/render/software/SDL_drawline.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_drawline.h b/src/render/software/SDL_drawline.h index e3378ae8f..e2dafeae2 100644 --- a/src/render/software/SDL_drawline.h +++ b/src/render/software/SDL_drawline.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_drawpoint.c b/src/render/software/SDL_drawpoint.c index 3f2de86c1..38ea4b740 100644 --- a/src/render/software/SDL_drawpoint.c +++ b/src/render/software/SDL_drawpoint.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_drawpoint.h b/src/render/software/SDL_drawpoint.h index 96933d616..d26c2b58b 100644 --- a/src/render/software/SDL_drawpoint.h +++ b/src/render/software/SDL_drawpoint.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index 37f42f072..119b20015 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -253,6 +253,12 @@ static int SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support + * color mod) to avoid potentially frequent RLE encoding/decoding. + */ + if ((texture->r & texture->g & texture->b) != 255) { + SDL_SetSurfaceRLE(surface, 0); + } return SDL_SetSurfaceColorMod(surface, texture->r, texture->g, texture->b); } @@ -261,6 +267,12 @@ static int SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently + * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding. + */ + if (texture->a != 255 && surface->format->Amask) { + SDL_SetSurfaceRLE(surface, 0); + } return SDL_SetSurfaceAlphaMod(surface, texture->a); } @@ -268,6 +280,12 @@ static int SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_Surface *surface = (SDL_Surface *) texture->driverdata; + /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support + * them) to avoid potentially frequent RLE encoding/decoding. + */ + if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) { + SDL_SetSurfaceRLE(surface, 0); + } return SDL_SetSurfaceBlendMode(surface, texture->blendMode); } @@ -553,6 +571,10 @@ SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) { return SDL_BlitSurface(src, srcrect, surface, &final_rect); } else { + /* If scaling is ever done, permanently disable RLE (which doesn't support scaling) + * to avoid potentially frequent RLE encoding/decoding. + */ + SDL_SetSurfaceRLE(surface, 0); return SDL_BlitScaled(src, srcrect, surface, &final_rect); } } @@ -578,7 +600,6 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect final_rect, tmp_rect; SDL_Surface *surface_rotated, *surface_scaled; - Uint32 colorkey; int retval, dstwidth, dstheight, abscenterx, abscentery; double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; @@ -596,66 +617,113 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, final_rect.w = (int)dstrect->w; final_rect.h = (int)dstrect->h; - surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel, - src->format->Rmask, src->format->Gmask, - src->format->Bmask, src->format->Amask ); - if (surface_scaled) { - SDL_GetColorKey(src, &colorkey); - SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey); - tmp_rect = final_rect; - tmp_rect.x = 0; - tmp_rect.y = 0; - - retval = SDL_BlitScaled(src, srcrect, surface_scaled, &tmp_rect); - if (!retval) { - SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle); - surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle); - if(surface_rotated) { - /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */ - abscenterx = final_rect.x + (int)center->x; - abscentery = final_rect.y + (int)center->y; - /* Compensate the angle inversion to match the behaviour of the other backends */ - sangle = -sangle; - - /* Top Left */ - px = final_rect.x - abscenterx; - py = final_rect.y - abscentery; - p1x = px * cangle - py * sangle + abscenterx; - p1y = px * sangle + py * cangle + abscentery; - - /* Top Right */ - px = final_rect.x + final_rect.w - abscenterx; - py = final_rect.y - abscentery; - p2x = px * cangle - py * sangle + abscenterx; - p2y = px * sangle + py * cangle + abscentery; - - /* Bottom Left */ - px = final_rect.x - abscenterx; - py = final_rect.y + final_rect.h - abscentery; - p3x = px * cangle - py * sangle + abscenterx; - p3y = px * sangle + py * cangle + abscentery; - - /* Bottom Right */ - px = final_rect.x + final_rect.w - abscenterx; - py = final_rect.y + final_rect.h - abscentery; - p4x = px * cangle - py * sangle + abscenterx; - p4y = px * sangle + py * cangle + abscentery; - - tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x)); - tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y)); - tmp_rect.w = dstwidth; - tmp_rect.h = dstheight; - - retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect); + /* SDLgfx_rotateSurface doesn't accept a source rectangle, so crop and scale if we need to */ + tmp_rect = final_rect; + tmp_rect.x = 0; + tmp_rect.y = 0; + if (srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0) { + surface_scaled = src; /* but if we don't need to, just use the original */ + retval = 0; + } else { + SDL_Surface *blit_src = src; + Uint32 colorkey; + SDL_BlendMode blendMode; + Uint8 alphaMod, r, g, b; + SDL_bool cloneSource = SDL_FALSE; + + surface_scaled = SDL_CreateRGBSurface(SDL_SWSURFACE, final_rect.w, final_rect.h, src->format->BitsPerPixel, + src->format->Rmask, src->format->Gmask, + src->format->Bmask, src->format->Amask ); + if (!surface_scaled) { + return -1; + } + + /* copy the color key, alpha mod, blend mode, and color mod so the scaled surface behaves like the source */ + if (SDL_GetColorKey(src, &colorkey) == 0) { + SDL_SetColorKey(surface_scaled, SDL_TRUE, colorkey); + cloneSource = SDL_TRUE; + } + SDL_GetSurfaceAlphaMod(src, &alphaMod); /* these will be copied to surface_scaled below if necessary */ + SDL_GetSurfaceBlendMode(src, &blendMode); + SDL_GetSurfaceColorMod(src, &r, &g, &b); + + /* now we need to blit the src into surface_scaled. since we want to copy the colors from the source to + * surface_scaled rather than blend them, etc. we'll need to disable the blend mode, alpha mod, etc. + * but we don't want to modify src (in case it's being used on other threads), so we'll need to clone it + * before changing the blend options + */ + cloneSource |= blendMode != SDL_BLENDMODE_NONE || (alphaMod & r & g & b) != 255; + if (cloneSource) { + blit_src = SDL_ConvertSurface(src, src->format, src->flags); /* clone src */ + if (!blit_src) { SDL_FreeSurface(surface_scaled); - SDL_FreeSurface(surface_rotated); - return retval; + return -1; } + SDL_SetSurfaceAlphaMod(blit_src, 255); /* disable all blending options in blit_src */ + SDL_SetSurfaceBlendMode(blit_src, SDL_BLENDMODE_NONE); + SDL_SetColorKey(blit_src, 0, 0); + SDL_SetSurfaceColorMod(blit_src, 255, 255, 255); + SDL_SetSurfaceRLE(blit_src, 0); /* don't RLE encode a surface we'll only use once */ + + SDL_SetSurfaceAlphaMod(surface_scaled, alphaMod); /* copy blending options to surface_scaled */ + SDL_SetSurfaceBlendMode(surface_scaled, blendMode); + SDL_SetSurfaceColorMod(surface_scaled, r, g, b); + } + + retval = SDL_BlitScaled(blit_src, srcrect, surface_scaled, &tmp_rect); + if (blit_src != src) { + SDL_FreeSurface(blit_src); + } + } + + if (!retval) { + SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, -angle, &dstwidth, &dstheight, &cangle, &sangle); + surface_rotated = SDLgfx_rotateSurface(surface_scaled, -angle, dstwidth/2, dstheight/2, GetScaleQuality(), flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle); + if(surface_rotated) { + /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */ + abscenterx = final_rect.x + (int)center->x; + abscentery = final_rect.y + (int)center->y; + /* Compensate the angle inversion to match the behaviour of the other backends */ + sangle = -sangle; + + /* Top Left */ + px = final_rect.x - abscenterx; + py = final_rect.y - abscentery; + p1x = px * cangle - py * sangle + abscenterx; + p1y = px * sangle + py * cangle + abscentery; + + /* Top Right */ + px = final_rect.x + final_rect.w - abscenterx; + py = final_rect.y - abscentery; + p2x = px * cangle - py * sangle + abscenterx; + p2y = px * sangle + py * cangle + abscentery; + + /* Bottom Left */ + px = final_rect.x - abscenterx; + py = final_rect.y + final_rect.h - abscentery; + p3x = px * cangle - py * sangle + abscenterx; + p3y = px * sangle + py * cangle + abscentery; + + /* Bottom Right */ + px = final_rect.x + final_rect.w - abscenterx; + py = final_rect.y + final_rect.h - abscentery; + p4x = px * cangle - py * sangle + abscenterx; + p4y = px * sangle + py * cangle + abscentery; + + tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x)); + tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y)); + tmp_rect.w = dstwidth; + tmp_rect.h = dstheight; + + retval = SDL_BlitSurface(surface_rotated, NULL, surface, &tmp_rect); + SDL_FreeSurface(surface_rotated); } - return retval; } - return -1; + if (surface_scaled != src) { + SDL_FreeSurface(surface_scaled); + } + return retval; } static int diff --git a/src/render/software/SDL_render_sw_c.h b/src/render/software/SDL_render_sw_c.h index 81cb656c9..df1a64734 100644 --- a/src/render/software/SDL_render_sw_c.h +++ b/src/render/software/SDL_render_sw_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/render/software/SDL_rotate.c b/src/render/software/SDL_rotate.c index 0edf784cd..8d92758f8 100644 --- a/src/render/software/SDL_rotate.c +++ b/src/render/software/SDL_rotate.c @@ -188,10 +188,8 @@ _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int dy = (sdy >> 16); if (flipx) dx = sw - dx; if (flipy) dy = sh - dy; - if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) { - sp = (tColorRGBA *)src->pixels; - sp += ((src->pitch/4) * dy); - sp += dx; + if ((unsigned)dx < (unsigned)sw && (unsigned)dy < (unsigned)sh) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy) + dx; c00 = *sp; sp += 1; c01 = *sp; @@ -237,14 +235,12 @@ _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int sdx = (ax + (isin * dy)) + xd; sdy = (ay - (icos * dy)) + yd; for (x = 0; x < dst->w; x++) { - dx = (short) (sdx >> 16); - dy = (short) (sdy >> 16); - if (flipx) dx = (src->w-1)-dx; - if (flipy) dy = (src->h-1)-dy; - if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { - sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); - sp += dx; - *pc = *sp; + dx = (sdx >> 16); + dy = (sdy >> 16); + if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { + if(flipx) dx = sw - dx; + if(flipy) dy = sh - dy; + *pc = *((tColorRGBA *)((Uint8 *)src->pixels + src->pitch * dy) + dx); } sdx += icos; sdy += isin; @@ -277,7 +273,7 @@ static void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy) { int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay; - tColorY *pc, *sp; + tColorY *pc; int gap; /* @@ -301,14 +297,12 @@ transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin sdx = (ax + (isin * dy)) + xd; sdy = (ay - (icos * dy)) + yd; for (x = 0; x < dst->w; x++) { - dx = (short) (sdx >> 16); - dy = (short) (sdy >> 16); - if (flipx) dx = (src->w-1)-dx; - if (flipy) dy = (src->h-1)-dy; - if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { - sp = (tColorY *) (src->pixels); - sp += (src->pitch * dy + dx); - *pc = *sp; + dx = (sdx >> 16); + dy = (sdy >> 16); + if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { + if (flipx) dx = (src->w-1)-dx; + if (flipy) dy = (src->h-1)-dy; + *pc = *((tColorY *)src->pixels + src->pitch * dy + dx); } sdx += icos; sdy += isin; @@ -348,7 +342,7 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, SDL_Surface *rz_src; SDL_Surface *rz_dst; int is32bit; - int i, src_converted; + int i; Uint8 r,g,b; Uint32 colorkey = 0; int colorKeyAvailable = 0; @@ -375,27 +369,15 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, * Use source surface 'as is' */ rz_src = src; - src_converted = 0; } else { - /* - * New source surface is 32bit with a defined RGBA ordering - */ - rz_src = - SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, + Uint32 format = SDL_MasksToPixelFormatEnum(32, #if SDL_BYTEORDER == SDL_LIL_ENDIAN 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 #else 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff #endif - ); - if(colorKeyAvailable) - SDL_SetColorKey(src, 0, 0); - - SDL_BlitSurface(src, NULL, rz_src, NULL); - - if(colorKeyAvailable) - SDL_SetColorKey(src, SDL_TRUE /* SDL_SRCCOLORKEY */, colorkey); - src_converted = 1; + ); + rz_src = SDL_ConvertSurfaceFormat(src, format, src->flags); is32bit = 1; } @@ -480,6 +462,19 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, flipx, flipy); SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src)); } + + /* copy alpha mod, color mod, and blend mode */ + { + SDL_BlendMode blendMode; + Uint8 alphaMod, cr, cg, cb; + SDL_GetSurfaceAlphaMod(src, &alphaMod); + SDL_GetSurfaceBlendMode(src, &blendMode); + SDL_GetSurfaceColorMod(src, &cr, &cg, &cb); + SDL_SetSurfaceAlphaMod(rz_dst, alphaMod); + SDL_SetSurfaceBlendMode(rz_dst, blendMode); + SDL_SetSurfaceColorMod(rz_dst, cr, cg, cb); + } + /* * Unlock source surface */ @@ -490,7 +485,7 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Cleanup temp surface */ - if (src_converted) { + if (rz_src != src) { SDL_FreeSurface(rz_src); } diff --git a/src/render/software/SDL_rotate.h b/src/render/software/SDL_rotate.h index e92c3b77f..01ceb2d84 100644 --- a/src/render/software/SDL_rotate.h +++ b/src/render/software/SDL_rotate.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index 782b8ccb0..7936498cc 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..31efb4269 100644 --- a/src/stdlib/SDL_iconv.c +++ b/src/stdlib/SDL_iconv.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..996e5d242 100644 --- a/src/stdlib/SDL_malloc.c +++ b/src/stdlib/SDL_malloc.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..a488af266 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 */ @@ -273,8 +278,8 @@ int SDL_tolower(int x) { return ((x) >= 'A') && ((x) <= 'Z') ? ('a'+((x)-'A')) : __declspec(selectany) int _fltused = 1; #endif -/* The optimizer on Visual Studio 2010/2012 generates memcpy() calls */ -#if _MSC_VER >= 1600 && defined(_WIN64) && !defined(_DEBUG) +/* The optimizer on Visual Studio 2005 and later generates memcpy() calls */ +#if (_MSC_VER >= 1400) && defined(_WIN64) && !defined(_DEBUG) #include #pragma function(memcpy) diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c index 84285865d..68d88ece0 100644 --- a/src/stdlib/SDL_string.c +++ b/src/stdlib/SDL_string.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -18,6 +18,15 @@ 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 + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include "../SDL_internal.h" /* This file contains portable string manipulation functions for SDL */ diff --git a/src/test/SDL_test_assert.c b/src/test/SDL_test_assert.c index 691453f0b..12eca146a 100644 --- a/src/test/SDL_test_assert.c +++ b/src/test/SDL_test_assert.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index d05dda47b..2f06a794a 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/test/SDL_test_compare.c b/src/test/SDL_test_compare.c index de7041662..9f74c44d4 100644 --- a/src/test/SDL_test_compare.c +++ b/src/test/SDL_test_compare.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -43,6 +43,7 @@ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, int bpp, bpp_reference; Uint8 *p, *p_reference; int dist; + int sampleErrorX, sampleErrorY, sampleDist; Uint8 R, G, B, A; Uint8 Rd, Gd, Bd, Ad; char imageFilename[128]; @@ -86,6 +87,11 @@ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, /* Allow some difference in blending accuracy */ if (dist > allowable_error) { ret++; + if (ret == 1) { + sampleErrorX = i; + sampleErrorY = j; + sampleDist = dist; + } } } } @@ -96,6 +102,8 @@ int SDLTest_CompareSurfaces(SDL_Surface *surface, SDL_Surface *referenceSurface, /* Save test image and reference for analysis on failures */ _CompareSurfaceCount++; if (ret != 0) { + SDLTest_LogError("Comparison of pixels with allowable error of %i failed %i times.", allowable_error, ret); + SDLTest_LogError("First detected occurrence at position %i,%i with a squared RGB-difference of %i.", sampleErrorX, sampleErrorY, sampleDist); SDL_snprintf(imageFilename, 127, "CompareSurfaces%04d_TestOutput.bmp", _CompareSurfaceCount); SDL_SaveBMP(surface, imageFilename); SDL_snprintf(referenceFilename, 127, "CompareSurfaces%04d_Reference.bmp", _CompareSurfaceCount); diff --git a/src/test/SDL_test_crc32.c b/src/test/SDL_test_crc32.c index dafe72296..7aa0a68fa 100644 --- a/src/test/SDL_test_crc32.c +++ b/src/test/SDL_test_crc32.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_font.c b/src/test/SDL_test_font.c index a6bc40cef..4be29f117 100644 --- a/src/test/SDL_test_font.c +++ b/src/test/SDL_test_font.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_fuzzer.c b/src/test/SDL_test_fuzzer.c index 963fc10b8..9fad17858 100644 --- a/src/test/SDL_test_fuzzer.c +++ b/src/test/SDL_test_fuzzer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -34,6 +34,7 @@ #define UINT32_MAX ~(Uint32)0 #define UINT64_MAX ~(Uint64)0 #else +#define _GNU_SOURCE #include #endif #include diff --git a/src/test/SDL_test_harness.c b/src/test/SDL_test_harness.c index 9ad2697ff..6dde93f87 100644 --- a/src/test/SDL_test_harness.c +++ b/src/test/SDL_test_harness.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -484,6 +484,7 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user if (suiteFilter == 0 && testFilter == 0) { SDLTest_LogError("Filter '%s' did not match any test suite/case.", filter); SDLTest_Log("Exit code: 2"); + SDL_free(failedTests); return 2; } } diff --git a/src/test/SDL_test_imageBlit.c b/src/test/SDL_test_imageBlit.c index d4c74fb42..1b9ed7bf6 100644 --- a/src/test/SDL_test_imageBlit.c +++ b/src/test/SDL_test_imageBlit.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_imageBlitBlend.c b/src/test/SDL_test_imageBlitBlend.c index f849d730d..963520bd7 100644 --- a/src/test/SDL_test_imageBlitBlend.c +++ b/src/test/SDL_test_imageBlitBlend.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_imageFace.c b/src/test/SDL_test_imageFace.c index 74fa8341d..37498d874 100644 --- a/src/test/SDL_test_imageFace.c +++ b/src/test/SDL_test_imageFace.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_imagePrimitives.c b/src/test/SDL_test_imagePrimitives.c index d2aafcbe3..5576d3d26 100644 --- a/src/test/SDL_test_imagePrimitives.c +++ b/src/test/SDL_test_imagePrimitives.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_imagePrimitivesBlend.c b/src/test/SDL_test_imagePrimitivesBlend.c index cfe189a05..c8e199309 100644 --- a/src/test/SDL_test_imagePrimitivesBlend.c +++ b/src/test/SDL_test_imagePrimitivesBlend.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_log.c b/src/test/SDL_test_log.c index 6c076aac7..ed7139b67 100644 --- a/src/test/SDL_test_log.c +++ b/src/test/SDL_test_log.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_md5.c b/src/test/SDL_test_md5.c index 8467ccbc4..291ad6b20 100644 --- a/src/test/SDL_test_md5.c +++ b/src/test/SDL_test_md5.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/test/SDL_test_random.c b/src/test/SDL_test_random.c index bc434183c..088c301ad 100644 --- a/src/test/SDL_test_random.c +++ b/src/test/SDL_test_random.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/SDL_systhread.h b/src/thread/SDL_systhread.h index 9c9409a5b..d3eab1f3f 100644 --- a/src/thread/SDL_systhread.h +++ b/src/thread/SDL_systhread.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/SDL_thread.c b/src/thread/SDL_thread.c index 3724f4f3c..8bc37fac9 100644 --- a/src/thread/SDL_thread.c +++ b/src/thread/SDL_thread.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/SDL_thread_c.h b/src/thread/SDL_thread_c.h index 85ef5cce2..2df712540 100644 --- a/src/thread/SDL_thread_c.h +++ b/src/thread/SDL_thread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_syscond.c b/src/thread/generic/SDL_syscond.c index 64cc63400..6e7f9b330 100644 --- a/src/thread/generic/SDL_syscond.c +++ b/src/thread/generic/SDL_syscond.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_sysmutex.c b/src/thread/generic/SDL_sysmutex.c index ddcc8cdf4..0c7a85142 100644 --- a/src/thread/generic/SDL_sysmutex.c +++ b/src/thread/generic/SDL_sysmutex.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_sysmutex_c.h b/src/thread/generic/SDL_sysmutex_c.h index f868fade8..7481b6656 100644 --- a/src/thread/generic/SDL_sysmutex_c.h +++ b/src/thread/generic/SDL_sysmutex_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_syssem.c b/src/thread/generic/SDL_syssem.c index c7220a2a4..cae084db5 100644 --- a/src/thread/generic/SDL_syssem.c +++ b/src/thread/generic/SDL_syssem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_systhread.c b/src/thread/generic/SDL_systhread.c index 6cd29f76e..b248165fd 100644 --- a/src/thread/generic/SDL_systhread.c +++ b/src/thread/generic/SDL_systhread.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_systhread_c.h b/src/thread/generic/SDL_systhread_c.h index 38e8b208e..30ba69ea0 100644 --- a/src/thread/generic/SDL_systhread_c.h +++ b/src/thread/generic/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/generic/SDL_systls.c b/src/thread/generic/SDL_systls.c index b73d901fa..99bfce77c 100644 --- a/src/thread/generic/SDL_systls.c +++ b/src/thread/generic/SDL_systls.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/psp/SDL_syscond.c b/src/thread/psp/SDL_syscond.c index 1abd9a3d9..d4ff59d59 100644 --- a/src/thread/psp/SDL_syscond.c +++ b/src/thread/psp/SDL_syscond.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e0f411ea5 100644 --- a/src/thread/psp/SDL_sysmutex.c +++ b/src/thread/psp/SDL_sysmutex.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_sysmutex_c.h b/src/thread/psp/SDL_sysmutex_c.h index f868fade8..7481b6656 100644 --- a/src/thread/psp/SDL_sysmutex_c.h +++ b/src/thread/psp/SDL_sysmutex_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/psp/SDL_syssem.c b/src/thread/psp/SDL_syssem.c index 27d3251a2..cfbbe433d 100644 --- a/src/thread/psp/SDL_syssem.c +++ b/src/thread/psp/SDL_syssem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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. */ @@ -76,7 +79,7 @@ void SDL_DestroySemaphore(SDL_sem *sem) int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) { Uint32 *pTimeout; - unsigned int res; + int res; if (sem == NULL) { SDL_SetError("Passed a NULL sem"); @@ -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..95141cc80 100644 --- a/src/thread/psp/SDL_systhread.c +++ b/src/thread/psp/SDL_systhread.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/thread/psp/SDL_systhread_c.h b/src/thread/psp/SDL_systhread_c.h index 4f9dac249..2c5de1bae 100644 --- a/src/thread/psp/SDL_systhread_c.h +++ b/src/thread/psp/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/pthread/SDL_syscond.c b/src/thread/pthread/SDL_syscond.c index c15df8632..2b0e0a537 100644 --- a/src/thread/pthread/SDL_syscond.c +++ b/src/thread/pthread/SDL_syscond.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -21,6 +21,7 @@ #include "../../SDL_internal.h" #include +#include #include #include #include @@ -98,17 +99,26 @@ int SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) { int retval; +#ifndef HAVE_CLOCK_GETTIME struct timeval delta; +#endif struct timespec abstime; if (!cond) { return SDL_SetError("Passed a NULL condition variable"); } +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &abstime); + + abstime.tv_nsec += (ms % 1000) * 1000000; + abstime.tv_sec += ms / 1000; +#else gettimeofday(&delta, NULL); abstime.tv_sec = delta.tv_sec + (ms / 1000); abstime.tv_nsec = (delta.tv_usec + (ms % 1000) * 1000) * 1000; +#endif if (abstime.tv_nsec > 1000000000) { abstime.tv_sec += 1; abstime.tv_nsec -= 1000000000; diff --git a/src/thread/pthread/SDL_sysmutex.c b/src/thread/pthread/SDL_sysmutex.c index 8303c6192..d7fa982c8 100644 --- a/src/thread/pthread/SDL_sysmutex.c +++ b/src/thread/pthread/SDL_sysmutex.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -23,8 +23,8 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif -#include #include +#include #include "SDL_thread.h" diff --git a/src/thread/pthread/SDL_sysmutex_c.h b/src/thread/pthread/SDL_sysmutex_c.h index bf69bcd16..475275a25 100644 --- a/src/thread/pthread/SDL_sysmutex_c.h +++ b/src/thread/pthread/SDL_sysmutex_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/pthread/SDL_syssem.c b/src/thread/pthread/SDL_syssem.c index 6d84e1b89..a89a262a7 100644 --- a/src/thread/pthread/SDL_syssem.c +++ b/src/thread/pthread/SDL_syssem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -20,10 +20,14 @@ */ #include "../../SDL_internal.h" +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #include #include #include #include +#include #include "SDL_thread.h" #include "SDL_timer.h" @@ -102,7 +106,9 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) { int retval; #ifdef HAVE_SEM_TIMEDWAIT +#ifndef HAVE_CLOCK_GETTIME struct timeval now; +#endif struct timespec ts_timeout; #else Uint32 end; @@ -125,22 +131,26 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) * a lapse of time, but until we reach a certain time. * This time is now plus the timeout. */ +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_REALTIME, &ts_timeout); + + /* Add our timeout to current time */ + ts_timeout.tv_nsec += (timeout % 1000) * 1000000; + ts_timeout.tv_sec += timeout / 1000; +#else gettimeofday(&now, NULL); /* Add our timeout to current time */ - now.tv_usec += (timeout % 1000) * 1000; - now.tv_sec += timeout / 1000; + ts_timeout.tv_sec = now.tv_sec + (timeout / 1000); + ts_timeout.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000; +#endif /* Wrap the second if needed */ - if ( now.tv_usec >= 1000000 ) { - now.tv_usec -= 1000000; - now.tv_sec ++; + if (ts_timeout.tv_nsec > 1000000000) { + ts_timeout.tv_sec += 1; + ts_timeout.tv_nsec -= 1000000000; } - /* Convert to timespec */ - ts_timeout.tv_sec = now.tv_sec; - ts_timeout.tv_nsec = now.tv_usec * 1000; - /* Wait. */ do { retval = sem_timedwait(&sem->sem, &ts_timeout); diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index 6eaf20ead..c77e31b29 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -45,6 +45,7 @@ #include "SDL_platform.h" #include "SDL_thread.h" +#include "SDL_hints.h" #include "../SDL_thread_c.h" #include "../SDL_systhread.h" #ifdef __ANDROID__ @@ -86,6 +87,8 @@ int SDL_SYS_CreateThread(SDL_Thread * thread, void *args) { pthread_attr_t type; + size_t ss; + const char *hint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE); /* do this here before any threads exist, so there's no race condition. */ #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__) @@ -105,6 +108,16 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) return SDL_SetError("Couldn't initialize pthread attributes"); } pthread_attr_setdetachstate(&type, PTHREAD_CREATE_JOINABLE); + + /* If the SDL_HINT_THREAD_STACK_SIZE exists and it seems to be a positive number, use it */ + if (hint && hint[0] >= '0' && hint[0] <= '9') { + const size_t stacksize = (size_t) SDL_atoi(hint); + if (stacksize > 0) { + pthread_attr_setstacksize(&type, stacksize); + } + } + + pthread_attr_getstacksize(&type, &ss); /* Create the thread and go! */ if (pthread_create(&thread->handle, &type, RunThread, args) != 0) { @@ -117,10 +130,10 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) void SDL_SYS_SetupThread(const char *name) { -#ifndef __NACL__ +#if !defined(__ANDROID__) && !defined(__NACL__) int i; sigset_t mask; -#endif +#endif /* !__ANDROID__ && !__NACL__ */ if (name != NULL) { #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__) @@ -146,14 +159,15 @@ SDL_SYS_SetupThread(const char *name) } /* NativeClient does not yet support signals.*/ -#ifndef __NACL__ +#if !defined(__ANDROID__) && !defined(__NACL__) /* Mask asynchronous signals for this thread */ sigemptyset(&mask); for (i = 0; sig_list[i]; ++i) { sigaddset(&mask, sig_list[i]); } pthread_sigmask(SIG_BLOCK, &mask, 0); -#endif +#endif /* !__ANDROID__ && !__NACL__ */ + #ifdef PTHREAD_CANCEL_ASYNCHRONOUS /* Allow ourselves to be asynchronously cancelled */ diff --git a/src/thread/pthread/SDL_systhread_c.h b/src/thread/pthread/SDL_systhread_c.h index eedb7d1f5..3a25f47a8 100644 --- a/src/thread/pthread/SDL_systhread_c.h +++ b/src/thread/pthread/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/pthread/SDL_systls.c b/src/thread/pthread/SDL_systls.c index 09a279040..0440af57f 100644 --- a/src/thread/pthread/SDL_systls.c +++ b/src/thread/pthread/SDL_systls.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/stdcpp/SDL_syscond.cpp b/src/thread/stdcpp/SDL_syscond.cpp index e9da82a3b..51ec4dc7c 100644 --- a/src/thread/stdcpp/SDL_syscond.cpp +++ b/src/thread/stdcpp/SDL_syscond.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/stdcpp/SDL_sysmutex.cpp b/src/thread/stdcpp/SDL_sysmutex.cpp index 4b60fb1dc..da411612b 100644 --- a/src/thread/stdcpp/SDL_sysmutex.cpp +++ b/src/thread/stdcpp/SDL_sysmutex.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/stdcpp/SDL_sysmutex_c.h b/src/thread/stdcpp/SDL_sysmutex_c.h index 6bbd9dcd8..d7b5b218b 100644 --- a/src/thread/stdcpp/SDL_sysmutex_c.h +++ b/src/thread/stdcpp/SDL_sysmutex_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/stdcpp/SDL_systhread.cpp b/src/thread/stdcpp/SDL_systhread.cpp index 5de700ab6..ab8e1505c 100644 --- a/src/thread/stdcpp/SDL_systhread.cpp +++ b/src/thread/stdcpp/SDL_systhread.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/stdcpp/SDL_systhread_c.h b/src/thread/stdcpp/SDL_systhread_c.h index a0a338f5c..d3affedc4 100644 --- a/src/thread/stdcpp/SDL_systhread_c.h +++ b/src/thread/stdcpp/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/windows/SDL_sysmutex.c b/src/thread/windows/SDL_sysmutex.c index 8333e11b4..a5c62cd5a 100644 --- a/src/thread/windows/SDL_sysmutex.c +++ b/src/thread/windows/SDL_sysmutex.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/windows/SDL_syssem.c b/src/thread/windows/SDL_syssem.c index a4f75f5cf..149c27577 100644 --- a/src/thread/windows/SDL_syssem.c +++ b/src/thread/windows/SDL_syssem.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/windows/SDL_systhread.c b/src/thread/windows/SDL_systhread.c index 79c40b161..34d70d45b 100644 --- a/src/thread/windows/SDL_systhread.c +++ b/src/thread/windows/SDL_systhread.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/windows/SDL_systhread_c.h b/src/thread/windows/SDL_systhread_c.h index f3c78e99a..0beafe889 100644 --- a/src/thread/windows/SDL_systhread_c.h +++ b/src/thread/windows/SDL_systhread_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/thread/windows/SDL_systls.c b/src/thread/windows/SDL_systls.c index 6ceadaa12..67c847414 100644 --- a/src/thread/windows/SDL_systls.c +++ b/src/thread/windows/SDL_systls.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/timer/SDL_timer.c b/src/timer/SDL_timer.c index 3ec1291b5..2e5e544c7 100644 --- a/src/timer/SDL_timer.c +++ b/src/timer/SDL_timer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/timer/SDL_timer_c.h b/src/timer/SDL_timer_c.h index 8d563cff8..ab1e16ac7 100644 --- a/src/timer/SDL_timer_c.h +++ b/src/timer/SDL_timer_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/timer/dummy/SDL_systimer.c b/src/timer/dummy/SDL_systimer.c index 57899ae95..0a63bfabd 100644 --- a/src/timer/dummy/SDL_systimer.c +++ b/src/timer/dummy/SDL_systimer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/timer/haiku/SDL_systimer.c b/src/timer/haiku/SDL_systimer.c index 685f72a82..ea736ba7a 100644 --- a/src/timer/haiku/SDL_systimer.c +++ b/src/timer/haiku/SDL_systimer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/timer/psp/SDL_systimer.c b/src/timer/psp/SDL_systimer.c index b706f4495..ece71d371 100644 --- a/src/timer/psp/SDL_systimer.c +++ b/src/timer/psp/SDL_systimer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/timer/unix/SDL_systimer.c b/src/timer/unix/SDL_systimer.c index cace86619..98917214d 100644 --- a/src/timer/unix/SDL_systimer.c +++ b/src/timer/unix/SDL_systimer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -48,6 +48,15 @@ #include #endif +/* Use CLOCK_MONOTONIC_RAW, if available, which is not subject to adjustment by NTP */ +#if HAVE_CLOCK_GETTIME +#ifdef CLOCK_MONOTONIC_RAW +#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC_RAW +#else +#define SDL_MONOTONIC_CLOCK CLOCK_MONOTONIC +#endif +#endif + /* The first ticks value of the application */ #if HAVE_CLOCK_GETTIME static struct timespec start_ts; @@ -69,7 +78,7 @@ SDL_TicksInit(void) /* Set first ticks value */ #if HAVE_CLOCK_GETTIME - if (clock_gettime(CLOCK_MONOTONIC, &start_ts) == 0) { + if (clock_gettime(SDL_MONOTONIC_CLOCK, &start_ts) == 0) { has_monotonic_time = SDL_TRUE; } else #elif defined(__APPLE__) @@ -101,7 +110,7 @@ SDL_GetTicks(void) if (has_monotonic_time) { #if HAVE_CLOCK_GETTIME struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); + clock_gettime(SDL_MONOTONIC_CLOCK, &now); ticks = (now.tv_sec - start_ts.tv_sec) * 1000 + (now.tv_nsec - start_ts.tv_nsec) / 1000000; #elif defined(__APPLE__) @@ -132,7 +141,7 @@ SDL_GetPerformanceCounter(void) #if HAVE_CLOCK_GETTIME struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); + clock_gettime(SDL_MONOTONIC_CLOCK, &now); ticks = now.tv_sec; ticks *= 1000000000; ticks += now.tv_nsec; diff --git a/src/timer/windows/SDL_systimer.c b/src/timer/windows/SDL_systimer.c index 07561636a..a213be009 100644 --- a/src/timer/windows/SDL_systimer.c +++ b/src/timer/windows/SDL_systimer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -30,10 +30,9 @@ /* The first (low-resolution) ticks value of the application */ -static DWORD start; +static DWORD start = 0; static BOOL ticks_started = FALSE; -#ifndef USE_GETTICKCOUNT /* Store if a high-resolution performance counter exists on the system */ static BOOL hires_timer_available; /* The first high-resolution ticks value of the application */ @@ -41,10 +40,10 @@ static LARGE_INTEGER hires_start_ticks; /* The number of ticks per second of the high-resolution performance counter */ static LARGE_INTEGER hires_ticks_per_second; -#ifndef __WINRT__ static void -timeSetPeriod(UINT uPeriod) +SDL_SetSystemTimerResolution(const UINT uPeriod) { +#ifndef __WINRT__ static UINT timer_period = 0; if (uPeriod != timer_period) { @@ -58,6 +57,7 @@ timeSetPeriod(UINT uPeriod) timeBeginPeriod(timer_period); } } +#endif } static void @@ -72,12 +72,9 @@ SDL_TimerResolutionChanged(void *userdata, const char *name, const char *oldValu uPeriod = 1; } if (uPeriod || oldValue != hint) { - timeSetPeriod(uPeriod); + SDL_SetSystemTimerResolution(uPeriod); } } -#endif /* ifndef __WINRT__ */ - -#endif /* !USE_GETTICKCOUNT */ void SDL_TicksInit(void) @@ -87,10 +84,12 @@ SDL_TicksInit(void) } ticks_started = SDL_TRUE; + /* if we didn't set a precision, set it high. This affects lots of things + on Windows besides the SDL timers, like audio callbacks, etc. */ + SDL_AddHintCallback(SDL_HINT_TIMER_RESOLUTION, + SDL_TimerResolutionChanged, NULL); + /* Set first ticks value */ -#ifdef USE_GETTICKCOUNT - start = GetTickCount(); -#else /* QueryPerformanceCounter has had problems in the past, but lots of games use it, so we'll rely on it here. */ @@ -99,51 +98,36 @@ SDL_TicksInit(void) QueryPerformanceCounter(&hires_start_ticks); } else { hires_timer_available = FALSE; -#ifdef __WINRT__ - start = 0; /* the timer failed to start! */ -#else - timeSetPeriod(1); /* use 1 ms timer precision */ +#ifndef __WINRT__ start = timeGetTime(); - - SDL_AddHintCallback(SDL_HINT_TIMER_RESOLUTION, - SDL_TimerResolutionChanged, NULL); #endif /* __WINRT__ */ } -#endif /* USE_GETTICKCOUNT */ } void SDL_TicksQuit(void) { -#ifndef USE_GETTICKCOUNT if (!hires_timer_available) { -#ifndef __WINRT__ SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION, SDL_TimerResolutionChanged, NULL); - - timeSetPeriod(0); -#endif /* __WINRT__ */ } -#endif /* USE_GETTICKCOUNT */ + SDL_SetSystemTimerResolution(0); /* always release our timer resolution request. */ + + start = 0; ticks_started = SDL_FALSE; } Uint32 SDL_GetTicks(void) { - DWORD now; -#ifndef USE_GETTICKCOUNT + DWORD now = 0; LARGE_INTEGER hires_now; -#endif if (!ticks_started) { SDL_TicksInit(); } -#ifdef USE_GETTICKCOUNT - now = GetTickCount(); -#else if (hires_timer_available) { QueryPerformanceCounter(&hires_now); @@ -153,13 +137,10 @@ SDL_GetTicks(void) return (DWORD) hires_now.QuadPart; } else { -#ifdef __WINRT__ - now = 0; -#else +#ifndef __WINRT__ now = timeGetTime(); #endif /* __WINRT__ */ } -#endif return (now - start); } @@ -186,23 +167,30 @@ SDL_GetPerformanceFrequency(void) return frequency.QuadPart; } -#ifdef __WINRT__ -static void -Sleep(DWORD timeout) +void +SDL_Delay(Uint32 ms) { + /* Sleep() is not publicly available to apps in early versions of WinRT. + * + * Visual C++ 2013 Update 4 re-introduced Sleep() for Windows 8.1 and + * Windows Phone 8.1. + * + * Use the compiler version to determine availability. + * + * NOTE #1: _MSC_FULL_VER == 180030723 for Visual C++ 2013 Update 3. + * NOTE #2: Visual C++ 2013, when compiling for Windows 8.0 and + * Windows Phone 8.0, uses the Visual C++ 2012 compiler to build + * apps and libraries. + */ +#if defined(__WINRT__) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER <= 180030723) static HANDLE mutex = 0; - if ( ! mutex ) - { + if (!mutex) { mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS); } - WaitForSingleObjectEx(mutex, timeout, FALSE); -} -#endif - -void -SDL_Delay(Uint32 ms) -{ + WaitForSingleObjectEx(mutex, ms, FALSE); +#else Sleep(ms); +#endif } #endif /* SDL_TIMER_WINDOWS */ diff --git a/src/video/SDL_RLEaccel.c b/src/video/SDL_RLEaccel.c index 1f0f75078..b9f1426dc 100644 --- a/src/video/SDL_RLEaccel.c +++ b/src/video/SDL_RLEaccel.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -373,6 +373,18 @@ } \ } while(0) +/* + * Set a pixel value using the given format, except that the alpha value is + * placed in the top byte. This is the format used for RLE with alpha. + */ +#define RLEPIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \ +{ \ + Pixel = ((r>>fmt->Rloss)<Rshift)| \ + ((g>>fmt->Gloss)<Gshift)| \ + ((b>>fmt->Bloss)<Bshift)| \ + (a<<24); \ +} + /* * This takes care of the case when the surface is clipped on the left and/or * right. Top clipping has already been taken care of. @@ -982,7 +994,7 @@ copy_32(void *dst, Uint32 * src, int n, for (i = 0; i < n; i++) { unsigned r, g, b, a; RGBA_FROM_8888(*src, sfmt, r, g, b, a); - PIXEL_FROM_RGBA(*d, dfmt, r, g, b, a); + RLEPIXEL_FROM_RGBA(*d, dfmt, r, g, b, a); d++; src++; } diff --git a/src/video/SDL_RLEaccel_c.h b/src/video/SDL_RLEaccel_c.h index 271faa0b7..ed980f981 100644 --- a/src/video/SDL_RLEaccel_c.h +++ b/src/video/SDL_RLEaccel_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit.c b/src/video/SDL_blit.c index fe30923bc..1c8b0735e 100644 --- a/src/video/SDL_blit.c +++ b/src/video/SDL_blit.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit.h b/src/video/SDL_blit.h index f12018d83..6b8effff9 100644 --- a/src/video/SDL_blit.h +++ b/src/video/SDL_blit.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_0.c b/src/video/SDL_blit_0.c index a820fb379..64e20f8e0 100644 --- a/src/video/SDL_blit_0.c +++ b/src/video/SDL_blit_0.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_1.c b/src/video/SDL_blit_1.c index 4dfcabda6..53f486b98 100644 --- a/src/video/SDL_blit_1.c +++ b/src/video/SDL_blit_1.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_A.c b/src/video/SDL_blit_A.c index d3a9e8148..4ba7c82cd 100644 --- a/src/video/SDL_blit_A.c +++ b/src/video/SDL_blit_A.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -580,7 +580,7 @@ BlitRGBtoRGBPixelAlphaMMX3DNOW(SDL_BlitInfo * info) _mm_empty(); } -#endif /* __MMX__ */ +#endif /* __3dNOW__ */ /* 16bpp special case for per-surface alpha=50%: blend 2 pixels in parallel */ diff --git a/src/video/SDL_blit_N.c b/src/video/SDL_blit_N.c index 41615be57..c0c7fbfbe 100644 --- a/src/video/SDL_blit_N.c +++ b/src/video/SDL_blit_N.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -2114,6 +2114,33 @@ Blit4to4MaskAlpha(SDL_BlitInfo * info) } } +/* blits 32 bit RGBA<->RGBA with both surfaces having the same R,G,B,A fields */ +static void +Blit4to4CopyAlpha(SDL_BlitInfo * info) +{ + int width = info->dst_w; + int height = info->dst_h; + Uint32 *src = (Uint32 *) info->src; + int srcskip = info->src_skip; + Uint32 *dst = (Uint32 *) info->dst; + int dstskip = info->dst_skip; + + /* RGBA->RGBA, COPY_ALPHA */ + while (height--) { + /* *INDENT-OFF* */ + DUFFS_LOOP( + { + *dst = *src; + ++dst; + ++src; + }, + width); + /* *INDENT-ON* */ + src = (Uint32 *) ((Uint8 *) src + srcskip); + dst = (Uint32 *) ((Uint8 *) dst + dstskip); + } +} + static void BlitNtoN(SDL_BlitInfo * info) { @@ -2562,8 +2589,17 @@ SDL_CalculateBlitN(SDL_Surface * surface) srcfmt->Rmask == dstfmt->Rmask && srcfmt->Gmask == dstfmt->Gmask && srcfmt->Bmask == dstfmt->Bmask) { - /* Fastpath C fallback: 32bit RGB<->RGBA blit with matching RGB */ - blitfun = Blit4to4MaskAlpha; + if (a_need == COPY_ALPHA) { + if (srcfmt->Amask == dstfmt->Amask) { + /* Fastpath C fallback: 32bit RGBA<->RGBA blit with matching RGBA */ + blitfun = Blit4to4CopyAlpha; + } else { + blitfun = BlitNtoNCopyAlpha; + } + } else { + /* Fastpath C fallback: 32bit RGB<->RGBA blit with matching RGB */ + blitfun = Blit4to4MaskAlpha; + } } else if (a_need == COPY_ALPHA) { blitfun = BlitNtoNCopyAlpha; } diff --git a/src/video/SDL_blit_auto.c b/src/video/SDL_blit_auto.c index 8b7c8e9b2..987d12d80 100644 --- a/src/video/SDL_blit_auto.c +++ b/src/video/SDL_blit_auto.c @@ -1,7 +1,7 @@ /* DO NOT EDIT! This file is generated by sdlgenblit.pl */ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_auto.h b/src/video/SDL_blit_auto.h index 369e12fc9..7ba689c7c 100644 --- a/src/video/SDL_blit_auto.h +++ b/src/video/SDL_blit_auto.h @@ -1,7 +1,7 @@ /* DO NOT EDIT! This file is generated by sdlgenblit.pl */ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_copy.c b/src/video/SDL_blit_copy.c index 5c62d633d..3ec2e7eb1 100644 --- a/src/video/SDL_blit_copy.c +++ b/src/video/SDL_blit_copy.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_copy.h b/src/video/SDL_blit_copy.h index 8b6950ced..73defa2f8 100644 --- a/src/video/SDL_blit_copy.h +++ b/src/video/SDL_blit_copy.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_slow.c b/src/video/SDL_blit_slow.c index ca644adcf..9082f7a62 100644 --- a/src/video/SDL_blit_slow.c +++ b/src/video/SDL_blit_slow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_blit_slow.h b/src/video/SDL_blit_slow.h index c1786e0b5..5bd0598ad 100644 --- a/src/video/SDL_blit_slow.h +++ b/src/video/SDL_blit_slow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_bmp.c b/src/video/SDL_bmp.c index fcc48c6d5..3ea2dd541 100644 --- a/src/video/SDL_bmp.c +++ b/src/video/SDL_bmp.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..feff8eb33 100644 --- a/src/video/SDL_clipboard.c +++ b/src/video/SDL_clipboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_egl.c b/src/video/SDL_egl.c index 956e839a9..7b1c690ef 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -1,6 +1,6 @@ /* * Simple DirectMedia Layer - * Copyright (C) 1997-2014 Sam Lantinga + * Copyright (C) 1997-2015 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 @@ -31,7 +31,14 @@ #include "SDL_loadso.h" #include "SDL_hints.h" -#if RASPBERRYPI || SDL_VIDEO_DRIVER_RPI +#ifdef EGL_KHR_create_context +/* EGL_OPENGL_ES3_BIT_KHR was added in version 13 of the extension. */ +#ifndef EGL_OPENGL_ES3_BIT_KHR +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#endif +#endif /* EGL_KHR_create_context */ + +#if SDL_VIDEO_DRIVER_RPI /* Raspbian places the OpenGL ES/EGL binaries in a non standard path */ #define DEFAULT_EGL "/opt/vc/lib/libEGL.so" #define DEFAULT_OGL_ES2 "/opt/vc/lib/libGLESv2.so" @@ -74,26 +81,25 @@ static int SDL_EGL_HasExtension(_THIS, const char *ext) { int i; int len = 0; - int ext_len; + size_t ext_len; const char *exts; const char *ext_word; ext_len = SDL_strlen(ext); exts = _this->egl_data->eglQueryString(_this->egl_data->egl_display, EGL_EXTENSIONS); - if(exts) { + if (exts) { ext_word = exts; - for(i = 0; exts[i] != 0; i++) { - if(exts[i] == ' ') { - if(ext_len == len && !SDL_strncmp(ext_word, ext, len)) { + for (i = 0; exts[i] != 0; i++) { + if (exts[i] == ' ') { + if (ext_len == len && !SDL_strncmp(ext_word, ext, len)) { return 1; } len = 0; ext_word = &exts[i + 1]; - } - else { + } else { len++; } } @@ -190,12 +196,11 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa } if (egl_dll_handle == NULL) { - if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { + if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { if (_this->gl_config.major_version > 1) { path = DEFAULT_OGL_ES2; egl_dll_handle = SDL_LoadObject(path); - } - else { + } else { path = DEFAULT_OGL_ES; egl_dll_handle = SDL_LoadObject(path); if (egl_dll_handle == NULL) { @@ -334,23 +339,40 @@ SDL_EGL_ChooseConfig(_THIS) attribs[i++] = EGL_SAMPLES; attribs[i++] = _this->gl_config.multisamplesamples; } - + + if (_this->gl_config.framebuffer_srgb_capable) { +#ifdef EGL_KHR_gl_colorspace + if (SDL_EGL_HasExtension(_this, "EGL_KHR_gl_colorspace")) { + attribs[i++] = EGL_GL_COLORSPACE_KHR; + attribs[i++] = EGL_GL_COLORSPACE_SRGB_KHR; + } else +#endif + { + return SDL_SetError("EGL implementation does not support sRGB system framebuffers"); + } + } + attribs[i++] = EGL_RENDERABLE_TYPE; - if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { - if (_this->gl_config.major_version == 2) { + if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { +#ifdef EGL_KHR_create_context + if (_this->gl_config.major_version >= 3 && + SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) { + attribs[i++] = EGL_OPENGL_ES3_BIT_KHR; + } else +#endif + if (_this->gl_config.major_version >= 2) { attribs[i++] = EGL_OPENGL_ES2_BIT; } else { attribs[i++] = EGL_OPENGL_ES_BIT; } _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); - } - else { + } else { attribs[i++] = EGL_OPENGL_BIT; _this->egl_data->eglBindAPI(EGL_OPENGL_API); } - + attribs[i++] = EGL_NONE; - + if (_this->egl_data->eglChooseConfig(_this->egl_data->egl_display, attribs, configs, SDL_arraysize(configs), @@ -358,11 +380,11 @@ SDL_EGL_ChooseConfig(_THIS) found_configs == 0) { return SDL_SetError("Couldn't find matching EGL config"); } - + /* eglChooseConfig returns a number of configurations that match or exceed the requested attribs. */ /* From those, we select the one that matches our requirements more closely via a makeshift algorithm */ - for ( i=0; igl_config.profile_mask; + EGLint major_version = _this->gl_config.major_version; + EGLint minor_version = _this->gl_config.minor_version; + SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES); + if (!_this->egl_data) { /* The EGL library wasn't loaded, SDL_GetError() should have info */ return NULL; } - + if (_this->gl_config.share_with_current_context) { share_context = (EGLContext)SDL_GL_GetCurrentContext(); } - - /* Bind the API */ - if(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) { - _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); - if (_this->gl_config.major_version) { - context_attrib_list[1] = _this->gl_config.major_version; + + /* Set the context version and other attributes. */ + if ((major_version < 3 || (minor_version == 0 && profile_es)) && + _this->gl_config.flags == 0 && + (profile_mask == 0 || profile_es)) { + /* Create a context without using EGL_KHR_create_context attribs. + * When creating a GLES context without EGL_KHR_create_context we can + * only specify the major version. When creating a desktop GL context + * we can't specify any version, so we only try in that case when the + * version is less than 3.0 (matches SDL's GLX/WGL behavior.) + */ + if (profile_es) { + attribs[attr++] = EGL_CONTEXT_CLIENT_VERSION; + attribs[attr++] = SDL_max(major_version, 1); } + } else { +#ifdef EGL_KHR_create_context + /* The Major/minor version, context profiles, and context flags can + * only be specified when this extension is available. + */ + if (SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) { + attribs[attr++] = EGL_CONTEXT_MAJOR_VERSION_KHR; + attribs[attr++] = major_version; + attribs[attr++] = EGL_CONTEXT_MINOR_VERSION_KHR; + attribs[attr++] = minor_version; + + /* SDL profile bits match EGL profile bits. */ + if (profile_mask != 0 && profile_mask != SDL_GL_CONTEXT_PROFILE_ES) { + attribs[attr++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; + attribs[attr++] = profile_mask; + } - egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, - _this->egl_data->egl_config, - share_context, context_attrib_list); - } - else { - _this->egl_data->eglBindAPI(EGL_OPENGL_API); -#ifdef EGL_KHR_create_context - if(SDL_EGL_HasExtension(_this, "EGL_KHR_create_context")) { - context_attrib_list[0] = EGL_CONTEXT_MAJOR_VERSION_KHR; - context_attrib_list[1] = _this->gl_config.major_version; - context_attrib_list[2] = EGL_CONTEXT_MINOR_VERSION_KHR; - context_attrib_list[3] = _this->gl_config.minor_version; - context_attrib_list[4] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; - switch(_this->gl_config.profile_mask) { - case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: - context_attrib_list[5] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; - break; - - case SDL_GL_CONTEXT_PROFILE_CORE: - default: - context_attrib_list[5] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; - break; + /* SDL flags match EGL flags. */ + if (_this->gl_config.flags != 0) { + attribs[attr++] = EGL_CONTEXT_FLAGS_KHR; + attribs[attr++] = _this->gl_config.flags; } - } - else { - context_attrib_list[0] = EGL_NONE; - } -#else /* EGL_KHR_create_context */ - context_attrib_list[0] = EGL_NONE; + } else #endif /* EGL_KHR_create_context */ - egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, - _this->egl_data->egl_config, - share_context, context_attrib_list); + { + SDL_SetError("Could not create EGL context (context attributes are not supported)"); + return NULL; + } } - + + attribs[attr++] = EGL_NONE; + + /* Bind the API */ + if (profile_es) { + _this->egl_data->eglBindAPI(EGL_OPENGL_ES_API); + } else { + _this->egl_data->eglBindAPI(EGL_OPENGL_API); + } + + egl_context = _this->egl_data->eglCreateContext(_this->egl_data->egl_display, + _this->egl_data->egl_config, + share_context, attribs); + if (egl_context == EGL_NO_CONTEXT) { SDL_SetError("Could not create EGL context"); return NULL; } - + _this->egl_data->egl_swapinterval = 0; - + if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) { SDL_EGL_DeleteContext(_this, egl_context); SDL_SetError("Could not make EGL context current"); return NULL; } - + return (SDL_GLContext) egl_context; } @@ -489,8 +526,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context) */ if (!egl_context || !egl_surface) { _this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - else { + } else { if (!_this->egl_data->eglMakeCurrent(_this->egl_data->egl_display, egl_surface, egl_surface, egl_context)) { return SDL_SetError("Unable to make EGL context current"); diff --git a/src/video/SDL_egl_c.h b/src/video/SDL_egl_c.h index ef58b18e0..b46cfca66 100644 --- a/src/video/SDL_egl_c.h +++ b/src/video/SDL_egl_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_fillrect.c b/src/video/SDL_fillrect.c index 5f343eaf2..2282d2b19 100644 --- a/src/video/SDL_fillrect.c +++ b/src/video/SDL_fillrect.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -196,9 +196,15 @@ SDL_FillRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h) static void SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h) { - Uint8 r = (Uint8) ((color >> 16) & 0xFF); - Uint8 g = (Uint8) ((color >> 8) & 0xFF); - Uint8 b = (Uint8) (color & 0xFF); +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + Uint8 b1 = (Uint8) (color & 0xFF); + Uint8 b2 = (Uint8) ((color >> 8) & 0xFF); + Uint8 b3 = (Uint8) ((color >> 16) & 0xFF); +#elif SDL_BYTEORDER == SDL_BIG_ENDIAN + Uint8 b1 = (Uint8) ((color >> 16) & 0xFF); + Uint8 b2 = (Uint8) ((color >> 8) & 0xFF); + Uint8 b3 = (Uint8) (color & 0xFF); +#endif int n; Uint8 *p = NULL; @@ -207,9 +213,9 @@ SDL_FillRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h) p = pixels; while (n--) { - *p++ = r; - *p++ = g; - *p++ = b; + *p++ = b1; + *p++ = b2; + *p++ = b3; } pixels += pitch; } @@ -251,6 +257,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_pixels.c b/src/video/SDL_pixels.c index 0858daade..6b96125bb 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -1101,9 +1101,7 @@ SDL_CalculateGammaRamp(float gamma, Uint16 * ramp) /* 0.0 gamma is all black */ if (gamma == 0.0f) { - for (i = 0; i < 256; ++i) { - ramp[i] = 0; - } + SDL_memset(ramp, 0, 256 * sizeof(Uint16)); return; } else if (gamma == 1.0f) { /* 1.0 gamma is identity */ diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h index de2916ffa..3d2deb1a1 100644 --- a/src/video/SDL_pixels_c.h +++ b/src/video/SDL_pixels_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_rect.c b/src/video/SDL_rect.c index a0456bd69..b22951954 100644 --- a/src/video/SDL_rect.c +++ b/src/video/SDL_rect.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_rect_c.h b/src/video/SDL_rect_c.h index e6be32926..bc639ae2e 100644 --- a/src/video/SDL_rect_c.h +++ b/src/video/SDL_rect_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_shape.c b/src/video/SDL_shape.c index 147c60a5b..3309f6dbb 100644 --- a/src/video/SDL_shape.c +++ b/src/video/SDL_shape.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_shape_internals.h b/src/video/SDL_shape_internals.h index b5413e1ea..4eda9dd11 100644 --- a/src/video/SDL_shape_internals.h +++ b/src/video/SDL_shape_internals.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_stretch.c b/src/video/SDL_stretch.c index a4faacaf4..d3abaed52 100644 --- a/src/video/SDL_stretch.c +++ b/src/video/SDL_stretch.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/SDL_surface.c b/src/video/SDL_surface.c index fcd78870e..ef581fa94 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..5e3e1526d 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -170,6 +170,11 @@ struct SDL_VideoDevice */ int (*GetDisplayBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); + /* + * Get the dots/pixels-per-inch of a display + */ + int (*GetDisplayDPI) (_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi); + /* * Get a list of the available display modes for a display. */ @@ -274,6 +279,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 +309,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 +401,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); @@ -418,6 +428,8 @@ extern SDL_Window * SDL_GetFocusWindow(void); extern SDL_bool SDL_ShouldAllowTopmost(void); +extern float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches); + #endif /* _SDL_sysvideo_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 43d674fe0..a89399d9d 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 @@ -680,6 +687,24 @@ SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect) return 0; } +int +SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) +{ + SDL_VideoDisplay *display; + + CHECK_DISPLAY_INDEX(displayIndex, -1); + + display = &_this->displays[displayIndex]; + + if (_this->GetDisplayDPI) { + if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) { + return 0; + } + } + + return -1; +} + SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay * display, const SDL_DisplayMode * mode) { @@ -1100,22 +1125,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 +1157,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 +1186,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 +1211,7 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) SDL_RestoreMousePosition(other); window->last_fullscreen_flags = window->flags; - return; + return 0; } } } @@ -1202,6 +1231,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 +1283,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; @@ -1370,8 +1406,6 @@ SDL_CreateWindowFrom(const void *data) int SDL_RecreateWindow(SDL_Window * window, Uint32 flags) { - char *title = window->title; - SDL_Surface *icon = window->icon; SDL_bool loaded_opengl = SDL_FALSE; if ((flags & SDL_WINDOW_OPENGL) && !_this->GL_CreateContext) { @@ -1411,8 +1445,6 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) } } - window->title = NULL; - window->icon = NULL; window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); window->last_fullscreen_flags = window->flags; window->is_destroying = SDL_FALSE; @@ -1426,17 +1458,17 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) return -1; } } + if (flags & SDL_WINDOW_FOREIGN) { window->flags |= SDL_WINDOW_FOREIGN; } - if (title) { - SDL_SetWindowTitle(window, title); - SDL_free(title); + if (_this->SetWindowTitle && window->title) { + _this->SetWindowTitle(_this, window); } - if (icon) { - SDL_SetWindowIcon(window, icon); - SDL_FreeSurface(icon); + + if (_this->SetWindowIcon && window->icon) { + _this->SetWindowIcon(_this, window, window->icon); } if (window->hit_test) { @@ -1489,11 +1521,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 +1633,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; @@ -1649,12 +1679,31 @@ SDL_GetWindowPosition(SDL_Window * window, int *x, int *y) /* Fullscreen windows are always at their display's origin */ if (window->flags & SDL_WINDOW_FULLSCREEN) { + int displayIndex; + if (x) { *x = 0; } if (y) { *y = 0; } + + /* Find the window's monitor and update to the + monitor offset. */ + displayIndex = SDL_GetWindowDisplayIndex(window); + if (displayIndex >= 0) { + SDL_Rect bounds; + + SDL_zero(bounds); + + SDL_GetDisplayBounds(displayIndex, &bounds); + if (x) { + *x = bounds.x; + } + if (y) { + *y = bounds.y; + } + } } else { if (x) { *x = window->x; @@ -1927,9 +1976,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 +2088,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) { @@ -2107,14 +2155,30 @@ SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red, void SDL_UpdateWindowGrab(SDL_Window * window) { - if (_this->SetWindowGrab) { - SDL_bool grabbed; - if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && - (window->flags & SDL_WINDOW_INPUT_FOCUS)) { - grabbed = SDL_TRUE; - } else { - grabbed = SDL_FALSE; + SDL_Window *grabbed_window; + SDL_bool grabbed; + if ((SDL_GetMouse()->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) && + (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + grabbed = SDL_TRUE; + } 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; + if (_this->SetWindowGrab) { + _this->SetWindowGrab(_this, grabbed_window, SDL_FALSE); + } } + _this->grabbed_window = window; + } else if (grabbed_window == window) { + _this->grabbed_window = NULL; /* ungrabbing. */ + } + + if (_this->SetWindowGrab) { _this->SetWindowGrab(_this, window, grabbed); } } @@ -2139,8 +2203,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 +2704,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 +2811,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; @@ -2753,19 +2828,31 @@ int SDL_GL_GetAttribute(SDL_GLattr attr, int *value) { #if SDL_VIDEO_OPENGL || SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); - GLenum(APIENTRY * glGetErrorFunc) (void); + GLenum (APIENTRY *glGetErrorFunc) (void); GLenum attrib = 0; GLenum error = 0; - glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); - if (!glGetIntegervFunc) { - return -1; + /* + * Some queries in Core Profile desktop OpenGL 3+ contexts require + * glGetFramebufferAttachmentParameteriv instead of glGetIntegerv. Note that + * the enums we use for the former function don't exist in OpenGL ES 2, and + * the function itself doesn't exist prior to OpenGL 3 and OpenGL ES 2. + */ +#if SDL_VIDEO_OPENGL + const GLubyte *(APIENTRY *glGetStringFunc) (GLenum name); + void (APIENTRY *glGetFramebufferAttachmentParameterivFunc) (GLenum target, GLenum attachment, GLenum pname, GLint* params); + GLenum attachment = GL_BACK_LEFT; + GLenum attachmentattrib = 0; + + glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); + if (!glGetStringFunc) { + return SDL_SetError("Failed getting OpenGL glGetString entry point"); } +#endif glGetErrorFunc = SDL_GL_GetProcAddress("glGetError"); if (!glGetErrorFunc) { - return -1; + return SDL_SetError("Failed getting OpenGL glGetError entry point"); } /* Clear value in any case */ @@ -2773,15 +2860,27 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) switch (attr) { case SDL_GL_RED_SIZE: +#if SDL_VIDEO_OPENGL + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE; +#endif attrib = GL_RED_BITS; break; case SDL_GL_BLUE_SIZE: +#if SDL_VIDEO_OPENGL + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE; +#endif attrib = GL_BLUE_BITS; break; case SDL_GL_GREEN_SIZE: +#if SDL_VIDEO_OPENGL + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE; +#endif attrib = GL_GREEN_BITS; break; case SDL_GL_ALPHA_SIZE: +#if SDL_VIDEO_OPENGL + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE; +#endif attrib = GL_ALPHA_BITS; break; case SDL_GL_DOUBLEBUFFER: @@ -2796,9 +2895,17 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) return 0; #endif case SDL_GL_DEPTH_SIZE: +#if SDL_VIDEO_OPENGL + attachment = GL_DEPTH; + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE; +#endif attrib = GL_DEPTH_BITS; break; case SDL_GL_STENCIL_SIZE: +#if SDL_VIDEO_OPENGL + attachment = GL_STENCIL; + attachmentattrib = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE; +#endif attrib = GL_STENCIL_BITS; break; #if SDL_VIDEO_OPENGL @@ -2828,38 +2935,37 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) return 0; #endif case SDL_GL_MULTISAMPLEBUFFERS: -#if SDL_VIDEO_OPENGL - attrib = GL_SAMPLE_BUFFERS_ARB; -#else attrib = GL_SAMPLE_BUFFERS; -#endif break; case SDL_GL_MULTISAMPLESAMPLES: + attrib = GL_SAMPLES; + break; + case SDL_GL_CONTEXT_RELEASE_BEHAVIOR: #if SDL_VIDEO_OPENGL - attrib = GL_SAMPLES_ARB; + attrib = GL_CONTEXT_RELEASE_BEHAVIOR; #else - attrib = GL_SAMPLES; + attrib = GL_CONTEXT_RELEASE_BEHAVIOR_KHR; #endif break; case SDL_GL_BUFFER_SIZE: { - GLint bits = 0; - GLint component; - - /* - * there doesn't seem to be a single flag in OpenGL - * for this! - */ - glGetIntegervFunc(GL_RED_BITS, &component); - bits += component; - glGetIntegervFunc(GL_GREEN_BITS, &component); - bits += component; - glGetIntegervFunc(GL_BLUE_BITS, &component); - bits += component; - glGetIntegervFunc(GL_ALPHA_BITS, &component); - bits += component; - - *value = bits; + int rsize = 0, gsize = 0, bsize = 0, asize = 0; + + /* There doesn't seem to be a single flag in OpenGL for this! */ + if (SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &rsize) < 0) { + return -1; + } + if (SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gsize) < 0) { + return -1; + } + if (SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &bsize) < 0) { + return -1; + } + if (SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &asize) < 0) { + return -1; + } + + *value = rsize + gsize + bsize + asize; return 0; } case SDL_GL_ACCELERATED_VISUAL: @@ -2918,7 +3024,27 @@ SDL_GL_GetAttribute(SDL_GLattr attr, int *value) return SDL_SetError("Unknown OpenGL attribute"); } - glGetIntegervFunc(attrib, (GLint *) value); +#if SDL_VIDEO_OPENGL + if (attachmentattrib && isAtLeastGL3((const char *) glGetStringFunc(GL_VERSION))) { + glGetFramebufferAttachmentParameterivFunc = SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameteriv"); + + if (glGetFramebufferAttachmentParameterivFunc) { + glGetFramebufferAttachmentParameterivFunc(GL_FRAMEBUFFER, attachment, attachmentattrib, (GLint *) value); + } else { + return SDL_SetError("Failed getting OpenGL glGetFramebufferAttachmentParameteriv entry point"); + } + } else +#endif + { + void (APIENTRY *glGetIntegervFunc) (GLenum pname, GLint * params); + glGetIntegervFunc = SDL_GL_GetProcAddress("glGetIntegerv"); + if (glGetIntegervFunc) { + glGetIntegervFunc(attrib, (GLint *) value); + } else { + return SDL_SetError("Failed getting OpenGL glGetIntegerv entry point"); + } + } + error = glGetErrorFunc(); if (error != GL_NO_ERROR) { if (error == GL_INVALID_ENUM) { @@ -3327,6 +3453,7 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) SDL_CaptureMouse(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); show_cursor_prev = SDL_ShowCursor(1); + SDL_ResetKeyboard(); if (!buttonid) { buttonid = &dummybutton; @@ -3448,4 +3575,15 @@ SDL_SetWindowHitTest(SDL_Window * window, SDL_HitTest callback, void *userdata) return 0; } +float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches) +{ + float den2 = hinches * hinches + vinches * vinches; + if ( den2 <= 0.0f ) { + return 0.0f; + } + + return (float)(SDL_sqrt((double)hpix * (double)hpix + (double)vpix * (double)vpix) / + SDL_sqrt((double)den2)); +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/android/SDL_androidclipboard.c b/src/video/android/SDL_androidclipboard.c index dcac2e701..6a4564724 100644 --- a/src/video/android/SDL_androidclipboard.c +++ b/src/video/android/SDL_androidclipboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidclipboard.h b/src/video/android/SDL_androidclipboard.h index c1ab140cf..600771b91 100644 --- a/src/video/android/SDL_androidclipboard.h +++ b/src/video/android/SDL_androidclipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 2662d1b3d..f15180a9e 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_androidevents.h b/src/video/android/SDL_androidevents.h index 547338d76..888a593c7 100644 --- a/src/video/android/SDL_androidevents.h +++ b/src/video/android/SDL_androidevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index b452b5c73..5bf8d1a17 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidkeyboard.c b/src/video/android/SDL_androidkeyboard.c index 5008cfde6..d75e42ada 100644 --- a/src/video/android/SDL_androidkeyboard.c +++ b/src/video/android/SDL_androidkeyboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -253,8 +253,8 @@ static SDL_Scancode Android_Keycodes[] = { SDL_SCANCODE_CALCULATOR, /* AKEYCODE_CALCULATOR */ SDL_SCANCODE_LANG5, /* AKEYCODE_ZENKAKU_HANKAKU */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_EISU */ - SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MUHENKAN */ - SDL_SCANCODE_UNKNOWN, /* AKEYCODE_HENKAN */ + SDL_SCANCODE_INTERNATIONAL5, /* AKEYCODE_MUHENKAN */ + SDL_SCANCODE_INTERNATIONAL4, /* AKEYCODE_HENKAN */ SDL_SCANCODE_LANG3, /* AKEYCODE_KATAKANA_HIRAGANA */ SDL_SCANCODE_INTERNATIONAL3, /* AKEYCODE_YEN */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_RO */ @@ -263,6 +263,43 @@ static SDL_Scancode Android_Keycodes[] = { SDL_SCANCODE_BRIGHTNESSDOWN, /* AKEYCODE_BRIGHTNESS_DOWN */ SDL_SCANCODE_BRIGHTNESSUP, /* AKEYCODE_BRIGHTNESS_UP */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_AUDIO_TRACK */ + SDL_SCANCODE_SLEEP, /* AKEYCODE_SLEEP */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_WAKEUP */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_PAIRING */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_TOP_MENU */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_11 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_12 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_LAST_CHANNEL */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_DATA_SERVICE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_VOICE_ASSIST */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_RADIO_SERVICE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TELETEXT */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_NUMBER_ENTRY */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TERRESTRIAL_ANALOG */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TERRESTRIAL_DIGITAL */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_BS */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_CS */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_SATELLITE_SERVICE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_NETWORK */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_ANTENNA_CABLE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_1 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_2 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_3 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_HDMI_4 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPOSITE_1 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPOSITE_2 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPONENT_1 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_COMPONENT_2 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_INPUT_VGA_1 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_ZOOM_MODE */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_CONTENTS_MENU */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_MEDIA_CONTEXT_MENU */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_TV_TIMER_PROGRAMMING */ + SDL_SCANCODE_HELP, /* AKEYCODE_HELP */ }; static SDL_Scancode diff --git a/src/video/android/SDL_androidkeyboard.h b/src/video/android/SDL_androidkeyboard.h index 041987aca..3f643c305 100644 --- a/src/video/android/SDL_androidkeyboard.h +++ b/src/video/android/SDL_androidkeyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidmessagebox.c b/src/video/android/SDL_androidmessagebox.c index a55afb376..1783b9cd5 100644 --- a/src/video/android/SDL_androidmessagebox.c +++ b/src/video/android/SDL_androidmessagebox.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_androidmessagebox.h b/src/video/android/SDL_androidmessagebox.h index bc439cbeb..b732a2a0b 100644 --- a/src/video/android/SDL_androidmessagebox.h +++ b/src/video/android/SDL_androidmessagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidmouse.c b/src/video/android/SDL_androidmouse.c new file mode 100644 index 000000000..795b2aabf --- /dev/null +++ b/src/video/android/SDL_androidmouse.c @@ -0,0 +1,84 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..72b3deb38 --- /dev/null +++ b/src/video/android/SDL_androidmouse.h @@ -0,0 +1,31 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..b7ba3860f 100644 --- a/src/video/android/SDL_androidtouch.c +++ b/src/video/android/SDL_androidtouch.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -24,13 +24,12 @@ #include +#include "SDL_hints.h" #include "SDL_events.h" -#include "../../events/SDL_mouse_c.h" -#include "../../events/SDL_touch_c.h" #include "SDL_log.h" - #include "SDL_androidtouch.h" - +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_touch_c.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..73a934fe3 100644 --- a/src/video/android/SDL_androidtouch.h +++ b/src/video/android/SDL_androidtouch.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..983f3aa30 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..fc6e60e8c 100644 --- a/src/video/android/SDL_androidvideo.h +++ b/src/video/android/SDL_androidvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/android/SDL_androidwindow.c b/src/video/android/SDL_androidwindow.c index 32446dd35..46eaeb2a0 100644 --- a/src/video/android/SDL_androidwindow.c +++ b/src/video/android/SDL_androidwindow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/android/SDL_androidwindow.h b/src/video/android/SDL_androidwindow.h index 9228b0f54..aa9283bc6 100644 --- a/src/video/android/SDL_androidwindow.h +++ b/src/video/android/SDL_androidwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoaclipboard.h b/src/video/cocoa/SDL_cocoaclipboard.h index 0a5e0dc0d..d86a75ef6 100644 --- a/src/video/cocoa/SDL_cocoaclipboard.h +++ b/src/video/cocoa/SDL_cocoaclipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoaclipboard.m b/src/video/cocoa/SDL_cocoaclipboard.m index bf3b90955..733074457 100644 --- a/src/video/cocoa/SDL_cocoaclipboard.m +++ b/src/video/cocoa/SDL_cocoaclipboard.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoaevents.h b/src/video/cocoa/SDL_cocoaevents.h index 687cf647e..f92a4a94b 100644 --- a/src/video/cocoa/SDL_cocoaevents.h +++ b/src/video/cocoa/SDL_cocoaevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..994da1825 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -26,6 +26,12 @@ #include "SDL_cocoavideo.h" #include "../../events/SDL_events_c.h" #include "SDL_assert.h" +#include "SDL_hints.h" + +/* This define was added in the 10.9 SDK. */ +#ifndef kIOPMAssertPreventUserIdleDisplaySleep +#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep +#endif @interface SDLApplication : NSApplication @@ -61,11 +67,19 @@ - (id)init { 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 +87,65 @@ - (id)init - (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 +314,26 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam { @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); + const char *hint = SDL_GetHint(SDL_HINT_MAC_BACKGROUND_APP); + if (!hint || *hint == '0') { +#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 +365,8 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam { @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 +408,35 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam } }} +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_cocoakeyboard.h b/src/video/cocoa/SDL_cocoakeyboard.h index a85f9b7b0..e206bd3a6 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.h +++ b/src/video/cocoa/SDL_cocoakeyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m index c621182b8..41ecf1f63 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.m +++ b/src/video/cocoa/SDL_cocoakeyboard.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamessagebox.h b/src/video/cocoa/SDL_cocoamessagebox.h index ff468a881..f9ac0c458 100644 --- a/src/video/cocoa/SDL_cocoamessagebox.h +++ b/src/video/cocoa/SDL_cocoamessagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamessagebox.m b/src/video/cocoa/SDL_cocoamessagebox.m index 5a8f78050..0998f7924 100644 --- a/src/video/cocoa/SDL_cocoamessagebox.m +++ b/src/video/cocoa/SDL_cocoamessagebox.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamodes.h b/src/video/cocoa/SDL_cocoamodes.h index 4f8e86324..57c22ebda 100644 --- a/src/video/cocoa/SDL_cocoamodes.h +++ b/src/video/cocoa/SDL_cocoamodes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index b3025c4f2..73b14ed7c 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -193,6 +193,7 @@ 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.h b/src/video/cocoa/SDL_cocoamouse.h index 336b84044..89e68caae 100644 --- a/src/video/cocoa/SDL_cocoamouse.h +++ b/src/video/cocoa/SDL_cocoamouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 8b933c27d..625d8f409 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -195,7 +195,22 @@ + (NSCursor *)invisibleCursor return 0; }} -static void +static SDL_Window * +SDL_FindWindowAtPoint(const int x, const int y) +{ + const SDL_Point pt = { x, y }; + SDL_Window *i; + for (i = SDL_GetVideoDevice()->windows; i; i = i->next) { + const SDL_Rect r = { i->x, i->y, i->w, i->h }; + if (SDL_PointInRect(&pt, &r)) { + return i; + } + } + + return NULL; +} + +static int Cocoa_WarpMouseGlobal(int x, int y) { SDL_Mouse *mouse = SDL_GetMouse(); @@ -204,10 +219,10 @@ + (NSCursor *)invisibleCursor if ([data->listener isMoving]) { DLog("Postponing warp, window being moved."); [data->listener setPendingMoveX:x Y:y]; - return; + return 0; } } - CGPoint point = CGPointMake((float)x, (float)y); + const CGPoint point = CGPointMake((float)x, (float)y); Cocoa_HandleMouseWarp(point.x, point.y); @@ -219,12 +234,19 @@ + (NSCursor *)invisibleCursor CGWarpMouseCursorPosition(point); CGSetLocalEventsSuppressionInterval(0.25); - if (!mouse->relative_mode && mouse->focus) { - /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our - * other implementations' APIs. - */ - SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x - mouse->focus->x, y - mouse->focus->y); + /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our + * other implementations' APIs. Send what's appropriate. + */ + if (!mouse->relative_mode) { + SDL_Window *win = SDL_FindWindowAtPoint(x, y); + SDL_SetMouseFocus(win); + if (win) { + SDL_assert(win == mouse->focus); + SDL_SendMouseMotion(win, mouse->mouseID, 0, x - win->x, y - win->y); + } } + + return 0; } static void @@ -399,6 +421,13 @@ + (NSCursor *)invisibleCursor 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 +439,7 @@ + (NSCursor *)invisibleCursor } 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_cocoamousetap.h b/src/video/cocoa/SDL_cocoamousetap.h index bf3e73838..f1041b182 100644 --- a/src/video/cocoa/SDL_cocoamousetap.h +++ b/src/video/cocoa/SDL_cocoamousetap.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoamousetap.m b/src/video/cocoa/SDL_cocoamousetap.m index c27428955..ca50ff962 100644 --- a/src/video/cocoa/SDL_cocoamousetap.m +++ b/src/video/cocoa/SDL_cocoamousetap.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoaopengl.h b/src/video/cocoa/SDL_cocoaopengl.h index 14fd3ab4a..6b18af1eb 100644 --- a/src/video/cocoa/SDL_cocoaopengl.h +++ b/src/video/cocoa/SDL_cocoaopengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoaopengl.m b/src/video/cocoa/SDL_cocoaopengl.m index 0bbbbcb72..d8e9c901c 100644 --- a/src/video/cocoa/SDL_cocoaopengl.m +++ b/src/video/cocoa/SDL_cocoaopengl.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -150,8 +150,8 @@ - (void)setWindow:(SDL_Window *)newWindow SDL_GLContext Cocoa_GL_CreateContext(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool; SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); SDL_DisplayData *displaydata = (SDL_DisplayData *)display->driverdata; SDL_bool lion_or_later = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; @@ -173,8 +173,6 @@ - (void)setWindow:(SDL_Window *)newWindow return NULL; } - pool = [[NSAutoreleasePool alloc] init]; - /* specify a profile if we're on Lion (10.7) or later. */ if (lion_or_later) { NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy; @@ -239,7 +237,6 @@ - (void)setWindow:(SDL_Window *)newWindow fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; if (fmt == nil) { SDL_SetError("Failed creating OpenGL pixel format"); - [pool release]; return NULL; } @@ -253,12 +250,9 @@ - (void)setWindow:(SDL_Window *)newWindow if (context == nil) { SDL_SetError("Failed creating OpenGL context"); - [pool release]; return NULL; } - [pool release]; - if ( Cocoa_GL_MakeCurrent(_this, window, context) < 0 ) { Cocoa_GL_DeleteContext(_this, context); SDL_SetError("Failed making OpenGL context current"); @@ -306,15 +300,12 @@ - (void)setWindow:(SDL_Window *)newWindow /*_this->gl_config.minor_version = glversion_minor;*/ } return context; -} +}} int Cocoa_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +{ @autoreleasepool { - NSAutoreleasePool *pool; - - pool = [[NSAutoreleasePool alloc] init]; - if (context) { SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context; [nscontext setWindow:window]; @@ -324,9 +315,8 @@ - (void)setWindow:(SDL_Window *)newWindow [NSOpenGLContext clearCurrentContext]; } - [pool release]; return 0; -} +}} void Cocoa_GL_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) @@ -352,8 +342,8 @@ - (void)setWindow:(SDL_Window *)newWindow int Cocoa_GL_SetSwapInterval(_THIS, int interval) +{ @autoreleasepool { - NSAutoreleasePool *pool; NSOpenGLContext *nscontext; GLint value; int status; @@ -362,8 +352,6 @@ - (void)setWindow:(SDL_Window *)newWindow return SDL_SetError("Late swap tearing currently unsupported"); } - pool = [[NSAutoreleasePool alloc] init]; - nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); if (nscontext != nil) { value = interval; @@ -373,57 +361,44 @@ - (void)setWindow:(SDL_Window *)newWindow status = SDL_SetError("No current OpenGL context"); } - [pool release]; return status; -} +}} int Cocoa_GL_GetSwapInterval(_THIS) +{ @autoreleasepool { - NSAutoreleasePool *pool; NSOpenGLContext *nscontext; GLint value; int status = 0; - pool = [[NSAutoreleasePool alloc] init]; - nscontext = (NSOpenGLContext*)SDL_GL_GetCurrentContext(); if (nscontext != nil) { [nscontext getValues:&value forParameter:NSOpenGLCPSwapInterval]; status = (int)value; } - [pool release]; return status; -} +}} void Cocoa_GL_SwapWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool; - - pool = [[NSAutoreleasePool alloc] init]; - SDLOpenGLContext* nscontext = (SDLOpenGLContext*)SDL_GL_GetCurrentContext(); [nscontext flushBuffer]; [nscontext updateIfNeeded]; - - [pool release]; -} +}} void Cocoa_GL_DeleteContext(_THIS, SDL_GLContext context) +{ @autoreleasepool { - NSAutoreleasePool *pool; SDLOpenGLContext *nscontext = (SDLOpenGLContext *)context; - pool = [[NSAutoreleasePool alloc] init]; - [nscontext setWindow:NULL]; [nscontext release]; - - [pool release]; -} +}} #endif /* SDL_VIDEO_OPENGL_CGL */ diff --git a/src/video/cocoa/SDL_cocoashape.h b/src/video/cocoa/SDL_cocoashape.h index 0ab9980e3..e7fd185d3 100644 --- a/src/video/cocoa/SDL_cocoashape.h +++ b/src/video/cocoa/SDL_cocoashape.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/cocoa/SDL_cocoashape.m b/src/video/cocoa/SDL_cocoashape.m index 61d800b6a..1dce56799 100644 --- a/src/video/cocoa/SDL_cocoashape.m +++ b/src/video/cocoa/SDL_cocoashape.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -75,11 +75,11 @@ int Cocoa_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode) +{ @autoreleasepool { SDL_ShapeData* data = (SDL_ShapeData*)shaper->driverdata; SDL_WindowData* windata = (SDL_WindowData*)shaper->window->driverdata; SDL_CocoaClosure closure; - NSAutoreleasePool *pool = NULL; if(data->saved == SDL_TRUE) { [data->context restoreGraphicsState]; data->saved = SDL_FALSE; @@ -93,16 +93,14 @@ NSRectFill([[windata->nswindow contentView] frame]); data->shape = SDL_CalculateShapeTree(*shape_mode,shape); - pool = [[NSAutoreleasePool alloc] init]; closure.view = [windata->nswindow contentView]; closure.path = [NSBezierPath bezierPath]; closure.window = shaper->window; SDL_TraverseShapeTree(data->shape,&ConvertRects,&closure); [closure.path addClip]; - [pool release]; return 0; -} +}} int Cocoa_ResizeWindowShape(SDL_Window *window) diff --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h index 288c41fca..873f2573a 100644 --- a/src/video/cocoa/SDL_cocoavideo.h +++ b/src/video/cocoa/SDL_cocoavideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..c6b012967 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -76,6 +76,7 @@ device->GetDisplayModes = Cocoa_GetDisplayModes; device->SetDisplayMode = Cocoa_SetDisplayMode; device->PumpEvents = Cocoa_PumpEvents; + device->SuspendScreenSaver = Cocoa_SuspendScreenSaver; device->CreateWindow = Cocoa_CreateWindow; device->CreateWindowFrom = Cocoa_CreateWindowFrom; @@ -148,6 +149,9 @@ const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES); data->allow_spaces = ( (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && (!hint || (*hint != '0')) ); + /* The IOPM assertion API can disable the screensaver as of 10.7. */ + data->screensaver_use_iopm = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; + return 0; } diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index 65a2c2fcf..ed56600f1 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -70,6 +70,7 @@ typedef enum -(void) windowDidDeminiaturize:(NSNotification *) aNotification; -(void) windowDidBecomeKey:(NSNotification *) aNotification; -(void) windowDidResignKey:(NSNotification *) aNotification; +-(void) windowDidChangeBackingProperties:(NSNotification *) aNotification; -(void) windowWillEnterFullScreen:(NSNotification *) aNotification; -(void) windowDidEnterFullScreen:(NSNotification *) aNotification; -(void) windowWillExitFullScreen:(NSNotification *) aNotification; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 29bba457c..0378e48a9 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -34,6 +34,7 @@ #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" #include "../../events/SDL_windowevents_c.h" +#include "../../events/SDL_dropevents_c.h" #include "SDL_cocoavideo.h" #include "SDL_cocoashape.h" #include "SDL_cocoamouse.h" @@ -52,15 +53,21 @@ #define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN) -@interface SDLWindow : NSWindow +@interface SDLWindow : NSWindow /* These are needed for borderless/fullscreen windows */ - (BOOL)canBecomeKeyWindow; - (BOOL)canBecomeMainWindow; - (void)sendEvent:(NSEvent *)event; - (void)doCommandBySelector:(SEL)aSelector; + +/* Handle drag-and-drop of files onto the SDL window. */ +- (NSDragOperation)draggingEntered:(id )sender; +- (BOOL)performDragOperation:(id )sender; +- (BOOL)wantsPeriodicDraggingUpdates; @end @implementation SDLWindow + - (BOOL)canBecomeKeyWindow { return YES; @@ -96,6 +103,73 @@ - (void)doCommandBySelector:(SEL)aSelector { /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/ } + +- (NSDragOperation)draggingEntered:(id )sender +{ + if (([sender draggingSourceOperationMask] & NSDragOperationGeneric) == NSDragOperationGeneric) { + return NSDragOperationGeneric; + } + + return NSDragOperationNone; /* no idea what to do with this, reject it. */ +} + +- (BOOL)performDragOperation:(id )sender +{ @autoreleasepool +{ + NSPasteboard *pasteboard = [sender draggingPasteboard]; + NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType]; + NSString *desiredType = [pasteboard availableTypeFromArray:types]; + if (desiredType == nil) { + return NO; /* can't accept anything that's being dropped here. */ + } + + NSData *data = [pasteboard dataForType:desiredType]; + if (data == nil) { + return NO; + } + + SDL_assert([desiredType isEqualToString:NSFilenamesPboardType]); + NSArray *array = [pasteboard propertyListForType:@"NSFilenamesPboardType"]; + + for (NSString *path in array) { + NSURL *fileURL = [[NSURL fileURLWithPath:path] autorelease]; + NSNumber *isAlias = nil; + + /* Functionality for resolving URL aliases was added with OS X 10.6. */ + if ([fileURL respondsToSelector:@selector(getResourceValue:forKey:error:)]) { + [fileURL getResourceValue:&isAlias forKey:NSURLIsAliasFileKey error:nil]; + } + + /* If the URL is an alias, resolve it. */ + if ([isAlias boolValue]) { + NSURLBookmarkResolutionOptions opts = NSURLBookmarkResolutionWithoutMounting | NSURLBookmarkResolutionWithoutUI; + NSData *bookmark = [NSURL bookmarkDataWithContentsOfURL:fileURL error:nil]; + if (bookmark != nil) { + NSURL *resolvedURL = [NSURL URLByResolvingBookmarkData:bookmark + options:opts + relativeToURL:nil + bookmarkDataIsStale:nil + error:nil]; + + if (resolvedURL != nil) { + fileURL = resolvedURL; + } + } + } + + if (!SDL_SendDropFile([[fileURL path] UTF8String])) { + return NO; + } + } + + return YES; +}} + +- (BOOL)wantsPeriodicDraggingUpdates +{ + return NO; +} + @end @@ -203,6 +277,7 @@ - (void)listen:(SDL_WindowData *)data [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window]; [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window]; [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window]; + [center addObserver:self selector:@selector(windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window]; [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window]; [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window]; [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window]; @@ -322,7 +397,6 @@ - (void)close NSNotificationCenter *center; NSWindow *window = _data->nswindow; NSView *view = [window contentView]; - NSArray *windows = nil; center = [NSNotificationCenter defaultCenter]; @@ -334,6 +408,7 @@ - (void)close [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window]; [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window]; [center removeObserver:self name:NSWindowDidResignKeyNotification object:window]; + [center removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window]; [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window]; [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window]; [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window]; @@ -350,25 +425,6 @@ - (void)close 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 @@ -499,13 +555,15 @@ - (void)windowDidBecomeKey:(NSNotification *)aNotification { SDL_Window *window = _data->window; SDL_Mouse *mouse = SDL_GetMouse(); - if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) { - mouse->SetRelativeMouseMode(SDL_TRUE); - } /* We're going to get keyboard events, since we're key. */ + /* This needs to be done before restoring the relative mouse mode. */ SDL_SetKeyboardFocus(window); + if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) { + mouse->SetRelativeMouseMode(SDL_TRUE); + } + /* If we just gained focus we need the updated mouse position */ if (!mouse->relative_mode) { NSPoint point; @@ -550,6 +608,22 @@ - (void)windowDidResignKey:(NSNotification *)aNotification } } +- (void)windowDidChangeBackingProperties:(NSNotification *)aNotification +{ + NSNumber *oldscale = [[aNotification userInfo] objectForKey:NSBackingPropertyOldScaleFactorKey]; + + if (inFullscreenTransition) { + return; + } + + if ([oldscale doubleValue] != [_data->nswindow backingScaleFactor]) { + /* Force a resize event when the backing scale factor changes. */ + _data->window->w = 0; + _data->window->h = 0; + [self windowDidResize:aNotification]; + } +} + - (void)windowWillEnterFullScreen:(NSNotification *)aNotification { SDL_Window *window = _data->window; @@ -699,6 +773,14 @@ - (void)mouseDown:(NSEvent *)theEvent { int button; + /* Ignore events that aren't inside the client area (i.e. title bar.) */ + if ([theEvent window]) { + const NSRect windowRect = [[[theEvent window] contentView] frame]; + if (!NSPointInRect([theEvent locationInWindow], windowRect)) { + return; + } + } + if ([self processHitTest:theEvent]) { return; /* dragging, drop event. */ } @@ -856,6 +938,25 @@ - (void)scrollWheel:(NSEvent *)theEvent - (void)touchesBeganWithEvent:(NSEvent *) theEvent { + NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil]; + int existingTouchCount = 0; + + for (NSTouch* touch in touches) { + if ([touch phase] != NSTouchPhaseBegan) { + existingTouchCount++; + } + } + if (existingTouchCount == 0) { + SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device]; + int numFingers = SDL_GetNumTouchFingers(touchID); + DLog("Reset Lost Fingers: %d", numFingers); + for (--numFingers; numFingers >= 0; --numFingers) { + SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers); + SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0); + } + } + + DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount); [self handleTouches:NSTouchPhaseBegan withEvent:theEvent]; } @@ -880,10 +981,8 @@ - (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent for (NSTouch *touch in touches) { const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device]; - if (!SDL_GetTouch(touchId)) { - if (SDL_AddTouch(touchId, "") < 0) { - return; - } + if (SDL_AddTouch(touchId, "") < 0) { + return; } const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity]; @@ -911,14 +1010,29 @@ - (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent @end -@interface SDLView : NSView +@interface SDLView : NSView { + SDL_Window *_sdlWindow; +} + +- (void)setSDLWindow:(SDL_Window*)window; /* The default implementation doesn't pass rightMouseDown to responder chain */ - (void)rightMouseDown:(NSEvent *)theEvent; - (BOOL)mouseDownCanMoveWindow; +- (void)drawRect:(NSRect)dirtyRect; @end @implementation SDLView +- (void)setSDLWindow:(SDL_Window*)window +{ + _sdlWindow = window; +} + +- (void)drawRect:(NSRect)dirtyRect +{ + SDL_SendWindowEvent(_sdlWindow, SDL_WINDOWEVENT_EXPOSED, 0, 0); +} + - (void)rightMouseDown:(NSEvent *)theEvent { [[self nextResponder] rightMouseDown:theEvent]; @@ -949,8 +1063,8 @@ - (void)resetCursorRects static int SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created) +{ @autoreleasepool { - NSAutoreleasePool *pool; SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; SDL_WindowData *data; @@ -965,8 +1079,6 @@ - (void)resetCursorRects data->videodata = videodata; data->nscontexts = [[NSMutableArray alloc] init]; - pool = [[NSAutoreleasePool alloc] init]; - /* Create an event listener for the window */ data->listener = [[Cocoa_WindowListener alloc] init]; @@ -1028,16 +1140,15 @@ - (void)resetCursorRects [nswindow setOneShot:NO]; /* All done! */ - [pool release]; window->driverdata = data; return 0; -} +}} int Cocoa_CreateWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *nswindow; SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); NSRect rect; @@ -1072,9 +1183,7 @@ - (void)resetCursorRects nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen]; } @catch (NSException *e) { - SDL_SetError("%s", [[e reason] UTF8String]); - [pool release]; - return -1; + return SDL_SetError("%s", [[e reason] UTF8String]); } [nswindow setBackgroundColor:[NSColor blackColor]]; @@ -1090,7 +1199,8 @@ - (void)resetCursorRects /* Create a default view for this window */ rect = [nswindow contentRectForFrameRect:[nswindow frame]]; - NSView *contentView = [[SDLView alloc] initWithFrame:rect]; + SDLView *contentView = [[SDLView alloc] initWithFrame:rect]; + [contentView setSDLWindow:window]; if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) { @@ -1101,70 +1211,58 @@ - (void)resetCursorRects [nswindow setContentView: contentView]; [contentView release]; - [pool release]; + /* Allow files and folders to be dragged onto the window by users */ + [nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]]; if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) { [nswindow release]; return -1; } return 0; -} +}} int Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) +{ @autoreleasepool { - NSAutoreleasePool *pool; NSWindow *nswindow = (NSWindow *) data; NSString *title; - pool = [[NSAutoreleasePool alloc] init]; - /* Query the title from the existing window */ title = [nswindow title]; if (title) { window->title = SDL_strdup([title UTF8String]); } - [pool release]; - return SetupWindowData(_this, window, nswindow, SDL_FALSE); -} +}} void Cocoa_SetWindowTitle(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + const char *title = window->title ? window->title : ""; 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:title]; [nswindow setTitle:string]; [string release]; - - [pool release]; -} +}} void Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSImage *nsimage = Cocoa_CreateImage(icon); if (nsimage) { [NSApp setApplicationIconImage:nsimage]; } - - [pool release]; -} +}} void Cocoa_SetWindowPosition(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = windata->nswindow; NSRect rect; @@ -1182,14 +1280,12 @@ - (void)resetCursorRects s_moveHack = moveHack; ScheduleContextUpdates(windata); - - [pool release]; -} +}} void Cocoa_SetWindowSize(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = windata->nswindow; NSSize size; @@ -1199,14 +1295,12 @@ - (void)resetCursorRects [nswindow setContentSize:size]; ScheduleContextUpdates(windata); - - [pool release]; -} +}} void Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; NSSize minSize; @@ -1214,14 +1308,12 @@ - (void)resetCursorRects minSize.height = window->min_h; [windata->nswindow setContentMinSize:minSize]; - - [pool release]; -} +}} void Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; NSSize maxSize; @@ -1229,14 +1321,12 @@ - (void)resetCursorRects maxSize.height = window->max_h; [windata->nswindow setContentMaxSize:maxSize]; - - [pool release]; -} +}} void Cocoa_ShowWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata); NSWindow *nswindow = windowData->nswindow; @@ -1245,23 +1335,21 @@ - (void)resetCursorRects [nswindow makeKeyAndOrderFront:nil]; [windowData->listener resumeVisibleObservation]; } - [pool release]; -} +}} void Cocoa_HideWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow; [nswindow orderOut:nil]; - [pool release]; -} +}} void Cocoa_RaiseWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata); NSWindow *nswindow = windowData->nswindow; @@ -1274,28 +1362,24 @@ - (void)resetCursorRects [nswindow makeKeyAndOrderFront:nil]; } [windowData->listener resumeVisibleObservation]; - - [pool release]; -} +}} void Cocoa_MaximizeWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *windata = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = windata->nswindow; [nswindow zoom:nil]; ScheduleContextUpdates(windata); - - [pool release]; -} +}} void Cocoa_MinimizeWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *data = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = data->nswindow; @@ -1304,13 +1388,12 @@ - (void)resetCursorRects } else { [nswindow miniaturize:nil]; } - [pool release]; -} +}} void Cocoa_RestoreWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow; if ([nswindow isMiniaturized]) { @@ -1318,8 +1401,7 @@ - (void)resetCursorRects } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) { [nswindow zoom:nil]; } - [pool release]; -} +}} static NSWindow * Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style) @@ -1332,6 +1414,7 @@ - (void)resetCursorRects [data->listener close]; data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]]; [data->nswindow setContentView:[nswindow contentView]]; + [data->nswindow registerForDraggedTypes:[NSArray arrayWithObject:(NSString *)kUTTypeFileURL]]; /* See comment in SetupWindowData. */ [data->nswindow setOneShot:NO]; [data->listener listen:data]; @@ -1343,21 +1426,20 @@ - (void)resetCursorRects void Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if (SetWindowStyle(window, GetWindowStyle(window))) { if (bordered) { Cocoa_SetWindowTitle(_this, window); /* this got blanked out. */ } } - [pool release]; -} +}} void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *data = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = data->nswindow; NSRect rect; @@ -1397,6 +1479,11 @@ - (void)resetCursorRects if ([nswindow respondsToSelector: @selector(setStyleMask:)]) { [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)]; + + /* Hack to restore window decorations on Mac OS X 10.10 */ + NSRect frameRect = [nswindow frame]; + [nswindow setFrame:NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width + 1, frameRect.size.height) display:NO]; + [nswindow setFrame:frameRect display:NO]; } else { nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window)); } @@ -1431,9 +1518,7 @@ - (void)resetCursorRects } ScheduleContextUpdates(data); - - [pool release]; -} +}} int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp) @@ -1516,8 +1601,8 @@ - (void)resetCursorRects void Cocoa_DestroyWindow(_THIS, SDL_Window * window) +{ @autoreleasepool { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *data = (SDL_WindowData *) window->driverdata; if (data) { @@ -1537,9 +1622,7 @@ - (void)resetCursorRects SDL_free(data); } window->driverdata = NULL; - - [pool release]; -} +}} SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) @@ -1571,9 +1654,9 @@ - (void)resetCursorRects SDL_bool Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state) +{ @autoreleasepool { SDL_bool succeeded = SDL_FALSE; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDL_WindowData *data = (SDL_WindowData *) window->driverdata; if ([data->listener setFullscreenSpace:(state ? YES : NO)]) { @@ -1594,10 +1677,8 @@ take effect properly (e.g. setting the window size, etc.) } } - [pool release]; - return succeeded; -} +}} int Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled) diff --git a/src/video/directfb/SDL_DirectFB_WM.c b/src/video/directfb/SDL_DirectFB_WM.c index b48a10698..f6e1dea48 100644 --- a/src/video/directfb/SDL_DirectFB_WM.c +++ b/src/video/directfb/SDL_DirectFB_WM.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_WM.h b/src/video/directfb/SDL_DirectFB_WM.h index 0bfe07e0d..828bd9528 100644 --- a/src/video/directfb/SDL_DirectFB_WM.h +++ b/src/video/directfb/SDL_DirectFB_WM.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_dyn.c b/src/video/directfb/SDL_DirectFB_dyn.c index 49c737b04..4dfd08c1e 100644 --- a/src/video/directfb/SDL_DirectFB_dyn.c +++ b/src/video/directfb/SDL_DirectFB_dyn.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_dyn.h b/src/video/directfb/SDL_DirectFB_dyn.h index ba57f4533..81d2b163d 100644 --- a/src/video/directfb/SDL_DirectFB_dyn.h +++ b/src/video/directfb/SDL_DirectFB_dyn.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_events.c b/src/video/directfb/SDL_DirectFB_events.c index 9c6c79407..8508f2a99 100644 --- a/src/video/directfb/SDL_DirectFB_events.c +++ b/src/video/directfb/SDL_DirectFB_events.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_events.h b/src/video/directfb/SDL_DirectFB_events.h index db5c7f0fd..fe205d1de 100644 --- a/src/video/directfb/SDL_DirectFB_events.h +++ b/src/video/directfb/SDL_DirectFB_events.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_modes.c b/src/video/directfb/SDL_DirectFB_modes.c index 73de1fc01..ab13b7ee7 100644 --- a/src/video/directfb/SDL_DirectFB_modes.c +++ b/src/video/directfb/SDL_DirectFB_modes.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_modes.h b/src/video/directfb/SDL_DirectFB_modes.h index 7999f606c..c847f1821 100644 --- a/src/video/directfb/SDL_DirectFB_modes.h +++ b/src/video/directfb/SDL_DirectFB_modes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_mouse.c b/src/video/directfb/SDL_DirectFB_mouse.c index 93798f8e3..caa9eeec3 100644 --- a/src/video/directfb/SDL_DirectFB_mouse.c +++ b/src/video/directfb/SDL_DirectFB_mouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_mouse.h b/src/video/directfb/SDL_DirectFB_mouse.h index 7ac486820..3f62c01bf 100644 --- a/src/video/directfb/SDL_DirectFB_mouse.h +++ b/src/video/directfb/SDL_DirectFB_mouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_opengl.c b/src/video/directfb/SDL_DirectFB_opengl.c index 1a378792d..edddd32cd 100644 --- a/src/video/directfb/SDL_DirectFB_opengl.c +++ b/src/video/directfb/SDL_DirectFB_opengl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_opengl.h b/src/video/directfb/SDL_DirectFB_opengl.h index ecd5bbafb..454aa249d 100644 --- a/src/video/directfb/SDL_DirectFB_opengl.h +++ b/src/video/directfb/SDL_DirectFB_opengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_render.c b/src/video/directfb/SDL_DirectFB_render.c index 3a0220ea8..003e4a772 100644 --- a/src/video/directfb/SDL_DirectFB_render.c +++ b/src/video/directfb/SDL_DirectFB_render.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_render.h b/src/video/directfb/SDL_DirectFB_render.h index 5405a5e5f..0cd4bd321 100644 --- a/src/video/directfb/SDL_DirectFB_render.h +++ b/src/video/directfb/SDL_DirectFB_render.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_shape.c b/src/video/directfb/SDL_DirectFB_shape.c index 64e91f61f..4c5715723 100644 --- a/src/video/directfb/SDL_DirectFB_shape.c +++ b/src/video/directfb/SDL_DirectFB_shape.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_shape.h b/src/video/directfb/SDL_DirectFB_shape.h index 99bff8004..27304712b 100644 --- a/src/video/directfb/SDL_DirectFB_shape.h +++ b/src/video/directfb/SDL_DirectFB_shape.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_video.c b/src/video/directfb/SDL_DirectFB_video.c index 0d107dc98..dbf890be0 100644 --- a/src/video/directfb/SDL_DirectFB_video.c +++ b/src/video/directfb/SDL_DirectFB_video.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/directfb/SDL_DirectFB_video.h b/src/video/directfb/SDL_DirectFB_video.h index 82250b63d..b722bbd9f 100644 --- a/src/video/directfb/SDL_DirectFB_video.h +++ b/src/video/directfb/SDL_DirectFB_video.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_window.c b/src/video/directfb/SDL_DirectFB_window.c index 42064be4c..b8a94b45a 100644 --- a/src/video/directfb/SDL_DirectFB_window.c +++ b/src/video/directfb/SDL_DirectFB_window.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/directfb/SDL_DirectFB_window.h b/src/video/directfb/SDL_DirectFB_window.h index a16d16095..9290abcdc 100644 --- a/src/video/directfb/SDL_DirectFB_window.h +++ b/src/video/directfb/SDL_DirectFB_window.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/dummy/SDL_nullevents.c b/src/video/dummy/SDL_nullevents.c index 22a34bbaa..d7df0dcbe 100644 --- a/src/video/dummy/SDL_nullevents.c +++ b/src/video/dummy/SDL_nullevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/dummy/SDL_nullevents_c.h b/src/video/dummy/SDL_nullevents_c.h index 41e28caa4..211684644 100644 --- a/src/video/dummy/SDL_nullevents_c.h +++ b/src/video/dummy/SDL_nullevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/dummy/SDL_nullframebuffer.c b/src/video/dummy/SDL_nullframebuffer.c index 2f1bcab7a..74eeb3101 100644 --- a/src/video/dummy/SDL_nullframebuffer.c +++ b/src/video/dummy/SDL_nullframebuffer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/dummy/SDL_nullframebuffer_c.h b/src/video/dummy/SDL_nullframebuffer_c.h index 4c582d7d4..f75c70e82 100644 --- a/src/video/dummy/SDL_nullframebuffer_c.h +++ b/src/video/dummy/SDL_nullframebuffer_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/dummy/SDL_nullvideo.c b/src/video/dummy/SDL_nullvideo.c index 28147bd18..96cee9213 100644 --- a/src/video/dummy/SDL_nullvideo.c +++ b/src/video/dummy/SDL_nullvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/dummy/SDL_nullvideo.h b/src/video/dummy/SDL_nullvideo.h index b0a76c064..90ed3bc81 100644 --- a/src/video/dummy/SDL_nullvideo.h +++ b/src/video/dummy/SDL_nullvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c new file mode 100644 index 000000000..79fa310f8 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -0,0 +1,644 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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 ) + +/* +.keyCode to scancode +https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent +https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode +*/ +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 = 1; + if (SDL_AddTouch(deviceId, "") < 0) { + return 0; + } + + for (i = 0; i < touchEvent->numTouches; i++) { + SDL_FingerID id; + float x, y; + + if (!touchEvent->touches[i].isChanged) + continue; + + id = touchEvent->touches[i].identifier; + x = touchEvent->touches[i].canvasX / (float)window_data->windowed_width; + y = touchEvent->touches[i].canvasY / (float)window_data->windowed_height; + + 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..ea5c3f5b3 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenevents.h @@ -0,0 +1,36 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..a8f927e57 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -0,0 +1,136 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..01ed37d1c --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenframebuffer.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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_emscriptenframebuffer_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..5748d1c2e --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenmouse.c @@ -0,0 +1,232 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..1d5d2e9e6 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenmouse.h @@ -0,0 +1,39 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..6e9624d76 --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenopengles.c @@ -0,0 +1,117 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..9c356854f --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenopengles.h @@ -0,0 +1,49 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..4ce0a036b --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenvideo.c @@ -0,0 +1,319 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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..519e3fc3e --- /dev/null +++ b/src/video/emscripten/SDL_emscriptenvideo.h @@ -0,0 +1,52 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 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/haiku/SDL_BWin.h b/src/video/haiku/SDL_BWin.h index e6de5b0d0..b4e347d04 100644 --- a/src/video/haiku/SDL_BWin.h +++ b/src/video/haiku/SDL_BWin.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bclipboard.cc b/src/video/haiku/SDL_bclipboard.cc index 9760d0fba..1a10b6bfe 100644 --- a/src/video/haiku/SDL_bclipboard.cc +++ b/src/video/haiku/SDL_bclipboard.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bclipboard.h b/src/video/haiku/SDL_bclipboard.h index 418ba90b9..654c6c59e 100644 --- a/src/video/haiku/SDL_bclipboard.h +++ b/src/video/haiku/SDL_bclipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bevents.cc b/src/video/haiku/SDL_bevents.cc index 2ffc47138..ec7d01251 100644 --- a/src/video/haiku/SDL_bevents.cc +++ b/src/video/haiku/SDL_bevents.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bevents.h b/src/video/haiku/SDL_bevents.h index 9b53f39aa..ffb9ba5ea 100644 --- a/src/video/haiku/SDL_bevents.h +++ b/src/video/haiku/SDL_bevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bframebuffer.cc b/src/video/haiku/SDL_bframebuffer.cc index 0c5639606..3eb835b2f 100644 --- a/src/video/haiku/SDL_bframebuffer.cc +++ b/src/video/haiku/SDL_bframebuffer.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bframebuffer.h b/src/video/haiku/SDL_bframebuffer.h index b0b73d3ca..f3fbd96fc 100644 --- a/src/video/haiku/SDL_bframebuffer.h +++ b/src/video/haiku/SDL_bframebuffer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bkeyboard.cc b/src/video/haiku/SDL_bkeyboard.cc index 97f34b23b..e12d30ba2 100644 --- a/src/video/haiku/SDL_bkeyboard.cc +++ b/src/video/haiku/SDL_bkeyboard.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bkeyboard.h b/src/video/haiku/SDL_bkeyboard.h index 0acb42c94..edf7643de 100644 --- a/src/video/haiku/SDL_bkeyboard.h +++ b/src/video/haiku/SDL_bkeyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bmodes.cc b/src/video/haiku/SDL_bmodes.cc index b56442b09..c5da410fd 100644 --- a/src/video/haiku/SDL_bmodes.cc +++ b/src/video/haiku/SDL_bmodes.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bmodes.h b/src/video/haiku/SDL_bmodes.h index 3df862d30..e73c090e2 100644 --- a/src/video/haiku/SDL_bmodes.h +++ b/src/video/haiku/SDL_bmodes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bopengl.cc b/src/video/haiku/SDL_bopengl.cc index 245cec12e..258699929 100644 --- a/src/video/haiku/SDL_bopengl.cc +++ b/src/video/haiku/SDL_bopengl.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bopengl.h b/src/video/haiku/SDL_bopengl.h index b046de4e4..e325687f7 100644 --- a/src/video/haiku/SDL_bopengl.h +++ b/src/video/haiku/SDL_bopengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bvideo.cc b/src/video/haiku/SDL_bvideo.cc index a526893f8..9fe24d347 100644 --- a/src/video/haiku/SDL_bvideo.cc +++ b/src/video/haiku/SDL_bvideo.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bvideo.h b/src/video/haiku/SDL_bvideo.h index 925c8b5b2..72292d00d 100644 --- a/src/video/haiku/SDL_bvideo.h +++ b/src/video/haiku/SDL_bvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bwindow.cc b/src/video/haiku/SDL_bwindow.cc index c0a3cee01..dc3ddb5df 100644 --- a/src/video/haiku/SDL_bwindow.cc +++ b/src/video/haiku/SDL_bwindow.cc @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/haiku/SDL_bwindow.h b/src/video/haiku/SDL_bwindow.h index 5a3934978..e1c59134f 100644 --- a/src/video/haiku/SDL_bwindow.h +++ b/src/video/haiku/SDL_bwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirdyn.c b/src/video/mir/SDL_mirdyn.c index f544d06ec..ffb1e9e23 100644 --- a/src/video/mir/SDL_mirdyn.c +++ b/src/video/mir/SDL_mirdyn.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirdyn.h b/src/video/mir/SDL_mirdyn.h index 3bd62e14e..1dadfc6d6 100644 --- a/src/video/mir/SDL_mirdyn.h +++ b/src/video/mir/SDL_mirdyn.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirevents.c b/src/video/mir/SDL_mirevents.c index b5829c7c7..8ff2cb3a4 100644 --- a/src/video/mir/SDL_mirevents.c +++ b/src/video/mir/SDL_mirevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/mir/SDL_mirevents.h b/src/video/mir/SDL_mirevents.h index 9219eed15..8caabc8a6 100644 --- a/src/video/mir/SDL_mirevents.h +++ b/src/video/mir/SDL_mirevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirframebuffer.c b/src/video/mir/SDL_mirframebuffer.c index 212c4a788..d1821cc44 100644 --- a/src/video/mir/SDL_mirframebuffer.c +++ b/src/video/mir/SDL_mirframebuffer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirframebuffer.h b/src/video/mir/SDL_mirframebuffer.h index b4860fe1f..328fb23dd 100644 --- a/src/video/mir/SDL_mirframebuffer.h +++ b/src/video/mir/SDL_mirframebuffer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirmouse.c b/src/video/mir/SDL_mirmouse.c index 72f4b6a3c..740ac20ef 100644 --- a/src/video/mir/SDL_mirmouse.c +++ b/src/video/mir/SDL_mirmouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -110,10 +110,10 @@ MIR_WarpMouse(SDL_Window* window, int x, int y) SDL_Unsupported(); } -static void +static int MIR_WarpMouseGlobal(int x, int y) { - SDL_Unsupported(); + return SDL_Unsupported(); } static int diff --git a/src/video/mir/SDL_mirmouse.h b/src/video/mir/SDL_mirmouse.h index fd4e47626..700cc6998 100644 --- a/src/video/mir/SDL_mirmouse.h +++ b/src/video/mir/SDL_mirmouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_miropengl.c b/src/video/mir/SDL_miropengl.c index 976b77272..b7c7ae80a 100644 --- a/src/video/mir/SDL_miropengl.c +++ b/src/video/mir/SDL_miropengl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_miropengl.h b/src/video/mir/SDL_miropengl.h index 0f4c97318..5a04ac8a1 100644 --- a/src/video/mir/SDL_miropengl.h +++ b/src/video/mir/SDL_miropengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirsym.h b/src/video/mir/SDL_mirsym.h index fe495e3e5..415df0c94 100644 --- a/src/video/mir/SDL_mirsym.h +++ b/src/video/mir/SDL_mirsym.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -26,7 +26,7 @@ SDL_MIR_SYM(MirDisplayConfiguration*,mir_connection_create_display_config,(MirCo SDL_MIR_SYM(MirSurface *,mir_connection_create_surface_sync,(MirConnection *connection, MirSurfaceParameters const *params)) SDL_MIR_SYM(void,mir_connection_get_available_surface_formats,(MirConnection* connection, MirPixelFormat* formats, unsigned const int format_size, unsigned int *num_valid_formats)) SDL_MIR_SYM(MirEGLNativeDisplayType,mir_connection_get_egl_native_display,(MirConnection *connection)) -SDL_MIR_SYM(int,mir_connection_is_valid,(MirConnection *connection)) +SDL_MIR_SYM(MirBool,mir_connection_is_valid,(MirConnection *connection)) SDL_MIR_SYM(void,mir_connection_release,(MirConnection *connection)) SDL_MIR_SYM(MirConnection *,mir_connect_sync,(char const *server, char const *app_name)) SDL_MIR_SYM(void,mir_display_config_destroy,(MirDisplayConfiguration* display_configuration)) @@ -34,10 +34,11 @@ SDL_MIR_SYM(MirEGLNativeWindowType,mir_surface_get_egl_native_window,(MirSurface SDL_MIR_SYM(char const *,mir_surface_get_error_message,(MirSurface *surface)) SDL_MIR_SYM(void,mir_surface_get_graphics_region,(MirSurface *surface, MirGraphicsRegion *graphics_region)) SDL_MIR_SYM(void,mir_surface_get_parameters,(MirSurface *surface, MirSurfaceParameters *parameters)) -SDL_MIR_SYM(int,mir_surface_is_valid,(MirSurface *surface)) +SDL_MIR_SYM(MirBool,mir_surface_is_valid,(MirSurface *surface)) SDL_MIR_SYM(void,mir_surface_release_sync,(MirSurface *surface)) SDL_MIR_SYM(void,mir_surface_set_event_handler,(MirSurface *surface, MirEventDelegate const *event_handler)) SDL_MIR_SYM(MirWaitHandle*,mir_surface_set_type,(MirSurface *surface, MirSurfaceType type)) +SDL_MIR_SYM(MirWaitHandle*,mir_surface_set_state,(MirSurface *surface, MirSurfaceState state)) SDL_MIR_SYM(void,mir_surface_swap_buffers_sync,(MirSurface *surface)) SDL_MIR_MODULE(XKBCOMMON) diff --git a/src/video/mir/SDL_mirvideo.c b/src/video/mir/SDL_mirvideo.c index 490e05718..176e9a128 100644 --- a/src/video/mir/SDL_mirvideo.c +++ b/src/video/mir/SDL_mirvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirvideo.h b/src/video/mir/SDL_mirvideo.h index 5a46d09c0..8db90b522 100644 --- a/src/video/mir/SDL_mirvideo.h +++ b/src/video/mir/SDL_mirvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/mir/SDL_mirwindow.c b/src/video/mir/SDL_mirwindow.c index cb8f1cb5f..513dbe24d 100644 --- a/src/video/mir/SDL_mirwindow.c +++ b/src/video/mir/SDL_mirwindow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -186,9 +186,9 @@ MIR_SetWindowFullscreen(_THIS, SDL_Window* window, return; if (fullscreen) { - MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_fullscreen); + MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_fullscreen); } else { - MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_restored); + MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_restored); } } @@ -200,7 +200,7 @@ MIR_MaximizeWindow(_THIS, SDL_Window* window) if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_maximized); + MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_maximized); } void @@ -211,7 +211,7 @@ MIR_MinimizeWindow(_THIS, SDL_Window* window) if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_minimized); + MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_minimized); } void @@ -222,7 +222,7 @@ MIR_RestoreWindow(_THIS, SDL_Window * window) if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_type(mir_window->surface, mir_surface_state_restored); + MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_restored); } #endif /* SDL_VIDEO_DRIVER_MIR */ diff --git a/src/video/mir/SDL_mirwindow.h b/src/video/mir/SDL_mirwindow.h index 411c1485f..577dfa417 100644 --- a/src/video/mir/SDL_mirwindow.h +++ b/src/video/mir/SDL_mirwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -63,7 +63,7 @@ MIR_RestoreWindow(_THIS, SDL_Window* window); extern SDL_bool MIR_GetWindowWMInfo(_THIS, SDL_Window* window, SDL_SysWMinfo* info); -#endif /* _SDL_mirwindow */ +#endif /* _SDL_mirwindow_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/nacl/SDL_naclevents.c b/src/video/nacl/SDL_naclevents.c index 5a4449a49..c552abb80 100644 --- a/src/video/nacl/SDL_naclevents.c +++ b/src/video/nacl/SDL_naclevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/nacl/SDL_naclevents_c.h b/src/video/nacl/SDL_naclevents_c.h index 6e3436833..5fa6f9914 100644 --- a/src/video/nacl/SDL_naclevents_c.h +++ b/src/video/nacl/SDL_naclevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/nacl/SDL_naclglue.c b/src/video/nacl/SDL_naclglue.c index 722f26ef4..127494e9e 100644 --- a/src/video/nacl/SDL_naclglue.c +++ b/src/video/nacl/SDL_naclglue.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -21,4 +21,4 @@ #include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_NACL -#endif /* SDL_VIDEO_DRIVER_NACL */ \ No newline at end of file +#endif /* SDL_VIDEO_DRIVER_NACL */ diff --git a/src/video/nacl/SDL_naclopengles.c b/src/video/nacl/SDL_naclopengles.c index 081cc8a4f..349d4bbd6 100644 --- a/src/video/nacl/SDL_naclopengles.c +++ b/src/video/nacl/SDL_naclopengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/nacl/SDL_naclopengles.h b/src/video/nacl/SDL_naclopengles.h index d5c3e97ef..bcbca7db4 100644 --- a/src/video/nacl/SDL_naclopengles.h +++ b/src/video/nacl/SDL_naclopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/nacl/SDL_naclvideo.c b/src/video/nacl/SDL_naclvideo.c index 90cc0f225..e9d014c85 100644 --- a/src/video/nacl/SDL_naclvideo.c +++ b/src/video/nacl/SDL_naclvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -180,4 +180,4 @@ void NACL_VideoQuit(_THIS) { } #endif /* SDL_VIDEO_DRIVER_NACL */ -/* vi: set ts=4 sw=4 expandtab: */ \ No newline at end of file +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/nacl/SDL_naclvideo.h b/src/video/nacl/SDL_naclvideo.h index 7e1c77fe6..d9dc16303 100644 --- a/src/video/nacl/SDL_naclvideo.h +++ b/src/video/nacl/SDL_naclvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/nacl/SDL_naclwindow.c b/src/video/nacl/SDL_naclwindow.c index 046331e03..73c703370 100644 --- a/src/video/nacl/SDL_naclwindow.c +++ b/src/video/nacl/SDL_naclwindow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/nacl/SDL_naclwindow.h b/src/video/nacl/SDL_naclwindow.h index ee94e60c1..3d6f375b9 100644 --- a/src/video/nacl/SDL_naclwindow.h +++ b/src/video/nacl/SDL_naclwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/pandora/SDL_pandora.c b/src/video/pandora/SDL_pandora.c index 10ca38241..2a0f4dcc3 100644 --- a/src/video/pandora/SDL_pandora.c +++ b/src/video/pandora/SDL_pandora.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/pandora/SDL_pandora.h b/src/video/pandora/SDL_pandora.h index 802365eed..2dbbb2a95 100644 --- a/src/video/pandora/SDL_pandora.h +++ b/src/video/pandora/SDL_pandora.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/pandora/SDL_pandora_events.c b/src/video/pandora/SDL_pandora_events.c index eedbc2934..f42e0b715 100644 --- a/src/video/pandora/SDL_pandora_events.c +++ b/src/video/pandora/SDL_pandora_events.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/pandora/SDL_pandora_events.h b/src/video/pandora/SDL_pandora_events.h index e628d14a9..c43137798 100644 --- a/src/video/pandora/SDL_pandora_events.h +++ b/src/video/pandora/SDL_pandora_events.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/psp/SDL_pspevents.c b/src/video/psp/SDL_pspevents.c index d096c0616..64fc0f816 100644 --- a/src/video/psp/SDL_pspevents.c +++ b/src/video/psp/SDL_pspevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_pspevents_c.h b/src/video/psp/SDL_pspevents_c.h index af45c4d16..9e24b6ba1 100644 --- a/src/video/psp/SDL_pspevents_c.h +++ b/src/video/psp/SDL_pspevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/psp/SDL_pspgl.c b/src/video/psp/SDL_pspgl.c index d24e72292..f0fa7c3fd 100644 --- a/src/video/psp/SDL_pspgl.c +++ b/src/video/psp/SDL_pspgl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_pspgl_c.h b/src/video/psp/SDL_pspgl_c.h index c0c15d955..03b7a8c24 100644 --- a/src/video/psp/SDL_pspgl_c.h +++ b/src/video/psp/SDL_pspgl_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/psp/SDL_pspmouse.c b/src/video/psp/SDL_pspmouse.c index 8df3d614e..14c69dee2 100644 --- a/src/video/psp/SDL_pspmouse.c +++ b/src/video/psp/SDL_pspmouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_pspmouse_c.h b/src/video/psp/SDL_pspmouse_c.h index d14b84b9a..de5ff4ef9 100644 --- a/src/video/psp/SDL_pspmouse_c.h +++ b/src/video/psp/SDL_pspmouse_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/psp/SDL_pspvideo.c b/src/video/psp/SDL_pspvideo.c index b3787239c..cfcf0cfff 100644 --- a/src/video/psp/SDL_pspvideo.c +++ b/src/video/psp/SDL_pspvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e468c2ddf 100644 --- a/src/video/psp/SDL_pspvideo.h +++ b/src/video/psp/SDL_pspvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/raspberry/SDL_rpievents.c b/src/video/raspberry/SDL_rpievents.c index cdfc746a7..12760a865 100644 --- a/src/video/raspberry/SDL_rpievents.c +++ b/src/video/raspberry/SDL_rpievents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/raspberry/SDL_rpievents_c.h b/src/video/raspberry/SDL_rpievents_c.h index e69c5917f..adc2fdd7c 100644 --- a/src/video/raspberry/SDL_rpievents_c.h +++ b/src/video/raspberry/SDL_rpievents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/raspberry/SDL_rpimouse.c b/src/video/raspberry/SDL_rpimouse.c index b0ba88de3..f8ee4ec61 100644 --- a/src/video/raspberry/SDL_rpimouse.c +++ b/src/video/raspberry/SDL_rpimouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -48,7 +48,7 @@ static int RPI_ShowCursor(SDL_Cursor * cursor); static void RPI_MoveCursor(SDL_Cursor * cursor); static void RPI_FreeCursor(SDL_Cursor * cursor); static void RPI_WarpMouse(SDL_Window * window, int x, int y); -static void RPI_WarpMouseGlobal(int x, int y); +static int RPI_WarpMouseGlobal(int x, int y); static SDL_Cursor * RPI_CreateDefaultCursor(void) @@ -216,18 +216,18 @@ RPI_WarpMouse(SDL_Window * window, int x, int y) } /* Warp the mouse to (x,y) */ -static void +static int RPI_WarpMouseGlobal(int x, int y) { RPI_CursorData *curdata; DISPMANX_UPDATE_HANDLE_T update; - int ret; VC_RECT_T dst_rect; SDL_Mouse *mouse = SDL_GetMouse(); if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) { curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata; if (curdata->element != DISPMANX_NO_HANDLE) { + int ret; update = vc_dispmanx_update_start( 10 ); SDL_assert( update ); vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h); @@ -245,8 +245,11 @@ RPI_WarpMouseGlobal(int x, int y) /* Submit asynchronously, otherwise the peformance suffers a lot */ ret = vc_dispmanx_update_submit( update, 0, NULL ); SDL_assert( ret == DISPMANX_SUCCESS ); + return (ret == DISPMANX_SUCCESS) ? 0 : -1; } } + + return -1; /* !!! FIXME: this should SDL_SetError() somewhere. */ } void diff --git a/src/video/raspberry/SDL_rpimouse.h b/src/video/raspberry/SDL_rpimouse.h index a39e6549d..db8df76f4 100644 --- a/src/video/raspberry/SDL_rpimouse.h +++ b/src/video/raspberry/SDL_rpimouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/raspberry/SDL_rpiopengles.c b/src/video/raspberry/SDL_rpiopengles.c index c6f462b2a..4809c9255 100644 --- a/src/video/raspberry/SDL_rpiopengles.c +++ b/src/video/raspberry/SDL_rpiopengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/raspberry/SDL_rpiopengles.h b/src/video/raspberry/SDL_rpiopengles.h index 5ef8f8fff..5dda45d57 100644 --- a/src/video/raspberry/SDL_rpiopengles.h +++ b/src/video/raspberry/SDL_rpiopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/raspberry/SDL_rpivideo.c b/src/video/raspberry/SDL_rpivideo.c index 8391c762a..fae9143b6 100644 --- a/src/video/raspberry/SDL_rpivideo.c +++ b/src/video/raspberry/SDL_rpivideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -284,15 +284,14 @@ RPI_CreateWindow(_THIS, SDL_Window * window) void RPI_DestroyWindow(_THIS, SDL_Window * window) { - SDL_WindowData *data; - - if(window->driverdata) { - data = (SDL_WindowData *) window->driverdata; + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + if(data) { +#if SDL_VIDEO_OPENGL_EGL if (data->egl_surface != EGL_NO_SURFACE) { SDL_EGL_DestroySurface(_this, data->egl_surface); - data->egl_surface = EGL_NO_SURFACE; } - SDL_free(window->driverdata); +#endif + SDL_free(data); window->driverdata = NULL; } } diff --git a/src/video/raspberry/SDL_rpivideo.h b/src/video/raspberry/SDL_rpivideo.h index 4de8983c3..648254c8e 100644 --- a/src/video/raspberry/SDL_rpivideo.h +++ b/src/video/raspberry/SDL_rpivideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/sdlgenblit.pl b/src/video/sdlgenblit.pl index db83d2507..202c6c228 100755 --- a/src/video/sdlgenblit.pl +++ b/src/video/sdlgenblit.pl @@ -92,7 +92,7 @@ sub open_file { /* DO NOT EDIT! This file is generated by sdlgenblit.pl */ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/uikit/SDL_uikitappdelegate.h b/src/video/uikit/SDL_uikitappdelegate.h index d5430beb1..9f3c98541 100644 --- a/src/video/uikit/SDL_uikitappdelegate.h +++ b/src/video/uikit/SDL_uikitappdelegate.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 a9924fbca..5d63019ec 100644 --- a/src/video/uikit/SDL_uikitappdelegate.m +++ b/src/video/uikit/SDL_uikitappdelegate.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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,145 +76,291 @@ int main(int argc, char **argv) [UIApplication sharedApplication].idleTimerDisabled = disable; } -@interface SDL_splashviewcontroller : UIViewController { - UIImageView *splash; - UIImage *splashPortrait; - UIImage *splashLandscape; -} +/* 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; + + 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]]; + } + } + } -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation; -@end + if (!image) { + image = [UIImage imageNamed:name]; + } + + return image; +} -@implementation SDL_splashviewcontroller +@implementation SDLLaunchScreenController -- (id)init +- (instancetype)init { - self = [super init]; - if (self == nil) { + if (!(self = [super initWithNibName:nil bundle:nil])) { return nil; } - self->splash = [[UIImageView alloc] init]; - [self setView:self->splash]; + NSBundle *bundle = [NSBundle mainBundle]; + NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; + BOOL atleastiOS8 = UIKit_IsSystemVersionAtLeast(8.0); - CGSize size = [UIScreen mainScreen].bounds.size; - float height = SDL_max(size.width, size.height); - 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]; + /* 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; + } } - [self updateSplashImage:[[UIApplication sharedApplication] statusBarOrientation]]; + if (!self.view) { + NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; + UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; + NSString *imagename = nil; + UIImage *image = nil; - return self; -} + int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); + int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); -- (NSUInteger)supportedInterfaceOrientations -{ - NSUInteger orientationMask = UIInterfaceOrientationMaskAll; + /* 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); + } + } - /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { - orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; + 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 orientationMask; + + return self; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient +- (void)loadView { - NSUInteger orientationMask = [self supportedInterfaceOrientations]; - return (orientationMask & (1 << orient)); + /* Do nothing. */ } -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration +- (BOOL)shouldAutorotate { - [self updateSplashImage:interfaceOrientation]; + /* If YES, the launch image will be incorrectly rotated in some cases. */ + return NO; } -- (void)updateSplashImage:(UIInterfaceOrientation)interfaceOrientation +- (NSUInteger)supportedInterfaceOrientations { - 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]]; - - UIViewController *splashViewController = [[SDL_splashviewcontroller alloc] init]; - launch_window.rootViewController = splashViewController; - [launch_window addSubview:splashViewController.view]; - [launch_window makeKeyAndVisible]; + NSBundle *bundle = [NSBundle mainBundle]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + +#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]; + + 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, @@ -235,7 +382,35 @@ - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application 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) { @@ -248,17 +423,17 @@ - (void) applicationWillResignActive:(UIApplication*)application 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); @@ -274,11 +449,11 @@ - (void) applicationDidBecomeActive:(UIApplication*)application - (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.h b/src/video/uikit/SDL_uikitevents.h index d9fb4ab36..63eeb955f 100644 --- a/src/video/uikit/SDL_uikitevents.h +++ b/src/video/uikit/SDL_uikitevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 94fba878b..d4d6fcc4e 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -40,8 +40,9 @@ 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.h b/src/video/uikit/SDL_uikitmessagebox.h index 86af87b5c..2f38ac0d4 100644 --- a/src/video/uikit/SDL_uikitmessagebox.h +++ b/src/video/uikit/SDL_uikitmessagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index c24f3ff8b..dea8bdc69 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 - -- (id)initWithButtonIndex:(int *)buttonIndex -{ - self = [self init]; - if (self == nil) { - return nil; - } - self->clickedButtonIndex = buttonIndex; - - return self; -} +@implementation SDLAlertViewDelegate -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex; +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - *clickedButtonIndex = (int)buttonIndex; + _clickedIndex = (int)buttonIndex; } -@end /* UIKit_UIAlertViewDelegate */ +@end SDL_bool @@ -70,41 +55,38 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) int UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) { - int clicked; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - UIAlertView* alert = [[UIAlertView alloc] init]; + int i; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; - alert.title = [NSString stringWithUTF8String:messageboxdata->title]; - alert.message = [NSString stringWithUTF8String:messageboxdata->message]; - alert.delegate = [[UIKit_UIAlertViewDelegate alloc] initWithButtonIndex:&clicked]; + @autoreleasepool { + UIAlertView *alert = [[UIAlertView alloc] init]; + SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; - const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; - int i; - for (i = 0; i < messageboxdata->numbuttons; ++i) { - [alert addButtonWithTitle:[[NSString alloc] initWithUTF8String:buttons[i].text]]; - } + alert.delegate = delegate; + alert.title = @(messageboxdata->title); + alert.message = @(messageboxdata->message); - /* Set up for showing the alert */ - clicked = messageboxdata->numbuttons; + for (i = 0; i < messageboxdata->numbuttons; ++i) { + [alert addButtonWithTitle:@(buttons[i].text)]; + } - [alert show]; + /* Set up for showing the alert */ + delegate.clickedIndex = messageboxdata->numbuttons; - /* 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; + [alert show]; - *buttonid = messageboxdata->buttons[clicked].buttonid; + /* 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; - [alert.delegate release]; - [alert release]; + *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid; - [pool release]; + alert.delegate = nil; + } return 0; } diff --git a/src/video/uikit/SDL_uikitmodes.h b/src/video/uikit/SDL_uikitmodes.h index 9f2e9dd34..86bf3b2ea 100644 --- a/src/video/uikit/SDL_uikitmodes.h +++ b/src/video/uikit/SDL_uikitmodes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -25,17 +25,17 @@ #include "SDL_uikitvideo.h" -typedef struct -{ - UIScreen *uiscreen; - CGFloat scale; -} SDL_DisplayData; - -typedef struct -{ - UIScreenMode *uiscreenmode; - CGFloat scale; -} SDL_DisplayModeData; +@interface SDL_DisplayData : NSObject + +@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..afe6a957d 100644 --- a/src/video/uikit/SDL_uikitmodes.m +++ b/src/video/uikit/SDL_uikitmodes.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - - SDL_bool isLandscape = UIKit_IsDisplayLandscape(data->uiscreen); - SDL_bool addRotation = (data->uiscreen == [UIScreen mainScreen]); - - 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; + @autoreleasepool { + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + + SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen); + SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]); + CGFloat scale = data.uiscreen.scale; + +#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 + + 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); + + /* Make sure the width/height are oriented correctly */ + if (isLandscape != (w > h)) { + int tmp = w; + w = h; + h = tmp; + } - /* Add the native screen resolution. */ - UIKit_AddDisplayMode(display, w, h, data->scale, uimode, addRotation); - - 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); + UIKit_AddDisplayMode(display, w, h, uimode, addRotation); } } } @@ -217,19 +217,24 @@ int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { - SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata; - - [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]; + @autoreleasepool { + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata; + + [data.uiscreen setCurrentMode:modedata.uiscreenmode]; + + 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 @@ { /* 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..aa6bc75d0 100644 --- a/src/video/uikit/SDL_uikitopengles.h +++ b/src/video/uikit/SDL_uikitopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e9c26e318 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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" @@ -34,154 +34,189 @@ #include "SDL_loadso.h" #include +@interface SDLEAGLContext : EAGLContext + +/* The OpenGL ES context owns a view / drawable. */ +@property (nonatomic, strong) SDL_uikitopenglview *sdlView; + +@end + +@implementation SDLEAGLContext + +- (void)dealloc +{ + /* When the context is deallocated, its view should be removed from any + * SDL window that it's attached to. */ + [self.sdlView setSDLWindow:NULL]; +} + +@end + static int UIKit_GL_Initialize(_THIS); 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; - - if (_this->gl_config.share_with_current_context) { - SDL_uikitopenglview *view = (SDL_uikitopenglview *) SDL_GL_GetCurrentContext(); - share_group = [view.context sharegroup]; - } + @autoreleasepool { + SDLEAGLContext *context = nil; + 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; + int samples = 0; + + /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES + * versions. */ + EAGLRenderingAPI api = _this->gl_config.major_version; + + if (_this->gl_config.multisamplebuffers > 0) { + samples = _this->gl_config.multisamplesamples; + } - /* 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; - } + if (_this->gl_config.share_with_current_context) { + EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); + sharegroup = context.sharegroup; + } - data->view = view; - view->viewcontroller = data->viewcontroller; - if (view->viewcontroller != nil) { - [view->viewcontroller setView:view]; - [view->viewcontroller retain]; - } - [uiwindow addSubview: view]; + 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; + } + } - /* 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; - } + context = [[SDLEAGLContext alloc] initWithAPI:api sharegroup:sharegroup]; + if (!context) { + SDL_SetError("OpenGL ES %d context could not be created", _this->gl_config.major_version); + return NULL; + } - EAGLContext *context = view.context; - if (UIKit_GL_MakeCurrent(_this, window, context) < 0) { - UIKit_GL_DeleteContext(_this, context); - return NULL; - } + /* 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 + multisamples:samples + context:context]; + + if (!view) { + return NULL; + } - /* Make this window the current mouse focus for touch input */ - if (displaydata->uiscreen == [UIScreen mainScreen]) { - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); - } + /* The context owns the view / drawable. */ + context.sdlView = view; + + if (UIKit_GL_MakeCurrent(_this, window, (__bridge SDL_GLContext) context) < 0) { + UIKit_GL_DeleteContext(_this, (SDL_GLContext) CFBridgingRetain(context)); + return NULL; + } - return context; + /* 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) +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; - } + @autoreleasepool { + /* The context was retained in SDL_GL_CreateContext, so we release it + * here. The context's view will be detached from its window when the + * context is deallocated. */ + CFRelease(context); } - - /* View not found... delete the context anyway? */ - [(EAGLContext *)context release]; } #endif /* SDL_VIDEO_DRIVER_UIKIT */ diff --git a/src/video/uikit/SDL_uikitopenglview.h b/src/video/uikit/SDL_uikitopenglview.h index eed2e5b70..c710813de 100644 --- a/src/video/uikit/SDL_uikitopenglview.h +++ b/src/video/uikit/SDL_uikitopenglview.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -21,66 +21,40 @@ #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 { +#import -@private - /* The pixel dimensions of the backbuffer */ - GLint backingWidth; - GLint backingHeight; - - EAGLContext *context; +#import "SDL_uikitview.h" +#include "SDL_uikitvideo.h" - /* OpenGL names for the renderbuffer and framebuffers used to render to this view */ - GLuint viewRenderbuffer, viewFramebuffer; +@interface SDL_uikitopenglview : SDL_uikitview - /* OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist) */ - GLuint depthRenderbuffer; +- (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 + multisamples:(int)multisamples + context:(EAGLContext *)glcontext; - /* format of depthRenderbuffer */ - GLenum depthBufferFormat; +@property (nonatomic, readonly, weak) EAGLContext *context; - id displayLink; - int animationInterval; - void (*animationCallback)(void*); - void *animationCallbackParam; -} +/* 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, retain, readonly) EAGLContext *context; +@property (nonatomic, readonly) GLuint drawableRenderbuffer; +@property (nonatomic, readonly) GLuint drawableFramebuffer; +@property (nonatomic, readonly) GLuint msaaResolveFramebuffer; - (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..5b8e9cc38 100644 --- a/src/video/uikit/SDL_uikitopenglview.m +++ b/src/video/uikit/SDL_uikitopenglview.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -22,216 +22,363 @@ #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 SDL_uikitopenglview { + /* The renderbuffer and framebuffer used to render to this layer. */ + GLuint viewRenderbuffer, viewFramebuffer; -@implementation SDL_uikitopenglview + /* The depth buffer that is attached to viewFramebuffer, if it exists. */ + GLuint depthRenderbuffer; + + GLenum colorBufferFormat; + + /* format of depthRenderbuffer */ + GLenum depthBufferFormat; + + /* The framebuffer and renderbuffer used for rendering with MSAA. */ + GLuint msaaFramebuffer, msaaRenderbuffer; + + /* The number of MSAA samples. */ + int samples; + + BOOL retainedBacking; +} @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 + multisamples:(int)multisamples + context:(EAGLContext *)glcontext { - 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. - */ - EAGLRenderingAPI api = majorVersion; + context = glcontext; + samples = multisamples; + retainedBacking = retained; + + if (!context || ![EAGLContext setCurrentContext:context]) { + SDL_SetError("Could not create OpenGL ES drawable (could not make context current)"); + return nil; + } + + if (samples > 0) { + GLint maxsamples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &maxsamples); - if (rBits == 8 && gBits == 8 && bBits == 8) { + /* Verify that the sample count is supported before creating any + * multisample Renderbuffers, to avoid generating GL errors. */ + if (samples > maxsamples) { + SDL_SetError("Failed creating OpenGL ES framebuffer: Unsupported MSAA sample count"); + return nil; + } + } + + if (sRGB) { + /* sRGB EAGL drawable support was added in iOS 7. */ + if (UIKit_IsSystemVersionAtLeast(7.0)) { + colorFormat = kEAGLColorFormatSRGBA8; + colorBufferFormat = GL_SRGB8_ALPHA8; + } 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; + colorBufferFormat = GL_RGBA8; } else { - /* default case (faster) */ + /* default case (potentially faster) */ colorFormat = kEAGLColorFormatRGB565; + colorBufferFormat = GL_RGB565; } - /* Get the layer */ CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool: retained], kEAGLDrawablePropertyRetainedBacking, colorFormat, kEAGLDrawablePropertyColorFormat, nil]; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking:@(retained), + kEAGLDrawablePropertyColorFormat:colorFormat + }; - context = [[EAGLContext alloc] initWithAPI:api sharegroup:shareGroup]; - if (!context || ![EAGLContext setCurrentContext:context]) { - [self release]; - SDL_SetError("OpenGL ES %d not supported", majorVersion); + /* Set the appropriate scale (for retina display support) */ + self.contentScaleFactor = scale; + + /* Create the color Renderbuffer Object */ + glGenRenderbuffers(1, &viewRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); + + if (![context renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]) { + SDL_SetError("Failed to create OpenGL ES drawable"); return nil; } - /* Set the appropriate scale (for retina display support) */ - self.contentScaleFactor = scale; + /* 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); - /* create the buffers */ - glGenFramebuffersOES(1, &viewFramebuffer); - glGenRenderbuffersOES(1, &viewRenderbuffer); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); - 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 (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + SDL_SetError("Failed creating OpenGL ES framebuffer"); + return nil; + } + + /* When MSAA is used we'll use a separate framebuffer for rendering to, + * since we'll need to do an explicit MSAA resolve before presenting. */ + if (samples > 0) { + glGenFramebuffers(1, &msaaFramebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + glGenRenderbuffers(1, &msaaRenderbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderbuffer); + + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, colorBufferFormat, backingWidth, backingHeight); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaRenderbuffer); + } - if ((useDepthBuffer) || (useStencilBuffer)) { + 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); + + if (samples > 0) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, depthBufferFormat, backingWidth, backingHeight); + } else { + 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 +{ + /* When MSAA is used, the MSAA draw framebuffer is used for drawing. */ + if (msaaFramebuffer) { + return msaaFramebuffer; + } else { + return viewFramebuffer; + } +} + +- (GLuint)msaaResolveFramebuffer +{ + /* When MSAA is used, the MSAA draw framebuffer is used for drawing and the + * view framebuffer is used as a MSAA resolve framebuffer. */ + if (msaaFramebuffer) { + return viewFramebuffer; + } else { + return 0; + } +} + - (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); + + glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer); + [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; - 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); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); - glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + if (msaaRenderbuffer != 0) { + glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderbuffer); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, backingWidth, backingHeight); + } if (depthRenderbuffer != 0) { - glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthBufferFormat, backingWidth, backingHeight); + glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); + + if (samples > 0) { + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, depthBufferFormat, backingWidth, backingHeight); + } else { + 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]; - - animationInterval = interval; - animationCallback = callback; - animationCallbackParam = callbackParam; + if (viewFramebuffer != 0) { + glLabelObjectEXT(GL_FRAMEBUFFER, viewFramebuffer, 0, "context FBO"); + } - if (animationCallback) - [self startAnimation]; -} + if (viewRenderbuffer != 0) { + glLabelObjectEXT(GL_RENDERBUFFER, viewRenderbuffer, 0, "context color buffer"); + } -- (void)startAnimation -{ - displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(doLoop:)]; - [displayLink setFrameInterval:animationInterval]; - [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; -} + 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"); + } + } -- (void)stopAnimation -{ - [displayLink invalidate]; - displayLink = nil; -} + if (msaaFramebuffer != 0) { + glLabelObjectEXT(GL_FRAMEBUFFER, msaaFramebuffer, 0, "context MSAA FBO"); + } -- (void)doLoop:(CADisplayLink*)sender -{ - /* Don't run the game loop while a messagebox is up */ - if (!UIKit_ShowingMessageBox()) { - animationCallback(animationCallbackParam); + if (msaaRenderbuffer != 0) { + glLabelObjectEXT(GL_RENDERBUFFER, msaaRenderbuffer, 0, "context MSAA renderbuffer"); } } -- (void)setCurrentContext +- (void)swapBuffers { - [EAGLContext setCurrentContext:context]; -} + if (msaaFramebuffer) { + const GLenum attachments[] = {GL_COLOR_ATTACHMENT0}; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, viewFramebuffer); + + /* OpenGL ES 3+ provides explicit MSAA resolves via glBlitFramebuffer. + * In OpenGL ES 1 and 2, MSAA resolves must be done via an extension. */ + if (context.API >= kEAGLRenderingAPIOpenGLES3) { + int w = backingWidth; + int h = backingHeight; + glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + if (!retainedBacking) { + /* Discard the contents of the MSAA drawable color buffer. */ + glInvalidateFramebuffer(GL_READ_FRAMEBUFFER, 1, attachments); + } + } else { + glResolveMultisampleFramebufferAPPLE(); + + if (!retainedBacking) { + glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER, 1, attachments); + } + } + + /* We assume the "drawable framebuffer" (MSAA draw framebuffer) was + * previously bound... */ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, msaaFramebuffer); + } -- (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; } -} + if (msaaFramebuffer != 0) { + glDeleteFramebuffers(1, &msaaFramebuffer); + msaaFramebuffer = 0; + } + + if (msaaRenderbuffer != 0) { + glDeleteRenderbuffers(1, &msaaRenderbuffer); + msaaRenderbuffer = 0; + } +} - (void)dealloc { - [self destroyFramebuffer]; - if ([EAGLContext currentContext] == context) { + if (context && context == [EAGLContext currentContext]) { + [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..5eacd8078 100644 --- a/src/video/uikit/SDL_uikitvideo.h +++ b/src/video/uikit/SDL_uikitvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -25,20 +25,10 @@ #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 */ +void UIKit_SuspendScreenSaver(_THIS); +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..3847de71e 100644 --- a/src/video/uikit/SDL_uikitvideo.m +++ b/src/video/uikit/SDL_uikitvideo.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -26,6 +26,7 @@ #include "SDL_video.h" #include "SDL_mouse.h" +#include "SDL_hints.h" #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" #include "../../events/SDL_events_c.h" @@ -74,16 +75,17 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) device->GetDisplayModes = UIKit_GetDisplayModes; device->SetDisplayMode = UIKit_SetDisplayMode; device->PumpEvents = UIKit_PumpEvents; + device->SuspendScreenSaver = UIKit_SuspendScreenSaver; 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 +95,13 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) #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 +132,40 @@ static void UIKit_DeleteDevice(SDL_VideoDevice * device) UIKit_QuitModes(_this); } +void +UIKit_SuspendScreenSaver(_THIS) +{ + @autoreleasepool { + /* Ignore ScreenSaver API calls if the idle timer hint has been set. */ + /* FIXME: The idle timer hint should be deprecated for SDL 2.1. */ + if (SDL_GetHint(SDL_HINT_IDLE_TIMER_DISABLED) == NULL) { + UIApplication *app = [UIApplication sharedApplication]; + + /* Prevent the display from dimming and going to sleep. */ + app.idleTimerDisabled = (_this->suspend_screensaver != SDL_FALSE); + } + } +} + +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..00be76574 100644 --- a/src/video/uikit/SDL_uikitview.h +++ b/src/video/uikit/SDL_uikitview.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -20,59 +20,22 @@ */ #import -#import "SDL_uikitviewcontroller.h" -#include "SDL_touch.h" - -#define IPHONE_TOUCH_EFFICIENT_DANGEROUS +#include "../SDL_sysvideo.h" -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS -#define MAX_SIMULTANEOUS_TOUCHES 5 -#endif +#include "SDL_touch.h" -#if SDL_IPHONE_KEYBOARD -@interface SDL_uikitview : UIView { -#else -@interface SDL_uikitview : UIView { -#endif +@interface SDL_uikitview : UIView - SDL_TouchID touchId; - UITouch *leftFingerDown; -#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS - UITouch *finger[MAX_SIMULTANEOUS_TOUCHES]; -#endif +- (instancetype)initWithFrame:(CGRect)frame; -#if SDL_IPHONE_KEYBOARD - UITextField *textField; - BOOL keyboardVisible; - SDL_Rect textInputRect; - int keyboardHeight; -#endif +- (void)setSDLWindow:(SDL_Window *)window; -@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..60cd1708e 100644 --- a/src/video/uikit/SDL_uikitview.m +++ b/src/video/uikit/SDL_uikitview.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 + SDL_TouchID touchId; + UITouch * __weak firstFingerDown; +} -- (void)dealloc +- (instancetype)initWithFrame:(CGRect)frame { - [super dealloc]; + if ((self = [super initWithFrame:frame])) { + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.autoresizesSubviews = YES; + + self.multipleTouchEnabled = YES; + + touchId = 1; + SDL_AddTouch(touchId, ""); + } + + return self; } -- (id)initWithFrame:(CGRect)frame +- (void)setSDLWindow:(SDL_Window *)window { - self = [super initWithFrame: frame]; + SDL_WindowData *data = nil; -#if SDL_IPHONE_KEYBOARD - [self initializeKeyboard]; -#endif + if (window == sdlwindow) { + return; + } - self.multipleTouchEnabled = YES; + /* Remove ourself from the old window. */ + if (sdlwindow) { + SDL_uikitview *view = nil; + data = (__bridge SDL_WindowData *) sdlwindow->driverdata; - touchId = 1; - SDL_AddTouch(touchId, ""); + [data.views removeObject:self]; - return self; + [self removeFromSuperview]; + + /* Restore the next-oldest view in the old window. */ + view = data.views.lastObject; + + data.viewcontroller.view = view; + + data.uiwindow.rootViewController = nil; + data.uiwindow.rootViewController = data.viewcontroller; + + [data.uiwindow layoutIfNeeded]; + } + + /* Add ourself to the new window. */ + 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..17db0b26a 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.h +++ b/src/video/uikit/SDL_uikitviewcontroller.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e1667aac8 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -28,107 +28,373 @@ #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; + + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIKit_GetSupportedOrientations(window); +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient +{ + return ([self supportedInterfaceOrientations] & (1 << orient)) != 0; +} + +- (BOOL)prefersStatusBarHidden +{ + 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; - w = (int)(size.width * displaymodedata->scale); - h = (int)(size.height * displaymodedata->scale); + textField.hidden = YES; + keyboardVisible = NO; - SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h); + 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]; } } -- (NSUInteger)supportedInterfaceOrientations +- (void)deinitKeyboard { - NSUInteger orientationMask = 0; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [center removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +} - 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:@" "]]; +/* reveal onscreen virtual keyboard */ +- (void)showKeyboard +{ + keyboardVisible = YES; + if (textField.window) { + [textField becomeFirstResponder]; + } +} - if ([orientations containsObject:@"LandscapeLeft"]) { - orientationMask |= UIInterfaceOrientationMaskLandscapeLeft; - } - if ([orientations containsObject:@"LandscapeRight"]) { - orientationMask |= UIInterfaceOrientationMaskLandscapeRight; - } - if ([orientations containsObject:@"Portrait"]) { - orientationMask |= UIInterfaceOrientationMaskPortrait; - } - if ([orientations containsObject:@"PortraitUpsideDown"]) { - orientationMask |= UIInterfaceOrientationMaskPortraitUpsideDown; +/* hide onscreen virtual keyboard */ +- (void)hideKeyboard +{ + keyboardVisible = NO; + [textField resignFirstResponder]; +} + +- (void)keyboardWillShow:(NSNotification *)notification +{ + CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue]; + + /* The keyboard rect is in the coordinate space of the screen/window, but we + * want its height in the coordinate space of the view. */ + kbrect = [self.view convertRect:kbrect fromView:nil]; + + [self setKeyboardHeight:(int)kbrect.size.height]; +} + +- (void)keyboardWillHide:(NSNotification *)notification +{ + [self setKeyboardHeight:0]; +} + +- (void)updateKeyboard +{ + CGAffineTransform t = self.view.transform; + CGPoint offset = CGPointMake(0.0, 0.0); + CGRect frame = UIKit_ComputeViewFrame(window, self.view.window.screen); + + if (self.keyboardHeight) { + int rectbottom = self.textInputRect.y + self.textInputRect.h; + int keybottom = self.view.bounds.size.height - self.keyboardHeight; + if (keybottom < rectbottom) { + offset.y = keybottom - rectbottom; } + } + + /* Apply this view's transform (except any translation) to the offset, in + * order to orient it correctly relative to the frame's coordinate space. */ + t.tx = 0.0; + t.ty = 0.0; + offset = CGPointApplyAffineTransform(offset, t); + + /* Apply the updated offset to the view's frame. */ + frame.origin.x += offset.x; + frame.origin.y += offset.y; + + self.view.frame = frame; +} - } else if (self->window->flags & SDL_WINDOW_RESIZABLE) { - orientationMask = UIInterfaceOrientationMaskAll; /* any orientation is okay. */ +- (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 { - if (self->window->w >= self->window->h) { - orientationMask |= UIInterfaceOrientationMaskLandscape; - } - if (self->window->h >= self->window->w) { - orientationMask |= (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown); + /* 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; } - /* Don't allow upside-down orientation on the phone, so answering calls is in the natural orientation */ - if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { - orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; + 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]; } - return orientationMask; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient +void +UIKit_HideScreenKeyboard(_THIS, SDL_Window *window) { - NSUInteger orientationMask = [self supportedInterfaceOrientations]; - return (orientationMask & (1 << orient)); + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(window); + [vc hideKeyboard]; + } } -- (BOOL)prefersStatusBarHidden +SDL_bool +UIKit_IsScreenKeyboardShown(_THIS, SDL_Window *window) { - if (self->window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - return YES; - } else { - return NO; + @autoreleasepool { + SDL_uikitviewcontroller *vc = GetWindowViewController(window); + if (vc != nil) { + return vc.isKeyboardVisible; + } + return SDL_FALSE; } } -@end +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 */ diff --git a/src/video/uikit/SDL_uikitwindow.h b/src/video/uikit/SDL_uikitwindow.h index 494b028f3..987bbe01d 100644 --- a/src/video/uikit/SDL_uikitwindow.h +++ b/src/video/uikit/SDL_uikitwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..3e26113dc 100644 --- a/src/video/uikit/SDL_uikitwindow.m +++ b/src/video/uikit/SDL_uikitwindow.m @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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; - - 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); + window->driverdata = (void *) CFBridgingRetain(data); + + data.uiwindow = uiwindow; + + /* only one window on iOS, always shown */ + window->flags &= ~SDL_WINDOW_HIDDEN; + + if (displaydata.uiscreen == [UIScreen mainScreen]) { + window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */ + } else { + 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. */ + } + + 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 (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) { + if ((width > height && !supportsLandscape) || (height > width && !supportsPortrait)) { int temp = width; width = height; height = temp; } - - window->w = width; - window->h = height; } - window->driverdata = data; + window->x = 0; + window->y = 0; + window->w = width; + window->h = height; - /* only one window on iOS, always shown */ - window->flags &= ~SDL_WINDOW_HIDDEN; + /* 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]; - /* 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]) { - window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */ + /* 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]; - /* 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_INPUT_FOCUS; /* never has input focus */ - window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */ - } + /* Sets this view as the controller's view, and adds the view to the window + * heirarchy. */ + [view setSDLWindow:window]; - /* 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() */ + /* 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,174 @@ 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]; - - /* SDL currently puts this window at the start of display's linked list. We rely on this. */ - SDL_assert(_this->windows == window); + @autoreleasepool { + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + const CGSize origsize = data.uiscreen.currentMode.size; - /* We currently only handle a single window per display on iOS */ - if (window->next != NULL) { - return SDL_SetError("Only one window allowed per display."); - } + /* SDL currently puts this window at the start of display's linked list. We rely on this. */ + SDL_assert(_this->windows == window); - /* 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 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); + } - if (bestmode) { - SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata; - [data->uiscreen setCurrentMode:modedata->uiscreenmode]; + 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; + } + } - /* 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 (bestmode) { + SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)bestmode->driverdata; + [data.uiscreen setCurrentMode:modedata.uiscreenmode]; - if (data->uiscreen == [UIScreen mainScreen]) { - if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { - [UIApplication sharedApplication].statusBarHidden = YES; - } else { - [UIApplication sharedApplication].statusBarHidden = NO; + /* 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 (!(window->flags & SDL_WINDOW_RESIZABLE)) { - if (window->w > window->h) { - if (!UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO]; - } - } else if (window->w < window->h) { - if (UIKit_IsDisplayLandscape(data->uiscreen)) { - [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO]; + if (data.uiscreen == [UIScreen mainScreen]) { + if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) { + [UIApplication sharedApplication].statusBarHidden = YES; + } else { + [UIApplication sharedApplication].statusBarHidden = NO; } } - } - /* 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]]; - - /* 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]; - } + /* 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) { - [uiwindow release]; - return -1; + 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); } -void -UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) +static void +UIKit_UpdateWindowBorder(_THIS, SDL_Window * window) { - SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; - SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata; - UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow; + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + SDL_uikitviewcontroller *viewcontroller = data.viewcontroller; - if (fullscreen) { - [UIApplication sharedApplication].statusBarHidden = YES; - } else { - [UIApplication sharedApplication].statusBarHidden = NO; + 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]; + } } - CGRect bounds; - if (fullscreen) { - bounds = [displaydata->uiscreen bounds]; - } else { - bounds = [displaydata->uiscreen applicationFrame]; + /* Update the view's frame to account for the status bar change. */ + viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen); + +#ifdef SDL_IPHONE_KEYBOARD + /* Make sure the view is offset correctly when the keyboard is visible. */ + [viewcontroller updateKeyboard]; +#endif + + [viewcontroller.view setNeedsLayout]; + [viewcontroller.view layoutIfNeeded]; +} + +void +UIKit_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) +{ + @autoreleasepool { + UIKit_UpdateWindowBorder(_this, window); } +} - /* 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; - } +void +UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) +{ + @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); + NSArray *views = nil; + + [data.viewcontroller stopAnimation]; + + /* Detach all views from this window. We use a copy of the array + * because setSDLWindow will remove the object from the original + * array, which would be undesirable if we were iterating over it. */ + views = [data.views copy]; + for (SDL_uikitview *view in views) { + [view setSDLWindow:NULL]; + } + } } window->driverdata = NULL; } @@ -301,29 +324,118 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo 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) { + 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; + info->info.uikit.resolveFramebuffer = glview.msaaResolveFramebuffer; + } else { + info->info.uikit.framebuffer = 0; + info->info.uikit.colorbuffer = 0; + info->info.uikit.resolveFramebuffer = 0; + } + } - 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; + 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 validOrientations = UIInterfaceOrientationMaskAll; + NSUInteger orientationMask = 0; + + @autoreleasepool { + SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; + UIApplication *app = [UIApplication sharedApplication]; + + /* Get all possible valid orientations. If the app delegate doesn't tell + * us, we get the orientations from Info.plist via UIApplication. */ + if ([app.delegate respondsToSelector:@selector(application:supportedInterfaceOrientationsForWindow:)]) { + validOrientations = [app.delegate application:app supportedInterfaceOrientationsForWindow:data.uiwindow]; + } else if ([app respondsToSelector:@selector(supportedInterfaceOrientationsForWindow:)]) { + validOrientations = [app supportedInterfaceOrientationsForWindow:data.uiwindow]; + } + + 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 phones, so answering calls is in the natural orientation */ + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { + orientationMask &= ~UIInterfaceOrientationMaskPortraitUpsideDown; + } + + /* If none of the specified orientations are actually supported by the + * app, we'll revert to what the app supports. An exception would be + * thrown by the system otherwise. */ + if ((validOrientations & orientationMask) == 0) { + orientationMask = validOrientations; + } } + + 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 (!window || !window->driverdata) { + return SDL_SetError("Invalid window"); + } - if (!data || !data->view) { - return SDL_SetError("Invalid window or view not set"); + @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/uikit/keyinfotable.h b/src/video/uikit/keyinfotable.h index 1d16868c8..22a79dceb 100644 --- a/src/video/uikit/keyinfotable.h +++ b/src/video/uikit/keyinfotable.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -169,6 +169,6 @@ static UIKitKeyInfo unicharToUIKeyInfoTable[] = { /* 127 */{ SDL_SCANCODE_BACKSPACE, KMOD_SHIFT } }; -#endif /* UIKitKeyInfo */ +#endif /* _UIKIT_KeyInfo */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vivante/SDL_vivanteopengles.c b/src/video/vivante/SDL_vivanteopengles.c index a5499a9b6..96d2f89dd 100644 --- a/src/video/vivante/SDL_vivanteopengles.c +++ b/src/video/vivante/SDL_vivanteopengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/vivante/SDL_vivanteopengles.h b/src/video/vivante/SDL_vivanteopengles.h index 59ce82005..b7b618030 100644 --- a/src/video/vivante/SDL_vivanteopengles.h +++ b/src/video/vivante/SDL_vivanteopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/vivante/SDL_vivanteplatform.c b/src/video/vivante/SDL_vivanteplatform.c index a779d64ca..40579dfab 100644 --- a/src/video/vivante/SDL_vivanteplatform.c +++ b/src/video/vivante/SDL_vivanteplatform.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/vivante/SDL_vivanteplatform.h b/src/video/vivante/SDL_vivanteplatform.h index 27b82afd5..b8376283a 100644 --- a/src/video/vivante/SDL_vivanteplatform.h +++ b/src/video/vivante/SDL_vivanteplatform.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/vivante/SDL_vivantevideo.c b/src/video/vivante/SDL_vivantevideo.c index 5ae3f981e..8095cb588 100644 --- a/src/video/vivante/SDL_vivantevideo.c +++ b/src/video/vivante/SDL_vivantevideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/vivante/SDL_vivantevideo.h b/src/video/vivante/SDL_vivantevideo.h index aab7bdf34..030516bd1 100644 --- a/src/video/vivante/SDL_vivantevideo.h +++ b/src/video/vivante/SDL_vivantevideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylanddyn.c b/src/video/wayland/SDL_waylanddyn.c index 1ed29db5c..edf6e2195 100644 --- a/src/video/wayland/SDL_waylanddyn.c +++ b/src/video/wayland/SDL_waylanddyn.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h index 8d9313a2d..19fd4558e 100644 --- a/src/video/wayland/SDL_waylanddyn.h +++ b/src/video/wayland/SDL_waylanddyn.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index cb729001e..face9d64b 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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); } } @@ -246,7 +293,14 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, struct wl_array *keys) { struct SDL_WaylandInput *input = data; - SDL_WindowData *window = wl_surface_get_user_data(surface); + SDL_WindowData *window; + + if (!surface) { + /* enter event for a window we've just destroyed */ + return; + } + + window = wl_surface_get_user_data(surface); input->keyboard_focus = window; window->keyboard_device = input; @@ -364,7 +418,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_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 8a6c3fcd6..5a914e908 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandmouse.c b/src/video/wayland/SDL_waylandmouse.c index 338f42f87..2d78ebb95 100644 --- a/src/video/wayland/SDL_waylandmouse.c +++ b/src/video/wayland/SDL_waylandmouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -347,17 +347,16 @@ Wayland_WarpMouse(SDL_Window *window, int x, int y) SDL_Unsupported(); } -static void +static int Wayland_WarpMouseGlobal(int x, int y) { - SDL_Unsupported(); + return SDL_Unsupported(); } static int Wayland_SetRelativeMouseMode(SDL_bool enabled) { - SDL_Unsupported(); - return -1; + return SDL_Unsupported(); } void diff --git a/src/video/wayland/SDL_waylandmouse.h b/src/video/wayland/SDL_waylandmouse.h index efd29d6ce..3a914a28b 100644 --- a/src/video/wayland/SDL_waylandmouse.h +++ b/src/video/wayland/SDL_waylandmouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c index 45078043c..ca301e57a 100644 --- a/src/video/wayland/SDL_waylandopengles.c +++ b/src/video/wayland/SDL_waylandopengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandopengles.h b/src/video/wayland/SDL_waylandopengles.h index 77081f81b..42c13f84c 100644 --- a/src/video/wayland/SDL_waylandopengles.h +++ b/src/video/wayland/SDL_waylandopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index c3b4fa508..edac091f4 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandtouch.c b/src/video/wayland/SDL_waylandtouch.c index 85f9f0ad8..3aa8828d2 100644 --- a/src/video/wayland/SDL_waylandtouch.c +++ b/src/video/wayland/SDL_waylandtouch.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -88,12 +88,10 @@ touch_handle_touch(void *data, uint32_t capabilities = flags >> 16; */ - SDL_TouchID deviceId = 0; - if (!SDL_GetTouch(deviceId)) { - if (SDL_AddTouch(deviceId, "qt_touch_extension") < 0) { - SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__); - } - } + SDL_TouchID deviceId = 1; + if (SDL_AddTouch(deviceId, "qt_touch_extension") < 0) { + SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__); + } switch (touchState) { case QtWaylandTouchPointPressed: diff --git a/src/video/wayland/SDL_waylandtouch.h b/src/video/wayland/SDL_waylandtouch.h index 435fd5624..8c0d20366 100644 --- a/src/video/wayland/SDL_waylandtouch.h +++ b/src/video/wayland/SDL_waylandtouch.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 43826b831..f509ddc1b 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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,54 +143,79 @@ 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; + } -static const struct wl_shm_listener shm_listener = { - shm_handle_format -}; + wl_output_add_listener(output, &output_listener, display); +} #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void @@ -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..6dc736a20 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e105408ac 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..e2bed5462 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_msctf.h b/src/video/windows/SDL_msctf.h index 01e732cfb..c2368d7ac 100644 --- a/src/video/windows/SDL_msctf.h +++ b/src/video/windows/SDL_msctf.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_vkeys.h b/src/video/windows/SDL_vkeys.h index 1ed155a18..4c3d390de 100644 --- a/src/video/windows/SDL_vkeys.h +++ b/src/video/windows/SDL_vkeys.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsclipboard.c b/src/video/windows/SDL_windowsclipboard.c index ae3a104ab..d93eceed1 100644 --- a/src/video/windows/SDL_windowsclipboard.c +++ b/src/video/windows/SDL_windowsclipboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsclipboard.h b/src/video/windows/SDL_windowsclipboard.h index 49c36c4ee..3b5e62b46 100644 --- a/src/video/windows/SDL_windowsclipboard.h +++ b/src/video/windows/SDL_windowsclipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 28801d2fc..8f3ec6855 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -24,6 +24,7 @@ #include "SDL_windowsvideo.h" #include "SDL_windowsshape.h" +#include "SDL_system.h" #include "SDL_syswm.h" #include "SDL_timer.h" #include "SDL_vkeys.h" @@ -31,6 +32,7 @@ #include "../../events/SDL_touch_c.h" #include "../../events/scancodes_windows.h" #include "SDL_assert.h" +#include "SDL_hints.h" /* Dropfile support */ #include @@ -44,6 +46,9 @@ #include "wmmsg.h" #endif +/* For processing mouse WM_*BUTTON* and WM_MOUSEMOVE message-data from GetMessageExtraInfo() */ +#define MOUSEEVENTF_FROMTOUCH 0xFF515700 + /* Masks for processing the windows KEYDOWN and KEYUP messages */ #define REPEATED_KEYMASK (1<<30) #define EXTENDED_KEYMASK (1<<24) @@ -195,7 +200,7 @@ WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam) void -WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button) +WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID) { if (data->focus_click_pending && button == SDL_BUTTON_LEFT && !bwParamMousePressed) { data->focus_click_pending = SDL_FALSE; @@ -203,9 +208,9 @@ WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePress } if (bwParamMousePressed && !bSDLMousePressed) { - SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button); + SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button); } else if (!bwParamMousePressed && bSDLMousePressed) { - SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button); + SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button); } } @@ -214,15 +219,15 @@ WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePress * so this funciton reconciles our view of the world with the current buttons reported by windows */ void -WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data) +WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID) { if (wParam != data->mouse_button_flags) { Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL); - WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT); - WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE); - WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT); - WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1); - WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2); + WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, mouseID); data->mouse_button_flags = wParam; } } @@ -234,25 +239,25 @@ WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data) if (rawButtons != data->mouse_button_flags) { Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL); if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); if ((rawButtons & RI_MOUSE_BUTTON_1_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); if ((rawButtons & RI_MOUSE_BUTTON_2_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); if ((rawButtons & RI_MOUSE_BUTTON_3_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); if ((rawButtons & RI_MOUSE_BUTTON_4_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); if ((rawButtons & RI_MOUSE_BUTTON_5_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); data->mouse_button_flags = rawButtons; } } @@ -270,28 +275,28 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data) keyState = GetAsyncKeyState(VK_LBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT); + WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); } keyState = GetAsyncKeyState(VK_RBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT); + WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); } keyState = GetAsyncKeyState(VK_MBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE); + WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); } keyState = GetAsyncKeyState(VK_XBUTTON1); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1); + WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); } keyState = GetAsyncKeyState(VK_XBUTTON2); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2); + WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); } data->mouse_button_flags = 0; } -SDL_FORCE_INLINE BOOL +BOOL WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text) { if (codepoint <= 0x7F) { @@ -318,6 +323,22 @@ WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text) return SDL_TRUE; } +static SDL_bool +ShouldGenerateWindowCloseOnAltF4(void) +{ + const char *hint; + + hint = SDL_GetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4); + if (hint) { + if (*hint == '0') { + return SDL_TRUE; + } else { + return SDL_FALSE; + } + } + return SDL_TRUE; +} + LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -409,7 +430,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_Mouse *mouse = SDL_GetMouse(); if (!mouse->relative_mode || mouse->relative_mode_warp) { - SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0); + SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } } /* don't break here, fall through to check the wParam like the button presses */ @@ -428,7 +450,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_Mouse *mouse = SDL_GetMouse(); if (!mouse->relative_mode || mouse->relative_mode_warp) { - WIN_CheckWParamMouseButtons(wParam, data); + SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0); + WIN_CheckWParamMouseButtons(wParam, data, mouseID); } } break; @@ -498,12 +521,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 +540,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; } } @@ -548,24 +571,21 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSKEYDOWN: { SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam); + const Uint8 *keyboardState = SDL_GetKeyboardState(NULL); + + /* Detect relevant keyboard shortcuts */ + if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) { + /* ALT+F4: Close window */ + if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); + } + } + if (code != SDL_SCANCODE_UNKNOWN) { SDL_SendKeyboardKey(SDL_PRESSED, code); } } - if (msg == WM_KEYDOWN) { - BYTE keyboardState[256]; - char text[5]; - UINT32 utf32 = 0; - - 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); - } - } - } + returnCode = 0; break; @@ -575,14 +595,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam); const Uint8 *keyboardState = SDL_GetKeyboardState(NULL); - /* Detect relevant keyboard shortcuts */ - if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) { - /* ALT+F4: Close window */ - if (code == SDL_SCANCODE_F4) { - SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); - } - } - if (code != SDL_SCANCODE_UNKNOWN) { if (code == SDL_SCANCODE_PRINTSCREEN && keyboardState[code] == SDL_RELEASED) { @@ -595,9 +607,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; case WM_UNICHAR: - case WM_CHAR: - /* Ignore WM_CHAR messages that come from TranslateMessage(), since we handle WM_KEY* messages directly */ - returnCode = 0; + if ( wParam == UNICODE_NOCHAR ) { + returnCode = 1; + break; + } + /* otherwise fall through to below */ + case WM_CHAR: + { + char text[5]; + if ( WIN_ConvertUTF32toUTF8( (UINT32)wParam, text ) ) { + SDL_SendKeyboardText( text ); + } + } + returnCode = 0; break; #ifdef WM_INPUTLANGCHANGE @@ -789,9 +811,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } return (1); -#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER) case WM_SYSCOMMAND: { + if ((wParam & 0xFFF0) == SC_KEYMENU) { + return (0); + } + +#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER) /* Don't start the screensaver or blank the monitor in fullscreen apps */ if ((wParam & 0xFFF0) == SC_SCREENSAVE || (wParam & 0xFFF0) == SC_MONITORPOWER) { @@ -799,9 +825,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return (0); } } +#endif /* System has screensaver support */ } break; -#endif /* System has screensaver support */ case WM_CLOSE: { @@ -836,10 +862,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) PTOUCHINPUT input = &inputs[i]; const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource); - if (!SDL_GetTouch(touchId)) { - if (SDL_AddTouch(touchId, "") < 0) { - continue; - } + if (SDL_AddTouch(touchId, "") < 0) { + continue; } /* Get the normalized coordinates for the window */ @@ -924,6 +948,16 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } } +/* A message hook called before TranslateMessage() */ +static SDL_WindowsMessageHook g_WindowsMessageHook = NULL; +static void *g_WindowsMessageHookData = NULL; + +void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata) +{ + g_WindowsMessageHook = callback; + g_WindowsMessageHookData = userdata; +} + void WIN_PumpEvents(_THIS) { @@ -933,6 +967,10 @@ WIN_PumpEvents(_THIS) if (g_WindowsEnableMessageLoop) { while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (g_WindowsMessageHook) { + g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam); + } + /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */ TranslateMessage(&msg); DispatchMessage(&msg); diff --git a/src/video/windows/SDL_windowsevents.h b/src/video/windows/SDL_windowsevents.h index b9944ee75..3e923aaba 100644 --- a/src/video/windows/SDL_windowsevents.h +++ b/src/video/windows/SDL_windowsevents.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsframebuffer.c b/src/video/windows/SDL_windowsframebuffer.c index 4292db5a6..d92a5a1b9 100644 --- a/src/video/windows/SDL_windowsframebuffer.c +++ b/src/video/windows/SDL_windowsframebuffer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsframebuffer.h b/src/video/windows/SDL_windowsframebuffer.h index daa42b83e..ed6837bab 100644 --- a/src/video/windows/SDL_windowsframebuffer.h +++ b/src/video/windows/SDL_windowsframebuffer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c index 0557b6cd2..02f7b630f 100644 --- a/src/video/windows/SDL_windowskeyboard.c +++ b/src/video/windows/SDL_windowskeyboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -122,10 +122,9 @@ WIN_UpdateKeymap() } /* If this key is one of the non-mappable keys, ignore it */ - /* Don't allow the number keys right above the qwerty row to translate or the top left key (grave/backquote) */ /* Not mapping numbers fixes the French layout, giving numeric keycodes for the number keys, which is the expected behavior */ if ((keymap[scancode] & SDLK_SCANCODE_MASK) || - scancode == SDL_SCANCODE_GRAVE || + /* scancode == SDL_SCANCODE_GRAVE || */ /* Uncomment this line to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */ (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0) ) { continue; } @@ -187,6 +186,7 @@ void WIN_SetTextInputRect(_THIS, SDL_Rect *rect) { SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + HIMC himc = 0; if (!rect) { SDL_InvalidParamError("rect"); @@ -194,6 +194,17 @@ WIN_SetTextInputRect(_THIS, SDL_Rect *rect) } videodata->ime_rect = *rect; + + himc = ImmGetContext(videodata->ime_hwnd_current); + if (himc) + { + COMPOSITIONFORM cf; + cf.ptCurrentPos.x = videodata->ime_rect.x; + cf.ptCurrentPos.y = videodata->ime_rect.y; + cf.dwStyle = CFS_FORCE_POSITION; + ImmSetCompositionWindow(himc, &cf); + ImmReleaseContext(videodata->ime_hwnd_current, himc); + } } #ifdef SDL_DISABLE_WINDOWS_IME @@ -211,7 +222,12 @@ void IME_Present(SDL_VideoData *videodata) #else -#ifdef __GNUC__ +#ifdef _SDL_msctf_h +#define USE_INIT_GUID +#elif defined(__GNUC__) +#define USE_INIT_GUID +#endif +#ifdef USE_INIT_GUID #undef DEFINE_GUID #define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} DEFINE_GUID(IID_ITfInputProcessorProfileActivationSink, 0x71C6E74E,0x0F28,0x11D8,0xA8,0x2A,0x00,0x06,0x5B,0x84,0x43,0x5C); @@ -722,7 +738,7 @@ IME_SendEditingEvent(SDL_VideoData *videodata) SDL_wcslcpy(buffer, videodata->ime_composition, size); } s = WIN_StringToUTF8(buffer); - SDL_SendEditingText(s, videodata->ime_cursor + SDL_wcslen(videodata->ime_readingstring), 0); + SDL_SendEditingText(s, videodata->ime_cursor + (int)SDL_wcslen(videodata->ime_readingstring), 0); SDL_free(s); } @@ -1387,7 +1403,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc) if (!*s) break; - GetTextExtentPoint32W(hdc, s, SDL_wcslen(s), &candsizes[i]); + GetTextExtentPoint32W(hdc, s, (int)SDL_wcslen(s), &candsizes[i]); maxcandsize.cx = SDL_max(maxcandsize.cx, candsizes[i].cx); maxcandsize.cy = SDL_max(maxcandsize.cy, candsizes[i].cy); @@ -1479,7 +1495,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc) } DrawRect(hdc, left, top, right, bottom, candborder); - ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, SDL_wcslen(s), NULL); + ExtTextOutW(hdc, left + candborder + candpadding, top + candborder + candpadding, 0, NULL, s, (int)SDL_wcslen(s), NULL); } StopDrawToBitmap(hdc, &hbm); diff --git a/src/video/windows/SDL_windowskeyboard.h b/src/video/windows/SDL_windowskeyboard.h index 3eb0cbf6b..5967b5114 100644 --- a/src/video/windows/SDL_windowskeyboard.h +++ b/src/video/windows/SDL_windowskeyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsmessagebox.c b/src/video/windows/SDL_windowsmessagebox.c index 6cffc8adf..31ffb8fc3 100644 --- a/src/video/windows/SDL_windowsmessagebox.c +++ b/src/video/windows/SDL_windowsmessagebox.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsmessagebox.h b/src/video/windows/SDL_windowsmessagebox.h index ea709a4af..37f9f4cba 100644 --- a/src/video/windows/SDL_windowsmessagebox.h +++ b/src/video/windows/SDL_windowsmessagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c index f64a5788b..f5f2b8a8a 100644 --- a/src/video/windows/SDL_windowsmodes.c +++ b/src/video/windows/SDL_windowsmodes.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -29,9 +29,50 @@ #define CDS_FULLSCREEN 0 #endif +typedef struct _WIN_GetMonitorDPIData { + SDL_VideoData *vid_data; + SDL_DisplayMode *mode; + SDL_DisplayModeData *mode_data; +} WIN_GetMonitorDPIData; + +static BOOL CALLBACK +WIN_GetMonitorDPI(HMONITOR hMonitor, + HDC hdcMonitor, + LPRECT lprcMonitor, + LPARAM dwData) +{ + WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData; + UINT hdpi, vdpi; + + if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK && + hdpi > 0 && + vdpi > 0) { + float hsize, vsize; + + data->mode_data->HorzDPI = (float)hdpi; + data->mode_data->VertDPI = (float)vdpi; + + // Figure out the monitor size and compute the diagonal DPI. + hsize = data->mode->w / data->mode_data->HorzDPI; + vsize = data->mode->h / data->mode_data->VertDPI; + + data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w, + data->mode->h, + hsize, + vsize ); + + // We can only handle one DPI per display mode so end the enumeration. + return FALSE; + } + + // We didn't get DPI information so keep going. + return TRUE; +} + static SDL_bool -WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) +WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) { + SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata; SDL_DisplayModeData *data; DEVMODE devmode; HDC hdc; @@ -52,6 +93,9 @@ WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) DM_DISPLAYFLAGS); data->ScaleX = 1.0f; data->ScaleY = 1.0f; + data->DiagDPI = 0.0f; + data->HorzDPI = 0.0f; + data->VertDPI = 0.0f; /* Fill in the mode information */ mode->format = SDL_PIXELFORMAT_UNKNOWN; @@ -73,6 +117,35 @@ WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) mode->w = logical_width; mode->h = logical_height; + // WIN_GetMonitorDPI needs mode->w and mode->h + // so only call after those are set. + if (vid_data->GetDpiForMonitor) { + WIN_GetMonitorDPIData dpi_data; + RECT monitor_rect; + + dpi_data.vid_data = vid_data; + dpi_data.mode = mode; + dpi_data.mode_data = data; + monitor_rect.left = devmode.dmPosition.x; + monitor_rect.top = devmode.dmPosition.y; + monitor_rect.right = monitor_rect.left + 1; + monitor_rect.bottom = monitor_rect.top + 1; + EnumDisplayMonitors(NULL, &monitor_rect, WIN_GetMonitorDPI, (LPARAM)&dpi_data); + } else { + // We don't have the Windows 8.1 routine so just + // get system DPI. + data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX ); + data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY ); + if (data->HorzDPI == data->VertDPI) { + data->DiagDPI = data->HorzDPI; + } else { + data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w, + mode->h, + (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f, + (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f ); + } + } + SDL_zero(bmi_data); bmi = (LPBITMAPINFO) bmi_data; bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -131,7 +204,7 @@ WIN_GetDisplayMode(LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) } static SDL_bool -WIN_AddDisplay(LPTSTR DeviceName) +WIN_AddDisplay(_THIS, LPTSTR DeviceName) { SDL_VideoDisplay display; SDL_DisplayData *displaydata; @@ -141,7 +214,7 @@ WIN_AddDisplay(LPTSTR DeviceName) #ifdef DEBUG_MODES printf("Display: %s\n", WIN_StringToUTF8(DeviceName)); #endif - if (!WIN_GetDisplayMode(DeviceName, ENUM_CURRENT_SETTINGS, &mode)) { + if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) { return SDL_FALSE; } @@ -215,10 +288,10 @@ WIN_InitModes(_THIS) continue; } } - count += WIN_AddDisplay(device.DeviceName); + count += WIN_AddDisplay(_this, device.DeviceName); } if (count == 0) { - WIN_AddDisplay(DeviceName); + WIN_AddDisplay(_this, DeviceName); } } } @@ -241,6 +314,24 @@ WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) return 0; } +int +WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi) +{ + SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata; + + if (ddpi) { + *ddpi = data->DiagDPI; + } + if (hdpi) { + *hdpi = data->HorzDPI; + } + if (vdpi) { + *vdpi = data->VertDPI; + } + + return data->DiagDPI != 0.0f ? 0 : -1; +} + void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { @@ -249,7 +340,7 @@ WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display) SDL_DisplayMode mode; for (i = 0;; ++i) { - if (!WIN_GetDisplayMode(data->DeviceName, i, &mode)) { + if (!WIN_GetDisplayMode(_this, data->DeviceName, i, &mode)) { break; } if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) { diff --git a/src/video/windows/SDL_windowsmodes.h b/src/video/windows/SDL_windowsmodes.h index d16a5e7a8..ba0964a3b 100644 --- a/src/video/windows/SDL_windowsmodes.h +++ b/src/video/windows/SDL_windowsmodes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -33,10 +33,14 @@ typedef struct DEVMODE DeviceMode; float ScaleX; float ScaleY; + float DiagDPI; + float HorzDPI; + float VertDPI; } SDL_DisplayModeData; extern int WIN_InitModes(_THIS); extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); +extern int WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi); extern void WIN_GetDisplayModes(_THIS, SDL_VideoDisplay * display); extern int WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); extern void WIN_QuitModes(_THIS); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index c61076c5f..69aa77712 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -236,7 +236,7 @@ WIN_WarpMouse(SDL_Window * window, int x, int y) SetCursorPos(pt.x, pt.y); } -static void +static int WIN_WarpMouseGlobal(int x, int y) { POINT pt; @@ -244,6 +244,7 @@ WIN_WarpMouseGlobal(int x, int y) pt.x = x; pt.y = y; SetCursorPos(pt.x, pt.y); + return 0; } static int diff --git a/src/video/windows/SDL_windowsmouse.h b/src/video/windows/SDL_windowsmouse.h index 665cdc57b..d3d8f6342 100644 --- a/src/video/windows/SDL_windowsmouse.h +++ b/src/video/windows/SDL_windowsmouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsopengl.c b/src/video/windows/SDL_windowsopengl.c index 71855c874..dc8cbb8a1 100644 --- a/src/video/windows/SDL_windowsopengl.c +++ b/src/video/windows/SDL_windowsopengl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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..71c05db03 100644 --- a/src/video/windows/SDL_windowsopengl.h +++ b/src/video/windows/SDL_windowsopengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_windowsopengles.c b/src/video/windows/SDL_windowsopengles.c index 544fe525e..9125da0e4 100644 --- a/src/video/windows/SDL_windowsopengles.c +++ b/src/video/windows/SDL_windowsopengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -111,6 +111,7 @@ WIN_GLES_SetupWindow(_THIS, SDL_Window * window) if (_this->egl_data == NULL) { if (SDL_EGL_LoadLibrary(_this, NULL, EGL_DEFAULT_DISPLAY) < 0) { + SDL_EGL_UnloadLibrary(_this); return -1; } } diff --git a/src/video/windows/SDL_windowsopengles.h b/src/video/windows/SDL_windowsopengles.h index 8e232177e..f63420880 100644 --- a/src/video/windows/SDL_windowsopengles.h +++ b/src/video/windows/SDL_windowsopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsshape.c b/src/video/windows/SDL_windowsshape.c index 9409e2b4d..6c38ba1a5 100644 --- a/src/video/windows/SDL_windowsshape.c +++ b/src/video/windows/SDL_windowsshape.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsshape.h b/src/video/windows/SDL_windowsshape.h index 9405a501e..568945c7d 100644 --- a/src/video/windows/SDL_windowsshape.h +++ b/src/video/windows/SDL_windowsshape.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index d87b9cff9..86c3437c4 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -78,6 +78,9 @@ WIN_DeleteDevice(SDL_VideoDevice * device) if (data->userDLL) { SDL_UnloadObject(data->userDLL); } + if (data->shcoreDLL) { + SDL_UnloadObject(data->shcoreDLL); + } SDL_free(device->driverdata); SDL_free(device); @@ -112,10 +115,16 @@ WIN_CreateDevice(int devindex) data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow"); } + data->shcoreDLL = SDL_LoadObject("SHCORE.DLL"); + if (data->shcoreDLL) { + data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor"); + } + /* Set the function pointers */ device->VideoInit = WIN_VideoInit; device->VideoQuit = WIN_VideoQuit; device->GetDisplayBounds = WIN_GetDisplayBounds; + device->GetDisplayDPI = WIN_GetDisplayDPI; device->GetDisplayModes = WIN_GetDisplayModes; device->SetDisplayMode = WIN_SetDisplayMode; device->PumpEvents = WIN_PumpEvents; diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index aaedc04ea..85327a7ab 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -27,7 +27,7 @@ #include "../SDL_sysvideo.h" -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (_MSC_VER >= 1500) #include #else #include "SDL_msctf.h" @@ -76,6 +76,17 @@ typedef struct _TOUCHINPUT { #endif /* WINVER < 0x0601 */ +#if WINVER < 0x0603 + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#endif /* WINVER < 0x0603 */ + typedef BOOL (*PFNSHFullScreen)(HWND, DWORD); typedef void (*PFCoordTransform)(SDL_Window*, POINT*); @@ -124,6 +135,12 @@ typedef struct SDL_VideoData BOOL (WINAPI *GetTouchInputInfo)( HTOUCHINPUT, UINT, PTOUCHINPUT, int ); BOOL (WINAPI *RegisterTouchWindow)( HWND, ULONG ); + void* shcoreDLL; + HRESULT (WINAPI *GetDpiForMonitor)( HMONITOR hmonitor, + MONITOR_DPI_TYPE dpiType, + UINT *dpiX, + UINT *dpiY ); + SDL_bool ime_com_initialized; struct ITfThreadMgr *ime_threadmgr; SDL_bool ime_initialized; diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 94328339f..2dc5386d7 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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); } @@ -621,6 +615,7 @@ WIN_DestroyWindow(_THIS, SDL_Window * window) if (data) { ReleaseDC(data->hwnd, data->hdc); + RemoveProp(data->hwnd, TEXT("SDL_WindowData")); if (data->created) { DestroyWindow(data->hwnd); } else { @@ -643,10 +638,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/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index 25d108bd5..32ce279ed 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/windows/wmmsg.h b/src/video/windows/wmmsg.h index cf373bc2b..e8f65ac3e 100644 --- a/src/video/windows/wmmsg.h +++ b/src/video/windows/wmmsg.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp index 7c0cf49a9..5c779d3c6 100644 --- a/src/video/winrt/SDL_winrtevents.cpp +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h index 826cad74e..b63c85fa3 100644 --- a/src/video/winrt/SDL_winrtevents_c.h +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -63,6 +63,7 @@ extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices:: /* Keyboard */ extern void WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args); extern void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args); +extern void WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArgs ^args); /* XAML Thread Management */ extern void WINRT_CycleXAMLThread(); diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp index 2371d74a6..f75dd5f9d 100644 --- a/src/video/winrt/SDL_winrtkeyboard.cpp +++ b/src/video/winrt/SDL_winrtkeyboard.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -22,10 +22,6 @@ #if SDL_VIDEO_DRIVER_WINRT -/* Standard C++11 includes */ -#include - - /* Windows-specific includes */ #include #include @@ -42,248 +38,290 @@ extern "C" { static SDL_Scancode WinRT_Official_Keycodes[] = { - SDL_SCANCODE_UNKNOWN, // VirtualKey.None -- 0 - SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftButton -- 1 - SDL_SCANCODE_UNKNOWN, // VirtualKey.RightButton -- 2 - SDL_SCANCODE_CANCEL, // VirtualKey.Cancel -- 3 - SDL_SCANCODE_UNKNOWN, // VirtualKey.MiddleButton -- 4 - SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton1 -- 5 - SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton2 -- 6 - SDL_SCANCODE_UNKNOWN, // -- 7 - SDL_SCANCODE_BACKSPACE, // VirtualKey.Back -- 8 - SDL_SCANCODE_TAB, // VirtualKey.Tab -- 9 - SDL_SCANCODE_UNKNOWN, // -- 10 - SDL_SCANCODE_UNKNOWN, // -- 11 - SDL_SCANCODE_CLEAR, // VirtualKey.Clear -- 12 - SDL_SCANCODE_RETURN, // VirtualKey.Enter -- 13 - SDL_SCANCODE_UNKNOWN, // -- 14 - SDL_SCANCODE_UNKNOWN, // -- 15 - SDL_SCANCODE_LSHIFT, // VirtualKey.Shift -- 16 - SDL_SCANCODE_LCTRL, // VirtualKey.Control -- 17 - SDL_SCANCODE_MENU, // VirtualKey.Menu -- 18 - SDL_SCANCODE_PAUSE, // VirtualKey.Pause -- 19 - SDL_SCANCODE_CAPSLOCK, // VirtualKey.CapitalLock -- 20 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Kana or VirtualKey.Hangul -- 21 - SDL_SCANCODE_UNKNOWN, // -- 22 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Junja -- 23 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Final -- 24 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Hanja or VirtualKey.Kanji -- 25 - SDL_SCANCODE_UNKNOWN, // -- 26 - SDL_SCANCODE_ESCAPE, // VirtualKey.Escape -- 27 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Convert -- 28 - SDL_SCANCODE_UNKNOWN, // VirtualKey.NonConvert -- 29 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Accept -- 30 - SDL_SCANCODE_UNKNOWN, // VirtualKey.ModeChange -- 31 (maybe SDL_SCANCODE_MODE ?) - SDL_SCANCODE_SPACE, // VirtualKey.Space -- 32 - SDL_SCANCODE_PAGEUP, // VirtualKey.PageUp -- 33 - SDL_SCANCODE_PAGEDOWN, // VirtualKey.PageDown -- 34 - SDL_SCANCODE_END, // VirtualKey.End -- 35 - SDL_SCANCODE_HOME, // VirtualKey.Home -- 36 - SDL_SCANCODE_LEFT, // VirtualKey.Left -- 37 - SDL_SCANCODE_UP, // VirtualKey.Up -- 38 - SDL_SCANCODE_RIGHT, // VirtualKey.Right -- 39 - SDL_SCANCODE_DOWN, // VirtualKey.Down -- 40 - SDL_SCANCODE_SELECT, // VirtualKey.Select -- 41 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Print -- 42 (maybe SDL_SCANCODE_PRINTSCREEN ?) - SDL_SCANCODE_EXECUTE, // VirtualKey.Execute -- 43 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Snapshot -- 44 - SDL_SCANCODE_INSERT, // VirtualKey.Insert -- 45 - SDL_SCANCODE_DELETE, // VirtualKey.Delete -- 46 - SDL_SCANCODE_HELP, // VirtualKey.Help -- 47 - SDL_SCANCODE_0, // VirtualKey.Number0 -- 48 - SDL_SCANCODE_1, // VirtualKey.Number1 -- 49 - SDL_SCANCODE_2, // VirtualKey.Number2 -- 50 - SDL_SCANCODE_3, // VirtualKey.Number3 -- 51 - SDL_SCANCODE_4, // VirtualKey.Number4 -- 52 - SDL_SCANCODE_5, // VirtualKey.Number5 -- 53 - SDL_SCANCODE_6, // VirtualKey.Number6 -- 54 - SDL_SCANCODE_7, // VirtualKey.Number7 -- 55 - SDL_SCANCODE_8, // VirtualKey.Number8 -- 56 - SDL_SCANCODE_9, // VirtualKey.Number9 -- 57 - SDL_SCANCODE_UNKNOWN, // -- 58 - SDL_SCANCODE_UNKNOWN, // -- 59 - SDL_SCANCODE_UNKNOWN, // -- 60 - SDL_SCANCODE_UNKNOWN, // -- 61 - SDL_SCANCODE_UNKNOWN, // -- 62 - SDL_SCANCODE_UNKNOWN, // -- 63 - SDL_SCANCODE_UNKNOWN, // -- 64 - SDL_SCANCODE_A, // VirtualKey.A -- 65 - SDL_SCANCODE_B, // VirtualKey.B -- 66 - SDL_SCANCODE_C, // VirtualKey.C -- 67 - SDL_SCANCODE_D, // VirtualKey.D -- 68 - SDL_SCANCODE_E, // VirtualKey.E -- 69 - SDL_SCANCODE_F, // VirtualKey.F -- 70 - SDL_SCANCODE_G, // VirtualKey.G -- 71 - SDL_SCANCODE_H, // VirtualKey.H -- 72 - SDL_SCANCODE_I, // VirtualKey.I -- 73 - SDL_SCANCODE_J, // VirtualKey.J -- 74 - SDL_SCANCODE_K, // VirtualKey.K -- 75 - SDL_SCANCODE_L, // VirtualKey.L -- 76 - SDL_SCANCODE_M, // VirtualKey.M -- 77 - SDL_SCANCODE_N, // VirtualKey.N -- 78 - SDL_SCANCODE_O, // VirtualKey.O -- 79 - SDL_SCANCODE_P, // VirtualKey.P -- 80 - SDL_SCANCODE_Q, // VirtualKey.Q -- 81 - SDL_SCANCODE_R, // VirtualKey.R -- 82 - SDL_SCANCODE_S, // VirtualKey.S -- 83 - SDL_SCANCODE_T, // VirtualKey.T -- 84 - SDL_SCANCODE_U, // VirtualKey.U -- 85 - SDL_SCANCODE_V, // VirtualKey.V -- 86 - SDL_SCANCODE_W, // VirtualKey.W -- 87 - SDL_SCANCODE_X, // VirtualKey.X -- 88 - SDL_SCANCODE_Y, // VirtualKey.Y -- 89 - SDL_SCANCODE_Z, // VirtualKey.Z -- 90 - SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftWindows -- 91 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?) - SDL_SCANCODE_UNKNOWN, // VirtualKey.RightWindows -- 92 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?) - SDL_SCANCODE_APPLICATION, // VirtualKey.Application -- 93 - SDL_SCANCODE_UNKNOWN, // -- 94 - SDL_SCANCODE_SLEEP, // VirtualKey.Sleep -- 95 - SDL_SCANCODE_KP_0, // VirtualKey.NumberPad0 -- 96 - SDL_SCANCODE_KP_1, // VirtualKey.NumberPad1 -- 97 - SDL_SCANCODE_KP_2, // VirtualKey.NumberPad2 -- 98 - SDL_SCANCODE_KP_3, // VirtualKey.NumberPad3 -- 99 - SDL_SCANCODE_KP_4, // VirtualKey.NumberPad4 -- 100 - SDL_SCANCODE_KP_5, // VirtualKey.NumberPad5 -- 101 - SDL_SCANCODE_KP_6, // VirtualKey.NumberPad6 -- 102 - SDL_SCANCODE_KP_7, // VirtualKey.NumberPad7 -- 103 - SDL_SCANCODE_KP_8, // VirtualKey.NumberPad8 -- 104 - SDL_SCANCODE_KP_9, // VirtualKey.NumberPad9 -- 105 - SDL_SCANCODE_KP_MULTIPLY, // VirtualKey.Multiply -- 106 - SDL_SCANCODE_KP_PLUS, // VirtualKey.Add -- 107 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Separator -- 108 - SDL_SCANCODE_KP_MINUS, // VirtualKey.Subtract -- 109 - SDL_SCANCODE_UNKNOWN, // VirtualKey.Decimal -- 110 (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?) - SDL_SCANCODE_KP_DIVIDE, // VirtualKey.Divide -- 111 - SDL_SCANCODE_F1, // VirtualKey.F1 -- 112 - SDL_SCANCODE_F2, // VirtualKey.F2 -- 113 - SDL_SCANCODE_F3, // VirtualKey.F3 -- 114 - SDL_SCANCODE_F4, // VirtualKey.F4 -- 115 - SDL_SCANCODE_F5, // VirtualKey.F5 -- 116 - SDL_SCANCODE_F6, // VirtualKey.F6 -- 117 - SDL_SCANCODE_F7, // VirtualKey.F7 -- 118 - SDL_SCANCODE_F8, // VirtualKey.F8 -- 119 - SDL_SCANCODE_F9, // VirtualKey.F9 -- 120 - SDL_SCANCODE_F10, // VirtualKey.F10 -- 121 - SDL_SCANCODE_F11, // VirtualKey.F11 -- 122 - SDL_SCANCODE_F12, // VirtualKey.F12 -- 123 - SDL_SCANCODE_F13, // VirtualKey.F13 -- 124 - SDL_SCANCODE_F14, // VirtualKey.F14 -- 125 - SDL_SCANCODE_F15, // VirtualKey.F15 -- 126 - SDL_SCANCODE_F16, // VirtualKey.F16 -- 127 - SDL_SCANCODE_F17, // VirtualKey.F17 -- 128 - SDL_SCANCODE_F18, // VirtualKey.F18 -- 129 - SDL_SCANCODE_F19, // VirtualKey.F19 -- 130 - SDL_SCANCODE_F20, // VirtualKey.F20 -- 131 - SDL_SCANCODE_F21, // VirtualKey.F21 -- 132 - SDL_SCANCODE_F22, // VirtualKey.F22 -- 133 - SDL_SCANCODE_F23, // VirtualKey.F23 -- 134 - SDL_SCANCODE_F24, // VirtualKey.F24 -- 135 - SDL_SCANCODE_UNKNOWN, // -- 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_NUMLOCKCLEAR, // VirtualKey.NumberKeyLock -- 144 - SDL_SCANCODE_SCROLLLOCK, // VirtualKey.Scroll -- 145 - SDL_SCANCODE_UNKNOWN, // -- 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_LSHIFT, // VirtualKey.LeftShift -- 160 - SDL_SCANCODE_RSHIFT, // VirtualKey.RightShift -- 161 - SDL_SCANCODE_LCTRL, // VirtualKey.LeftControl -- 162 - SDL_SCANCODE_RCTRL, // VirtualKey.RightControl -- 163 - SDL_SCANCODE_MENU, // VirtualKey.LeftMenu -- 164 - SDL_SCANCODE_MENU, // VirtualKey.RightMenu -- 165 - SDL_SCANCODE_AC_BACK, // VirtualKey.GoBack -- 166 : The go back key. - SDL_SCANCODE_AC_FORWARD, // VirtualKey.GoForward -- 167 : The go forward key. - SDL_SCANCODE_AC_REFRESH, // VirtualKey.Refresh -- 168 : The refresh key. - SDL_SCANCODE_AC_STOP, // VirtualKey.Stop -- 169 : The stop key. - SDL_SCANCODE_AC_SEARCH, // VirtualKey.Search -- 170 : The search key. - SDL_SCANCODE_AC_BOOKMARKS, // VirtualKey.Favorites -- 171 : The favorites key. - SDL_SCANCODE_AC_HOME // VirtualKey.GoHome -- 172 : The go home key. + SDL_SCANCODE_UNKNOWN, /* VirtualKey.None -- 0 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.LeftButton -- 1 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.RightButton -- 2 */ + SDL_SCANCODE_CANCEL, /* VirtualKey.Cancel -- 3 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.MiddleButton -- 4 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.XButton1 -- 5 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.XButton2 -- 6 */ + SDL_SCANCODE_UNKNOWN, /* -- 7 */ + SDL_SCANCODE_BACKSPACE, /* VirtualKey.Back -- 8 */ + SDL_SCANCODE_TAB, /* VirtualKey.Tab -- 9 */ + SDL_SCANCODE_UNKNOWN, /* -- 10 */ + SDL_SCANCODE_UNKNOWN, /* -- 11 */ + SDL_SCANCODE_CLEAR, /* VirtualKey.Clear -- 12 */ + SDL_SCANCODE_RETURN, /* VirtualKey.Enter -- 13 */ + SDL_SCANCODE_UNKNOWN, /* -- 14 */ + SDL_SCANCODE_UNKNOWN, /* -- 15 */ + SDL_SCANCODE_LSHIFT, /* VirtualKey.Shift -- 16 */ + SDL_SCANCODE_LCTRL, /* VirtualKey.Control -- 17 */ + SDL_SCANCODE_MENU, /* VirtualKey.Menu -- 18 */ + SDL_SCANCODE_PAUSE, /* VirtualKey.Pause -- 19 */ + SDL_SCANCODE_CAPSLOCK, /* VirtualKey.CapitalLock -- 20 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Kana or VirtualKey.Hangul -- 21 */ + SDL_SCANCODE_UNKNOWN, /* -- 22 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Junja -- 23 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Final -- 24 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Hanja or VirtualKey.Kanji -- 25 */ + SDL_SCANCODE_UNKNOWN, /* -- 26 */ + SDL_SCANCODE_ESCAPE, /* VirtualKey.Escape -- 27 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Convert -- 28 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.NonConvert -- 29 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Accept -- 30 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.ModeChange -- 31 (maybe SDL_SCANCODE_MODE ?) */ + SDL_SCANCODE_SPACE, /* VirtualKey.Space -- 32 */ + SDL_SCANCODE_PAGEUP, /* VirtualKey.PageUp -- 33 */ + SDL_SCANCODE_PAGEDOWN, /* VirtualKey.PageDown -- 34 */ + SDL_SCANCODE_END, /* VirtualKey.End -- 35 */ + SDL_SCANCODE_HOME, /* VirtualKey.Home -- 36 */ + SDL_SCANCODE_LEFT, /* VirtualKey.Left -- 37 */ + SDL_SCANCODE_UP, /* VirtualKey.Up -- 38 */ + SDL_SCANCODE_RIGHT, /* VirtualKey.Right -- 39 */ + SDL_SCANCODE_DOWN, /* VirtualKey.Down -- 40 */ + SDL_SCANCODE_SELECT, /* VirtualKey.Select -- 41 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Print -- 42 (maybe SDL_SCANCODE_PRINTSCREEN ?) */ + SDL_SCANCODE_EXECUTE, /* VirtualKey.Execute -- 43 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Snapshot -- 44 */ + SDL_SCANCODE_INSERT, /* VirtualKey.Insert -- 45 */ + SDL_SCANCODE_DELETE, /* VirtualKey.Delete -- 46 */ + SDL_SCANCODE_HELP, /* VirtualKey.Help -- 47 */ + SDL_SCANCODE_0, /* VirtualKey.Number0 -- 48 */ + SDL_SCANCODE_1, /* VirtualKey.Number1 -- 49 */ + SDL_SCANCODE_2, /* VirtualKey.Number2 -- 50 */ + SDL_SCANCODE_3, /* VirtualKey.Number3 -- 51 */ + SDL_SCANCODE_4, /* VirtualKey.Number4 -- 52 */ + SDL_SCANCODE_5, /* VirtualKey.Number5 -- 53 */ + SDL_SCANCODE_6, /* VirtualKey.Number6 -- 54 */ + SDL_SCANCODE_7, /* VirtualKey.Number7 -- 55 */ + SDL_SCANCODE_8, /* VirtualKey.Number8 -- 56 */ + SDL_SCANCODE_9, /* VirtualKey.Number9 -- 57 */ + SDL_SCANCODE_UNKNOWN, /* -- 58 */ + SDL_SCANCODE_UNKNOWN, /* -- 59 */ + SDL_SCANCODE_UNKNOWN, /* -- 60 */ + SDL_SCANCODE_UNKNOWN, /* -- 61 */ + SDL_SCANCODE_UNKNOWN, /* -- 62 */ + SDL_SCANCODE_UNKNOWN, /* -- 63 */ + SDL_SCANCODE_UNKNOWN, /* -- 64 */ + SDL_SCANCODE_A, /* VirtualKey.A -- 65 */ + SDL_SCANCODE_B, /* VirtualKey.B -- 66 */ + SDL_SCANCODE_C, /* VirtualKey.C -- 67 */ + SDL_SCANCODE_D, /* VirtualKey.D -- 68 */ + SDL_SCANCODE_E, /* VirtualKey.E -- 69 */ + SDL_SCANCODE_F, /* VirtualKey.F -- 70 */ + SDL_SCANCODE_G, /* VirtualKey.G -- 71 */ + SDL_SCANCODE_H, /* VirtualKey.H -- 72 */ + SDL_SCANCODE_I, /* VirtualKey.I -- 73 */ + SDL_SCANCODE_J, /* VirtualKey.J -- 74 */ + SDL_SCANCODE_K, /* VirtualKey.K -- 75 */ + SDL_SCANCODE_L, /* VirtualKey.L -- 76 */ + SDL_SCANCODE_M, /* VirtualKey.M -- 77 */ + SDL_SCANCODE_N, /* VirtualKey.N -- 78 */ + SDL_SCANCODE_O, /* VirtualKey.O -- 79 */ + SDL_SCANCODE_P, /* VirtualKey.P -- 80 */ + SDL_SCANCODE_Q, /* VirtualKey.Q -- 81 */ + SDL_SCANCODE_R, /* VirtualKey.R -- 82 */ + SDL_SCANCODE_S, /* VirtualKey.S -- 83 */ + SDL_SCANCODE_T, /* VirtualKey.T -- 84 */ + SDL_SCANCODE_U, /* VirtualKey.U -- 85 */ + SDL_SCANCODE_V, /* VirtualKey.V -- 86 */ + SDL_SCANCODE_W, /* VirtualKey.W -- 87 */ + SDL_SCANCODE_X, /* VirtualKey.X -- 88 */ + SDL_SCANCODE_Y, /* VirtualKey.Y -- 89 */ + SDL_SCANCODE_Z, /* VirtualKey.Z -- 90 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.LeftWindows -- 91 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?) */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.RightWindows -- 92 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?) */ + SDL_SCANCODE_APPLICATION, /* VirtualKey.Application -- 93 */ + SDL_SCANCODE_UNKNOWN, /* -- 94 */ + SDL_SCANCODE_SLEEP, /* VirtualKey.Sleep -- 95 */ + SDL_SCANCODE_KP_0, /* VirtualKey.NumberPad0 -- 96 */ + SDL_SCANCODE_KP_1, /* VirtualKey.NumberPad1 -- 97 */ + SDL_SCANCODE_KP_2, /* VirtualKey.NumberPad2 -- 98 */ + SDL_SCANCODE_KP_3, /* VirtualKey.NumberPad3 -- 99 */ + SDL_SCANCODE_KP_4, /* VirtualKey.NumberPad4 -- 100 */ + SDL_SCANCODE_KP_5, /* VirtualKey.NumberPad5 -- 101 */ + SDL_SCANCODE_KP_6, /* VirtualKey.NumberPad6 -- 102 */ + SDL_SCANCODE_KP_7, /* VirtualKey.NumberPad7 -- 103 */ + SDL_SCANCODE_KP_8, /* VirtualKey.NumberPad8 -- 104 */ + SDL_SCANCODE_KP_9, /* VirtualKey.NumberPad9 -- 105 */ + SDL_SCANCODE_KP_MULTIPLY, /* VirtualKey.Multiply -- 106 */ + SDL_SCANCODE_KP_PLUS, /* VirtualKey.Add -- 107 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Separator -- 108 */ + SDL_SCANCODE_KP_MINUS, /* VirtualKey.Subtract -- 109 */ + SDL_SCANCODE_UNKNOWN, /* VirtualKey.Decimal -- 110 (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?) */ + SDL_SCANCODE_KP_DIVIDE, /* VirtualKey.Divide -- 111 */ + SDL_SCANCODE_F1, /* VirtualKey.F1 -- 112 */ + SDL_SCANCODE_F2, /* VirtualKey.F2 -- 113 */ + SDL_SCANCODE_F3, /* VirtualKey.F3 -- 114 */ + SDL_SCANCODE_F4, /* VirtualKey.F4 -- 115 */ + SDL_SCANCODE_F5, /* VirtualKey.F5 -- 116 */ + SDL_SCANCODE_F6, /* VirtualKey.F6 -- 117 */ + SDL_SCANCODE_F7, /* VirtualKey.F7 -- 118 */ + SDL_SCANCODE_F8, /* VirtualKey.F8 -- 119 */ + SDL_SCANCODE_F9, /* VirtualKey.F9 -- 120 */ + SDL_SCANCODE_F10, /* VirtualKey.F10 -- 121 */ + SDL_SCANCODE_F11, /* VirtualKey.F11 -- 122 */ + SDL_SCANCODE_F12, /* VirtualKey.F12 -- 123 */ + SDL_SCANCODE_F13, /* VirtualKey.F13 -- 124 */ + SDL_SCANCODE_F14, /* VirtualKey.F14 -- 125 */ + SDL_SCANCODE_F15, /* VirtualKey.F15 -- 126 */ + SDL_SCANCODE_F16, /* VirtualKey.F16 -- 127 */ + SDL_SCANCODE_F17, /* VirtualKey.F17 -- 128 */ + SDL_SCANCODE_F18, /* VirtualKey.F18 -- 129 */ + SDL_SCANCODE_F19, /* VirtualKey.F19 -- 130 */ + SDL_SCANCODE_F20, /* VirtualKey.F20 -- 131 */ + SDL_SCANCODE_F21, /* VirtualKey.F21 -- 132 */ + SDL_SCANCODE_F22, /* VirtualKey.F22 -- 133 */ + SDL_SCANCODE_F23, /* VirtualKey.F23 -- 134 */ + SDL_SCANCODE_F24, /* VirtualKey.F24 -- 135 */ + SDL_SCANCODE_UNKNOWN, /* -- 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_NUMLOCKCLEAR, /* VirtualKey.NumberKeyLock -- 144 */ + SDL_SCANCODE_SCROLLLOCK, /* VirtualKey.Scroll -- 145 */ + SDL_SCANCODE_UNKNOWN, /* -- 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_LSHIFT, /* VirtualKey.LeftShift -- 160 */ + SDL_SCANCODE_RSHIFT, /* VirtualKey.RightShift -- 161 */ + SDL_SCANCODE_LCTRL, /* VirtualKey.LeftControl -- 162 */ + SDL_SCANCODE_RCTRL, /* VirtualKey.RightControl -- 163 */ + SDL_SCANCODE_MENU, /* VirtualKey.LeftMenu -- 164 */ + SDL_SCANCODE_MENU, /* VirtualKey.RightMenu -- 165 */ + SDL_SCANCODE_AC_BACK, /* VirtualKey.GoBack -- 166 : The go back key. */ + SDL_SCANCODE_AC_FORWARD, /* VirtualKey.GoForward -- 167 : The go forward key. */ + SDL_SCANCODE_AC_REFRESH, /* VirtualKey.Refresh -- 168 : The refresh key. */ + SDL_SCANCODE_AC_STOP, /* VirtualKey.Stop -- 169 : The stop key. */ + SDL_SCANCODE_AC_SEARCH, /* VirtualKey.Search -- 170 : The search key. */ + SDL_SCANCODE_AC_BOOKMARKS, /* VirtualKey.Favorites -- 171 : The favorites key. */ + SDL_SCANCODE_AC_HOME /* VirtualKey.GoHome -- 172 : The go home key. */ }; -static std::unordered_map WinRT_Unofficial_Keycodes; - +/* Attempt to translate a keycode that isn't listed in WinRT's VirtualKey enum. + */ static SDL_Scancode -TranslateKeycode(int keycode) +WINRT_TranslateUnofficialKeycode(int keycode) { - if (WinRT_Unofficial_Keycodes.empty()) { - /* Set up a table of keycodes that aren't listed in WinRT's - * VirtualKey enum. - */ - - WinRT_Unofficial_Keycodes[173] = SDL_SCANCODE_MUTE; - WinRT_Unofficial_Keycodes[174] = SDL_SCANCODE_VOLUMEDOWN; - WinRT_Unofficial_Keycodes[175] = SDL_SCANCODE_VOLUMEUP; - WinRT_Unofficial_Keycodes[176] = SDL_SCANCODE_AUDIONEXT; - WinRT_Unofficial_Keycodes[177] = SDL_SCANCODE_AUDIOPREV; - // WinRT_Unofficial_Keycodes[178] = ; - WinRT_Unofficial_Keycodes[179] = SDL_SCANCODE_AUDIOPLAY; - WinRT_Unofficial_Keycodes[180] = SDL_SCANCODE_MAIL; - WinRT_Unofficial_Keycodes[181] = SDL_SCANCODE_MEDIASELECT; - // WinRT_Unofficial_Keycodes[182] = ; - WinRT_Unofficial_Keycodes[183] = SDL_SCANCODE_CALCULATOR; - // WinRT_Unofficial_Keycodes[184] = ; - // WinRT_Unofficial_Keycodes[185] = ; - WinRT_Unofficial_Keycodes[186] = SDL_SCANCODE_SEMICOLON; - WinRT_Unofficial_Keycodes[187] = SDL_SCANCODE_EQUALS; - WinRT_Unofficial_Keycodes[188] = SDL_SCANCODE_COMMA; - WinRT_Unofficial_Keycodes[189] = SDL_SCANCODE_MINUS; - WinRT_Unofficial_Keycodes[190] = SDL_SCANCODE_PERIOD; - WinRT_Unofficial_Keycodes[191] = SDL_SCANCODE_SLASH; - WinRT_Unofficial_Keycodes[192] = SDL_SCANCODE_GRAVE; + switch (keycode) { + case 173: return SDL_SCANCODE_MUTE; /* VK_VOLUME_MUTE */ + case 174: return SDL_SCANCODE_VOLUMEDOWN; /* VK_VOLUME_DOWN */ + case 175: return SDL_SCANCODE_VOLUMEUP; /* VK_VOLUME_UP */ + case 176: return SDL_SCANCODE_AUDIONEXT; /* VK_MEDIA_NEXT_TRACK */ + case 177: return SDL_SCANCODE_AUDIOPREV; /* VK_MEDIA_PREV_TRACK */ + // case 178: return ; /* VK_MEDIA_STOP */ + case 179: return SDL_SCANCODE_AUDIOPLAY; /* VK_MEDIA_PLAY_PAUSE */ + case 180: return SDL_SCANCODE_MAIL; /* VK_LAUNCH_MAIL */ + case 181: return SDL_SCANCODE_MEDIASELECT; /* VK_LAUNCH_MEDIA_SELECT */ + // case 182: return ; /* VK_LAUNCH_APP1 */ + case 183: return SDL_SCANCODE_CALCULATOR; /* VK_LAUNCH_APP2 */ + // case 184: return ; /* ... reserved ... */ + // case 185: return ; /* ... reserved ... */ + case 186: return SDL_SCANCODE_SEMICOLON; /* VK_OEM_1, ';:' key on US standard keyboards */ + case 187: return SDL_SCANCODE_EQUALS; /* VK_OEM_PLUS */ + case 188: return SDL_SCANCODE_COMMA; /* VK_OEM_COMMA */ + case 189: return SDL_SCANCODE_MINUS; /* VK_OEM_MINUS */ + case 190: return SDL_SCANCODE_PERIOD; /* VK_OEM_PERIOD */ + case 191: return SDL_SCANCODE_SLASH; /* VK_OEM_2, '/?' key on US standard keyboards */ + case 192: return SDL_SCANCODE_GRAVE; /* VK_OEM_3, '`~' key on US standard keyboards */ // ? - // ... + // ... reserved or unassigned ... // ? - WinRT_Unofficial_Keycodes[219] = SDL_SCANCODE_LEFTBRACKET; - WinRT_Unofficial_Keycodes[220] = SDL_SCANCODE_BACKSLASH; - WinRT_Unofficial_Keycodes[221] = SDL_SCANCODE_RIGHTBRACKET; - WinRT_Unofficial_Keycodes[222] = SDL_SCANCODE_APOSTROPHE; + case 219: return SDL_SCANCODE_LEFTBRACKET; /* VK_OEM_4, '[{' key on US standard keyboards */ + case 220: return SDL_SCANCODE_BACKSLASH; /* VK_OEM_5, '\|' key on US standard keyboards */ + case 221: return SDL_SCANCODE_RIGHTBRACKET; /* VK_OEM_6, ']}' key on US standard keyboards */ + case 222: return SDL_SCANCODE_APOSTROPHE; /* VK_OEM_7, 'single/double quote' on US standard keyboards */ + default: break; } + return SDL_SCANCODE_UNKNOWN; +} + +static SDL_Scancode +WINRT_TranslateKeycode(int keycode, unsigned int nativeScancode) +{ + // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints + + SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; - /* Try to get a documented, WinRT, 'VirtualKey' first (as documented at + /* HACK ALERT: At least one VirtualKey constant (Shift) with a left/right + * designation might not get reported with its correct handedness, however + * its hardware scan code can fill in the gaps. If this is detected, + * use the hardware scan code to try telling if the left, or the right + * side's key was used. + * + * If Microsoft ever allows MapVirtualKey or MapVirtualKeyEx to be used + * in WinRT apps, or something similar to these (it doesn't appear to be, + * at least not for Windows [Phone] 8/8.1, as of Oct 24, 2014), then this + * hack might become deprecated, or obsolete. + */ + if (nativeScancode < SDL_arraysize(windows_scancode_table)) { + switch (keycode) { + case 16: // VirtualKey.Shift + switch (windows_scancode_table[nativeScancode]) { + case SDL_SCANCODE_LSHIFT: + case SDL_SCANCODE_RSHIFT: + return windows_scancode_table[nativeScancode]; + } + break; + + // Add others, as necessary. + // + // Unfortunately, this hack doesn't seem to work in determining + // handedness with Control keys. + + default: + break; + } + } + + /* Try to get a documented, WinRT, 'VirtualKey' next (as documented at http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.virtualkey.aspx ). If that fails, fall back to a Win32 virtual key. + If that fails, attempt to fall back to a scancode-derived key. */ - // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints - //SDL_Log("WinRT TranslateKeycode, keycode=%d\n", (int)keycode); - SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; if (keycode < SDL_arraysize(WinRT_Official_Keycodes)) { scancode = WinRT_Official_Keycodes[keycode]; } if (scancode == SDL_SCANCODE_UNKNOWN) { - if (WinRT_Unofficial_Keycodes.find(keycode) != WinRT_Unofficial_Keycodes.end()) { - scancode = WinRT_Unofficial_Keycodes[keycode]; + scancode = WINRT_TranslateUnofficialKeycode(keycode); + } + if (scancode == SDL_SCANCODE_UNKNOWN) { + if (nativeScancode < SDL_arraysize(windows_scancode_table)) { + scancode = windows_scancode_table[nativeScancode]; } } + /* if (scancode == SDL_SCANCODE_UNKNOWN) { SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode); } + */ return scancode; } void WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args) { - SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); + SDL_Scancode sdlScancode = WINRT_TranslateKeycode((int)args->VirtualKey, args->KeyStatus.ScanCode); #if 0 SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); - SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", + SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, " + "repeat count=%d, native scan code=0x%x, was down?=%s, vkey=%d, " + "sdl scan code=%d (%s), sdl key code=%d (%s)\n", (args->Handled ? "1" : "0"), (args->KeyStatus.IsExtendedKey ? "1" : "0"), (args->KeyStatus.IsKeyReleased ? "1" : "0"), @@ -297,7 +335,6 @@ WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args) keycode, SDL_GetKeyName(keycode)); //args->Handled = true; - //VirtualKey vkey = args->VirtualKey; #endif SDL_SendKeyboardKey(SDL_PRESSED, sdlScancode); } @@ -305,10 +342,12 @@ WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args) void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args) { - SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey); + SDL_Scancode sdlScancode = WINRT_TranslateKeycode((int)args->VirtualKey, args->KeyStatus.ScanCode); #if 0 SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode); - SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n", + SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, " + "repeat count=%d, native scan code=0x%x, was down?=%s, vkey=%d, " + "sdl scan code=%d (%s), sdl key code=%d (%s)\n", (args->Handled ? "1" : "0"), (args->KeyStatus.IsExtendedKey ? "1" : "0"), (args->KeyStatus.IsKeyReleased ? "1" : "0"), @@ -326,4 +365,22 @@ WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args) SDL_SendKeyboardKey(SDL_RELEASED, sdlScancode); } +void +WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArgs ^args) +{ + wchar_t src_ucs2[2]; + char dest_utf8[16]; + int result; + + /* Setup src */ + src_ucs2[0] = args->KeyCode; + src_ucs2[1] = L'\0'; + + /* Convert the text, then send an SDL_TEXTINPUT event. */ + result = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)&src_ucs2, -1, (LPSTR)dest_utf8, sizeof(dest_utf8), NULL, NULL); + if (result > 0) { + SDL_SendKeyboardText(dest_utf8); + } +} + #endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtmessagebox.cpp b/src/video/winrt/SDL_winrtmessagebox.cpp index a2153ce0f..dc38d214c 100644 --- a/src/video/winrt/SDL_winrtmessagebox.cpp +++ b/src/video/winrt/SDL_winrtmessagebox.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/winrt/SDL_winrtmessagebox.h b/src/video/winrt/SDL_winrtmessagebox.h index 63e23c5c4..8cae479a0 100644 --- a/src/video/winrt/SDL_winrtmessagebox.h +++ b/src/video/winrt/SDL_winrtmessagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/winrt/SDL_winrtmouse.cpp b/src/video/winrt/SDL_winrtmouse.cpp index 4c04a211c..cfebe9e0d 100644 --- a/src/video/winrt/SDL_winrtmouse.cpp +++ b/src/video/winrt/SDL_winrtmouse.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/winrt/SDL_winrtmouse_c.h b/src/video/winrt/SDL_winrtmouse_c.h index 676669b34..f97af04d2 100644 --- a/src/video/winrt/SDL_winrtmouse_c.h +++ b/src/video/winrt/SDL_winrtmouse_c.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -35,6 +35,6 @@ extern SDL_bool WINRT_UsingRelativeMouseMode; } #endif -#endif /* _SDL_windowsmouse_h */ +#endif /* _SDL_winrtmouse_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp index 4a84174d0..04c61ab9f 100644 --- a/src/video/winrt/SDL_winrtopengles.cpp +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -36,6 +36,16 @@ using namespace Windows::UI::Core; /* ANGLE/WinRT constants */ static const int ANGLE_D3D_FEATURE_LEVEL_ANY = 0; +#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 /* @@ -52,34 +62,114 @@ WINRT_GLES_LoadLibrary(_THIS, const char *path) } /* Load ANGLE/WinRT-specific functions */ - CreateWinrtEglWindow_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow"); - if (!CreateWinrtEglWindow) { - return SDL_SetError("Could not retrieve ANGLE/WinRT function CreateWinrtEglWindow"); - } - - /* Create an ANGLE/WinRT EGL-window */ - /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */ - CoreWindow ^ native_win = CoreWindow::GetForCurrentThread(); - Microsoft::WRL::ComPtr cpp_win = reinterpret_cast(native_win); - HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow)); - if (FAILED(result)) { - return -1; - } - - /* Call eglGetDisplay and eglInitialize as appropriate. On other - * platforms, this would probably get done by SDL_EGL_LoadLibrary, - * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of - * eglGetDisplay requires that a C++ object be passed into it, so the - * call will be made in this file, a C++ file, instead. - */ - Microsoft::WRL::ComPtr cpp_display = video_data->winrtEglWindow; - _this->egl_data->egl_display = ((eglGetDisplay_Function)_this->egl_data->eglGetDisplay)(cpp_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"); + CreateWinrtEglWindow_Old_Function CreateWinrtEglWindow = (CreateWinrtEglWindow_Old_Function) SDL_LoadFunction(_this->egl_data->egl_dll_handle, "CreateWinrtEglWindow"); + if (CreateWinrtEglWindow) { + /* 'CreateWinrtEglWindow' was found, which means that an an older + * version of ANGLE/WinRT is being used. Continue setting up EGL, + * as appropriate to this version of ANGLE. + */ + + /* Create an ANGLE/WinRT EGL-window */ + /* TODO, WinRT: check for XAML usage before accessing the CoreWindow, as not doing so could lead to a crash */ + CoreWindow ^ native_win = CoreWindow::GetForCurrentThread(); + Microsoft::WRL::ComPtr cpp_win = reinterpret_cast(native_win); + HRESULT result = CreateWinrtEglWindow(cpp_win, ANGLE_D3D_FEATURE_LEVEL_ANY, &(video_data->winrtEglWindow)); + if (FAILED(result)) { + return -1; + } + + /* Call eglGetDisplay and eglInitialize as appropriate. On other + * platforms, this would probably get done by SDL_EGL_LoadLibrary, + * however ANGLE/WinRT's current implementation (as of Mar 22, 2014) of + * eglGetDisplay requires that a C++ object be passed into it, so the + * call will be made in this file, a C++ file, instead. + */ + 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 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 { + /* 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, + }; + + /* 'CreateWinrtEglWindow' was NOT found, which either means that a + * newer version of ANGLE/WinRT is being used, or that we don't have + * a valid copy of ANGLE. + * + * Try loading ANGLE as if it were the newer version. + */ + eglGetPlatformDisplayEXT_Function eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_Function)_this->egl_data->eglGetProcAddress("eglGetPlatformDisplayEXT"); + if (!eglGetPlatformDisplayEXT) { + return SDL_SetError("Could not retrieve ANGLE/WinRT display function(s)"); + } + +#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 10_0+ EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) +#endif + { + /* Try initializing EGL at D3D11 Feature Level 9_3, in case the + * 10_0 init fails, or we're on Windows Phone (which only supports + * 9_3). + */ + _this->egl_data->egl_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3DisplayAttributes); + if (!_this->egl_data->egl_display) { + return SDL_SetError("Could not get 9_3 EGL display"); + } + + if (_this->egl_data->eglInitialize(_this->egl_data->egl_display, NULL, NULL) != EGL_TRUE) { + /* 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_winrtopengles.h b/src/video/winrt/SDL_winrtopengles.h index ae1739171..a0fde81ae 100644 --- a/src/video/winrt/SDL_winrtopengles.h +++ b/src/video/winrt/SDL_winrtopengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -47,18 +47,22 @@ extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext cont /* Typedefs for ANGLE/WinRT's C++-based native-display and native-window types, * which are used when calling eglGetDisplay and eglCreateWindowSurface. */ -typedef Microsoft::WRL::ComPtr WINRT_EGLNativeWindowType; -typedef WINRT_EGLNativeWindowType WINRT_EGLNativeDisplayType; +typedef Microsoft::WRL::ComPtr WINRT_EGLNativeWindowType_Old; -/* Function pointer typedefs for ANGLE/WinRT's functions that require - * parameter customization [by passing in C++ objects]. +/* Function pointer typedefs for 'old' ANGLE/WinRT's functions, which may + * require that C++ objects be passed in: */ -typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Function)(WINRT_EGLNativeWindowType); -typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType, const EGLint *); -typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Function)(Microsoft::WRL::ComPtr, int, IUnknown ** result); +typedef EGLDisplay (EGLAPIENTRY *eglGetDisplay_Old_Function)(WINRT_EGLNativeWindowType_Old); +typedef EGLSurface (EGLAPIENTRY *eglCreateWindowSurface_Old_Function)(EGLDisplay, EGLConfig, WINRT_EGLNativeWindowType_Old, const EGLint *); +typedef HRESULT (EGLAPIENTRY *CreateWinrtEglWindow_Old_Function)(Microsoft::WRL::ComPtr, int, IUnknown ** result); #endif /* __cplusplus */ +/* Function pointer typedefs for 'new' ANGLE/WinRT functions, which, unlike + * the old functions, do not require C++ support and work with plain C. + */ +typedef EGLDisplay (EGLAPIENTRY *eglGetPlatformDisplayEXT_Function)(EGLenum, void *, const EGLint *); + #endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ #endif /* _SDL_winrtopengles_h */ diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp index a2f7e4b54..d900ef48f 100644 --- a/src/video/winrt/SDL_winrtpointerinput.cpp +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -233,8 +233,8 @@ void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::Po if (!WINRT_LeftFingerDown) { if (button) { - SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); - SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, (int)windowPoint.X, (int)windowPoint.Y); + SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_PRESSED, button); } WINRT_LeftFingerDown = pointerPoint->PointerId; @@ -262,9 +262,9 @@ WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPo if ( ! WINRT_IsTouchEvent(pointerPoint)) { SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); - } else if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + } else { if (pointerPoint->PointerId == WINRT_LeftFingerDown) { - SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + SDL_SendMouseMotion(window, SDL_TOUCH_MOUSEID, 0, (int)windowPoint.X, (int)windowPoint.Y); } SDL_SendTouchMotion( @@ -291,7 +291,7 @@ void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::P if (WINRT_LeftFingerDown == pointerPoint->PointerId) { if (button) { - SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + SDL_SendMouseButton(window, SDL_TOUCH_MOUSEID, SDL_RELEASED, button); } WINRT_LeftFingerDown = 0; } @@ -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 6ec01609a..edd56f025 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -318,23 +318,43 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata; /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly, - * rather than via SDL_EGL_CreateSurface, as ANGLE/WinRT requires - * a C++ object, ComPtr, to be passed into - * eglCreateWindowSurface. + * rather than via SDL_EGL_CreateSurface, as older versions of + * ANGLE/WinRT may require that a C++ object, ComPtr, + * be passed into eglCreateWindowSurface. */ 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); } - Microsoft::WRL::ComPtr cpp_winrtEglWindow = video_data->winrtEglWindow; - data->egl_surface = ((eglCreateWindowSurface_Function)_this->egl_data->eglCreateWindowSurface)( - _this->egl_data->egl_display, - _this->egl_data->egl_config, - cpp_winrtEglWindow, NULL); - if (data->egl_surface == NULL) { - return SDL_SetError("eglCreateWindowSurface failed"); + if (video_data->winrtEglWindow) { /* ... is the 'old' version of ANGLE/WinRT being used? */ + /* Attempt to create a window surface using older versions of + * ANGLE/WinRT: + */ + Microsoft::WRL::ComPtr cpp_winrtEglWindow = video_data->winrtEglWindow; + data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)( + _this->egl_data->egl_display, + _this->egl_data->egl_config, + cpp_winrtEglWindow, NULL); + if (data->egl_surface == NULL) { + return SDL_SetError("eglCreateWindowSurface failed"); + } + } else if (data->coreWindow.Get() != nullptr) { + /* Attempt to create a window surface using newer versions of + * ANGLE/WinRT: + */ + IInspectable * coreWindowAsIInspectable = reinterpret_cast(data->coreWindow.Get()); + data->egl_surface = _this->egl_data->eglCreateWindowSurface( + _this->egl_data->egl_display, + _this->egl_data->egl_config, + coreWindowAsIInspectable, + NULL); + if (data->egl_surface == NULL) { + return SDL_SetError("eglCreateWindowSurface failed"); + } + } else { + return SDL_SetError("No supported means to create an EGL window surface are available"); } } #endif @@ -394,6 +414,7 @@ WINRT_DestroyWindow(_THIS, SDL_Window * window) // Delete the internal window data: delete data; data = NULL; + window->driverdata = NULL; } } diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h index e327280dc..a39de826a 100644 --- a/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/src/video/winrt/SDL_winrtvideo_cpp.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11clipboard.c b/src/video/x11/SDL_x11clipboard.c index 2999d9837..eca40f2af 100644 --- a/src/video/x11/SDL_x11clipboard.c +++ b/src/video/x11/SDL_x11clipboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -49,6 +49,14 @@ GetWindow(_THIS) return None; } +/* We use our own cut-buffer for intermediate storage instead of + XA_CUT_BUFFER0 because their use isn't really defined for holding UTF8. */ +Atom +X11_GetSDLCutBufferClipboardType(Display *display) +{ + return X11_XInternAtom(display, "SDL_CUTBUFFER", False); +} + int X11_SetClipboardText(_THIS, const char *text) { @@ -66,7 +74,7 @@ X11_SetClipboardText(_THIS, const char *text) /* Save the selection on the root window */ format = TEXT_FORMAT; X11_XChangeProperty(display, DefaultRootWindow(display), - XA_CUT_BUFFER0, format, 8, PropModeReplace, + X11_GetSDLCutBufferClipboardType(display), format, 8, PropModeReplace, (const unsigned char *)text, SDL_strlen(text)); if (XA_CLIPBOARD != None && @@ -109,9 +117,14 @@ X11_GetClipboardText(_THIS) window = GetWindow(_this); format = TEXT_FORMAT; owner = X11_XGetSelectionOwner(display, XA_CLIPBOARD); - if ((owner == None) || (owner == window)) { + if (owner == None) { + /* Fall back to ancient X10 cut-buffers which do not support UTF8 strings*/ owner = DefaultRootWindow(display); selection = XA_CUT_BUFFER0; + format = XA_STRING; + } else if (owner == window) { + owner = DefaultRootWindow(display); + selection = X11_GetSDLCutBufferClipboardType(display); } else { /* Request that the selection owner copy the data to our window */ owner = window; diff --git a/src/video/x11/SDL_x11clipboard.h b/src/video/x11/SDL_x11clipboard.h index 46291cf60..09dcf568c 100644 --- a/src/video/x11/SDL_x11clipboard.h +++ b/src/video/x11/SDL_x11clipboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -26,6 +26,7 @@ extern int X11_SetClipboardText(_THIS, const char *text); extern char *X11_GetClipboardText(_THIS); extern SDL_bool X11_HasClipboardText(_THIS); +extern Atom X11_GetSDLCutBufferClipboardType(Display *display); #endif /* _SDL_x11clipboard_h */ diff --git a/src/video/x11/SDL_x11dyn.c b/src/video/x11/SDL_x11dyn.c index 97760ba32..58e97be7e 100644 --- a/src/video/x11/SDL_x11dyn.c +++ b/src/video/x11/SDL_x11dyn.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -207,7 +207,7 @@ SDL_X11_LoadSymbols(void) #else /* no dynamic X11 */ #define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 1; /* default yes */ -#define SDL_X11_SYM(a,fn,x,y,z) X11_##fn = fn; +#define SDL_X11_SYM(a,fn,x,y,z) X11_##fn = (SDL_DYNX11FN_##fn) fn; #include "SDL_x11sym.h" #undef SDL_X11_MODULE #undef SDL_X11_SYM diff --git a/src/video/x11/SDL_x11dyn.h b/src/video/x11/SDL_x11dyn.h index 7d2e077c6..2d729b708 100644 --- a/src/video/x11/SDL_x11dyn.h +++ b/src/video/x11/SDL_x11dyn.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -50,6 +50,9 @@ #if SDL_VIDEO_DRIVER_X11_XCURSOR #include #endif +#if SDL_VIDEO_DRIVER_X11_XDBE +#include +#endif #if SDL_VIDEO_DRIVER_X11_XINERAMA #include #endif diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index b4b33d76a..313753d36 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -40,6 +40,8 @@ #include +/*#define DEBUG_XEVENTS*/ + #ifndef _NET_WM_MOVERESIZE_SIZE_TOPLEFT #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 #endif @@ -132,7 +134,6 @@ static Atom X11_PickTargetFromAtoms(Display *disp, Atom a0, Atom a1, Atom a2) if (a2 != None) atom[count++] = a2; return X11_PickTarget(disp, atom, count); } -/* #define DEBUG_XEVENTS */ struct KeyRepeatCheckData { @@ -172,14 +173,15 @@ static Bool X11_IsWheelCheckIfEvent(Display *display, XEvent *chkev, XEvent *event = (XEvent *) arg; /* we only handle buttons 4 and 5 - false positive avoidance */ if (chkev->type == ButtonRelease && - (event->xbutton.button == Button4 || event->xbutton.button == Button5) && + (event->xbutton.button == Button4 || event->xbutton.button == Button5 || + event->xbutton.button == 6 || event->xbutton.button == 7) && chkev->xbutton.button == event->xbutton.button && chkev->xbutton.time == event->xbutton.time) return True; return False; } -static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks) +static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * xticks,int * yticks) { XEvent relevent; if (X11_XPending(display)) { @@ -197,12 +199,19 @@ static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * ticks) (XPointer) event)) { /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse, - Button4 maps to wheel up, Button5 maps to wheel down. */ + Button4 maps to (vertical) wheel up, Button5 maps to wheel down. + Horizontal scrolling usually maps to 6 and 7 which have no name */ if (event->xbutton.button == Button4) { - *ticks = 1; + *yticks = 1; } else if (event->xbutton.button == Button5) { - *ticks = -1; + *yticks = -1; + } + else if (event->xbutton.button == 6) { + *xticks = 1; + } + else if (event->xbutton.button == 7) { + *xticks = -1; } return SDL_TRUE; } @@ -293,27 +302,27 @@ static char* X11_URIToLocal(char* uri) { if (memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */ else if (strstr(uri,":/") != NULL) return file; /* wrong scheme */ - local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' ); + local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/'); /* got a hostname? */ - if ( !local && uri[0] == '/' && uri[2] != '/' ) { - char* hostname_end = strchr( uri+1, '/' ); - if ( hostname_end != NULL ) { + if (!local && uri[0] == '/' && uri[2] != '/') { + char* hostname_end = strchr(uri+1, '/'); + if (hostname_end != NULL) { char hostname[ 257 ]; - if ( gethostname( hostname, 255 ) == 0 ) { + if (gethostname(hostname, 255) == 0) { hostname[ 256 ] = '\0'; - if ( memcmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) { + if (memcmp(uri+1, hostname, hostname_end - (uri+1)) == 0) { uri = hostname_end + 1; local = SDL_TRUE; } } } } - if ( local ) { + if (local) { file = uri; /* Convert URI escape sequences to real characters */ X11_URIDecode(file, 0); - if ( uri[1] == '/' ) { + if (uri[1] == '/') { file++; } else { file--; @@ -334,14 +343,86 @@ static void X11_HandleGenericEvent(SDL_VideoData *videodata,XEvent event) } #endif /* SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS */ +static unsigned +X11_GetNumLockModifierMask(_THIS) +{ + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + Display *display = viddata->display; + unsigned num_mask = 0; + int i, j; + XModifierKeymap *xmods; + unsigned n; + + xmods = X11_XGetModifierMapping(display); + n = xmods->max_keypermod; + for(i = 3; i < 8; i++) { + for(j = 0; j < n; j++) { + KeyCode kc = xmods->modifiermap[i * n + j]; + if (viddata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) { + num_mask = 1 << i; + break; + } + } + } + X11_XFreeModifiermap(xmods); + + return num_mask; +} static void -X11_DispatchFocusIn(SDL_WindowData *data) +X11_ReconcileKeyboardState(_THIS) +{ + SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + Display *display = viddata->display; + char keys[32]; + int keycode; + Window junk_window; + int x, y; + unsigned int mask; + + X11_XQueryKeymap(display, keys); + + /* Get the keyboard modifier state */ + if (X11_XQueryPointer(display, DefaultRootWindow(display), &junk_window, &junk_window, &x, &y, &x, &y, &mask)) { + unsigned num_mask = X11_GetNumLockModifierMask(_this); + const Uint8 *keystate = SDL_GetKeyboardState(NULL); + Uint8 capslockState = keystate[SDL_SCANCODE_CAPSLOCK]; + Uint8 numlockState = keystate[SDL_SCANCODE_NUMLOCKCLEAR]; + + /* Toggle key mod state if needed */ + if (!!(mask & LockMask) != !!(SDL_GetModState() & KMOD_CAPS)) { + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); + if (capslockState == SDL_RELEASED) { + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); + } + } + + if (!!(mask & num_mask) != !!(SDL_GetModState() & KMOD_NUM)) { + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_NUMLOCKCLEAR); + if (numlockState == SDL_RELEASED) { + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_NUMLOCKCLEAR); + } + } + } + + for (keycode = 0; keycode < 256; ++keycode) { + if (keys[keycode / 8] & (1 << (keycode % 8))) { + SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]); + } else { + SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]); + } + } +} + + +static void +X11_DispatchFocusIn(_THIS, SDL_WindowData *data) { #ifdef DEBUG_XEVENTS printf("window %p: Dispatching FocusIn\n", data); #endif SDL_SetKeyboardFocus(data->window); + X11_ReconcileKeyboardState(_this); #ifdef X_HAVE_UTF8_STRING if (data->ic) { X11_XSetICFocus(data->ic); @@ -353,7 +434,7 @@ X11_DispatchFocusIn(SDL_WindowData *data) } static void -X11_DispatchFocusOut(SDL_WindowData *data) +X11_DispatchFocusOut(_THIS, SDL_WindowData *data) { #ifdef DEBUG_XEVENTS printf("window %p: Dispatching FocusOut\n", data); @@ -448,84 +529,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; -} - -static void -ReconcileKeyboardState(_THIS, const SDL_WindowData *data) -{ - SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; - SDL_Window* window = data->window; - Display *display = viddata->display; - char keys[32]; - int keycode = 0; - - X11_XQueryKeymap( display, keys ); - - while ( keycode < 256 ) { - if ( keys[keycode / 8] & (1 << (keycode % 8)) ) { - SDL_SendKeyboardKey(SDL_PRESSED, viddata->key_layout[keycode]); - } else { - SDL_SendKeyboardKey(SDL_RELEASED, viddata->key_layout[keycode]); - } - keycode++; - } + return SDL_FALSE; } static void @@ -607,6 +642,24 @@ X11_DispatchEvent(_THIS) } } if (!data) { + /* The window for KeymapNotify, etc events is 0 */ + if (xevent.type == KeymapNotify) { + if (SDL_GetKeyboardFocus() != NULL) { + X11_ReconcileKeyboardState(_this); + } + } else if (xevent.type == MappingNotify) { + /* Has the keyboard layout changed? */ + const int request = xevent.xmapping.request; + +#ifdef DEBUG_XEVENTS + printf("window %p: MappingNotify!\n", data); +#endif + if ((request == MappingKeyboard) || (request == MappingModifier)) { + X11_XRefreshKeyboardMapping(&xevent.xmapping); + } + + X11_UpdateKeymap(_this); + } return; } @@ -674,12 +727,17 @@ X11_DispatchEvent(_THIS) #ifdef DEBUG_XEVENTS printf("window %p: FocusIn!\n", data); #endif - if (data->pending_focus == PENDING_FOCUS_OUT && - data->window == SDL_GetKeyboardFocus()) { - ReconcileKeyboardState(_this, data); + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusIn(_this, data); + } + else + { + data->pending_focus = PENDING_FOCUS_IN; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; } - data->pending_focus = PENDING_FOCUS_IN; - data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_IN_TIME; } break; @@ -702,28 +760,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; - } - break; - - /* Generated upon EnterWindow and FocusIn */ - case KeymapNotify:{ -#ifdef DEBUG_XEVENTS - printf("window %p: KeymapNotify!\n", data); -#endif - /* FIXME: - X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); - */ - } - break; - - /* Has the keyboard layout changed? */ - case MappingNotify:{ -#ifdef DEBUG_XEVENTS - printf("window %p: MappingNotify!\n", data); -#endif - X11_UpdateKeymap(_this); + if (!videodata->last_mode_change_deadline) /* no recent mode changes */ + { + data->pending_focus = PENDING_FOCUS_NONE; + data->pending_focus_time = 0; + X11_DispatchFocusOut(_this, data); + } + else + { + data->pending_focus = PENDING_FOCUS_OUT; + data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; + } } break; @@ -745,7 +792,7 @@ X11_DispatchEvent(_THIS) #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); #else - keysym = XKeycodeToKeysym(display, keycode, 0); + keysym = X11_XKeycodeToKeysym(display, keycode, 0); #endif fprintf(stderr, "The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list X11 KeyCode %d (%d), X11 KeySym 0x%lX (%s).\n", @@ -761,21 +808,19 @@ X11_DispatchEvent(_THIS) &keysym, &status); } #else - XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); + X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); #endif + #ifdef SDL_USE_IBUS if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - if(!(handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode))){ -#endif - if(*text){ - SDL_SendKeyboardText(text); - } -#ifdef SDL_USE_IBUS - } + handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode); } #endif if (!handled_by_ime) { SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); + if(*text) { + SDL_SendKeyboardText(text); + } } } @@ -867,12 +912,19 @@ X11_DispatchEvent(_THIS) /* Have we been requested to quit (or another client message?) */ case ClientMessage:{ - int xdnd_version=0; + static int xdnd_version=0; if (xevent.xclient.message_type == videodata->XdndEnter) { + SDL_bool use_list = xevent.xclient.data.l[1] & 1; data->xdnd_source = xevent.xclient.data.l[0]; - xdnd_version = ( xevent.xclient.data.l[1] >> 24); + xdnd_version = (xevent.xclient.data.l[1] >> 24); +#ifdef DEBUG_XEVENTS + printf("XID of source window : %ld\n", data->xdnd_source); + printf("Protocol version to use : %d\n", xdnd_version); + printf("More then 3 data types : %d\n", (int) use_list); +#endif + if (use_list) { /* fetch conversion targets */ SDL_x11Prop p; @@ -886,6 +938,15 @@ X11_DispatchEvent(_THIS) } } else if (xevent.xclient.message_type == videodata->XdndPosition) { + +#ifdef DEBUG_XEVENTS + Atom act= videodata->XdndActionCopy; + if(xdnd_version >= 2) { + act = xevent.xclient.data.l[4]; + } + printf("Action requested by user is : %s\n", X11_XGetAtomName(display , act)); +#endif + /* reply with status */ memset(&m, 0, sizeof(XClientMessageEvent)); @@ -973,22 +1034,33 @@ X11_DispatchEvent(_THIS) break; case ButtonPress:{ - int ticks = 0; - if (X11_IsWheelEvent(display,&xevent,&ticks)) { - SDL_SendMouseWheel(data->window, 0, 0, ticks); + int xticks = 0, yticks = 0; + if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) { + SDL_SendMouseWheel(data->window, 0, xticks, yticks, SDL_MOUSEWHEEL_NORMAL); } else { - if(xevent.xbutton.button == Button1) { + int button = xevent.xbutton.button; + if(button == Button1) { if (ProcessHitTest(_this, data, &xevent)) { break; /* don't pass this event on to app. */ } } - SDL_SendMouseButton(data->window, 0, SDL_PRESSED, xevent.xbutton.button); + else if(button > 7) { + /* X button values 4-7 are used for scrolling, so X1 is 8, X2 is 9, ... + => subtract (8-SDL_BUTTON_X1) to get value SDL expects */ + button -= (8-SDL_BUTTON_X1); + } + SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button); } } break; case ButtonRelease:{ - SDL_SendMouseButton(data->window, 0, SDL_RELEASED, xevent.xbutton.button); + int button = xevent.xbutton.button; + if (button > 7) { + /* see explanation at case ButtonPress */ + button -= (8-SDL_BUTTON_X1); + } + SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button); } break; @@ -997,7 +1069,7 @@ X11_DispatchEvent(_THIS) unsigned char *propdata; int status, real_format; Atom real_type; - unsigned long items_read, items_left, i; + unsigned long items_read, items_left; char *name = X11_XGetAtomName(display, xevent.xproperty.atom); if (name) { @@ -1049,18 +1121,18 @@ X11_DispatchEvent(_THIS) printf("{"); for (i = 0; i < items_read; i++) { - char *name = X11_XGetAtomName(display, atoms[i]); - if (name) { - printf(" %s", name); - X11_XFree(name); + char *atomname = X11_XGetAtomName(display, atoms[i]); + if (atomname) { + printf(" %s", atomname); + X11_XFree(atomname); } } printf(" }\n"); } else { - char *name = X11_XGetAtomName(display, real_type); - printf("Unknown type: %ld (%s)\n", real_type, name ? name : "UNKNOWN"); - if (name) { - X11_XFree(name); + char *atomname = X11_XGetAtomName(display, real_type); + printf("Unknown type: %ld (%s)\n", real_type, atomname ? atomname : "UNKNOWN"); + if (atomname) { + X11_XFree(atomname); } } } @@ -1075,20 +1147,30 @@ 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; - /* Copy the selection from XA_CUT_BUFFER0 to the requested property */ + /* Copy the selection from our own CUTBUFFER to the requested property */ case SelectionRequest: { XSelectionRequestEvent *req; XEvent sevent; @@ -1110,8 +1192,9 @@ X11_DispatchEvent(_THIS) sevent.xselection.property = None; sevent.xselection.requestor = req->requestor; sevent.xselection.time = req->time; + if (X11_XGetWindowProperty(display, DefaultRootWindow(display), - XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target, + X11_GetSDLCutBufferClipboardType(display), 0, INT_MAX/4, False, req->target, &sevent.xselection.target, &seln_format, &nbytes, &overflow, &seln_data) == Success) { Atom XA_TARGETS = X11_XInternAtom(display, "TARGETS", 0); @@ -1121,12 +1204,13 @@ X11_DispatchEvent(_THIS) seln_data, nbytes); sevent.xselection.property = req->property; } else if (XA_TARGETS == req->target) { - Atom SupportedFormats[] = { sevent.xselection.target, XA_TARGETS }; + Atom SupportedFormats[] = { XA_TARGETS, sevent.xselection.target }; X11_XChangeProperty(display, req->requestor, req->property, XA_ATOM, 32, PropModeReplace, (unsigned char*)SupportedFormats, - sizeof(SupportedFormats)/sizeof(*SupportedFormats)); + SDL_arraysize(SupportedFormats)); sevent.xselection.property = req->property; + sevent.xselection.target = XA_TARGETS; } X11_XFree(seln_data); } @@ -1203,6 +1287,16 @@ X11_DispatchEvent(_THIS) } break; + case SelectionClear: { + Atom XA_CLIPBOARD = X11_XInternAtom(display, "CLIPBOARD", 0); + + if (xevent.xselectionclear.selection == XA_PRIMARY || + (XA_CLIPBOARD != None && xevent.xselectionclear.selection == XA_CLIPBOARD)) { + SDL_SendClipboardUpdate(); + } + } + break; + default:{ #ifdef DEBUG_XEVENTS printf("window %p: Unhandled event %d\n", data, xevent.type); @@ -1224,10 +1318,10 @@ X11_HandleFocusChanges(_THIS) if (data && data->pending_focus != PENDING_FOCUS_NONE) { Uint32 now = SDL_GetTicks(); if (SDL_TICKS_PASSED(now, data->pending_focus_time)) { - if ( data->pending_focus == PENDING_FOCUS_IN ) { - X11_DispatchFocusIn(data); + if (data->pending_focus == PENDING_FOCUS_IN) { + X11_DispatchFocusIn(_this, data); } else { - X11_DispatchFocusOut(data); + X11_DispatchFocusOut(_this, data); } data->pending_focus = PENDING_FOCUS_NONE; } @@ -1268,9 +1362,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); @@ -1283,17 +1383,17 @@ X11_PumpEvents(_THIS) } } + /* Keep processing pending events */ + while (X11_Pending(data->display)) { + X11_DispatchEvent(_this); + } + #ifdef SDL_USE_IBUS if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ SDL_IBus_PumpEvents(); } #endif - /* Keep processing pending events */ - while (X11_Pending(data->display)) { - X11_DispatchEvent(_this); - } - /* FIXME: Only need to do this when there are pending focus changes */ X11_HandleFocusChanges(_this); } diff --git a/src/video/x11/SDL_x11events.h b/src/video/x11/SDL_x11events.h index e27d53ac5..a6d434de6 100644 --- a/src/video/x11/SDL_x11events.h +++ b/src/video/x11/SDL_x11events.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11framebuffer.c b/src/video/x11/SDL_x11framebuffer.c index 19d9d0ba0..90a4a6fcc 100644 --- a/src/video/x11/SDL_x11framebuffer.c +++ b/src/video/x11/SDL_x11framebuffer.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11framebuffer.h b/src/video/x11/SDL_x11framebuffer.h index c73c7487d..359ee1571 100644 --- a/src/video/x11/SDL_x11framebuffer.h +++ b/src/video/x11/SDL_x11framebuffer.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index 53866ab55..0c4a2a8a9 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -154,7 +154,7 @@ X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); #else - keysym = XKeycodeToKeysym(display, keycode, 0); + keysym = X11_XKeycodeToKeysym(display, keycode, 0); #endif if (keysym == NoSymbol) { return SDL_SCANCODE_UNKNOWN; @@ -184,7 +184,7 @@ X11_KeyCodeToUcs4(Display *display, KeyCode keycode) #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); #else - keysym = XKeycodeToKeysym(display, keycode, 0); + keysym = X11_XKeycodeToKeysym(display, keycode, 0); #endif if (keysym == NoSymbol) { return 0; @@ -252,8 +252,7 @@ X11_InitKeyboard(_THIS) #endif SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table, sizeof(SDL_Scancode) * scancode_set[best_index].table_size); - } - else { + } else { SDL_Keycode keymap[SDL_NUM_SCANCODES]; printf @@ -266,7 +265,7 @@ X11_InitKeyboard(_THIS) #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0); #else - sym = XKeycodeToKeysym(data->display, i, 0); + sym = X11_XKeycodeToKeysym(data->display, i, 0); #endif if (sym != NoSymbol) { SDL_Scancode scancode; @@ -316,6 +315,29 @@ X11_UpdateKeymap(_THIS) key = X11_KeyCodeToUcs4(data->display, (KeyCode)i); if (key) { keymap[scancode] = key; + } else { + SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(data->display, (KeyCode)i); + + switch (keyScancode) { + case SDL_SCANCODE_RETURN: + keymap[scancode] = SDLK_RETURN; + break; + case SDL_SCANCODE_ESCAPE: + keymap[scancode] = SDLK_ESCAPE; + break; + case SDL_SCANCODE_BACKSPACE: + keymap[scancode] = SDLK_BACKSPACE; + break; + case SDL_SCANCODE_TAB: + keymap[scancode] = SDLK_TAB; + break; + case SDL_SCANCODE_DELETE: + keymap[scancode] = SDLK_DELETE; + break; + default: + keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode); + break; + } } } SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); diff --git a/src/video/x11/SDL_x11keyboard.h b/src/video/x11/SDL_x11keyboard.h index 6037e5c09..1e9c48ca5 100644 --- a/src/video/x11/SDL_x11keyboard.h +++ b/src/video/x11/SDL_x11keyboard.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 2a98e3c3e..a52d4c9e0 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -28,11 +28,12 @@ #include "SDL_x11dyn.h" #include "SDL_assert.h" +#include #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 @@ -83,6 +84,10 @@ typedef struct SDL_MessageBoxDataX11 Display *display; int screen; Window window; +#if SDL_VIDEO_DRIVER_X11_XDBE + XdbeBackBuffer buf; + SDL_bool xdbe; /* Whether Xdbe is present or not */ +#endif long event_mask; Atom wm_protocols; Atom wm_delete_message; @@ -347,6 +352,12 @@ X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data ) data->font_struct = NULL; } +#if SDL_VIDEO_DRIVER_X11_XDBE + if ( SDL_X11_HAVE_XDBE && data->xdbe ) { + X11_XdbeDeallocateBackBufferName(data->display, data->buf); + } +#endif + if ( data->display ) { if ( data->window != None ) { X11_XWithdrawWindow( data->display, data->window, data->screen ); @@ -366,6 +377,7 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) int x, y; XSizeHints *sizehints; XSetWindowAttributes wnd_attr; + Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME, UTF8_STRING; Display *display = data->display; SDL_WindowData *windowdata = NULL; const SDL_MessageBoxData *messageboxdata = data->messageboxdata; @@ -400,6 +412,18 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) } X11_XStoreName( display, data->window, messageboxdata->title ); + _NET_WM_NAME = X11_XInternAtom(display, "_NET_WM_NAME", False); + UTF8_STRING = X11_XInternAtom(display, "UTF8_STRING", False); + X11_XChangeProperty(display, data->window, _NET_WM_NAME, UTF8_STRING, 8, + PropModeReplace, (unsigned char *) messageboxdata->title, + strlen(messageboxdata->title) + 1 ); + + /* 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 ); @@ -415,8 +439,16 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ; X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy); } else { - x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2; - y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ; + const SDL_VideoDevice *dev = SDL_GetVideoDevice(); + if ((dev) && (dev->displays) && (dev->num_displays > 0)) { + const SDL_VideoDisplay *dpy = &dev->displays[0]; + const SDL_DisplayData *dpydata = (SDL_DisplayData *) dpy->driverdata; + x = dpydata->x + (( dpy->current_mode.w - data->dialog_width ) / 2); + y = dpydata->y + (( dpy->current_mode.h - data->dialog_height ) / 3); + } else { /* oh well. This will misposition on a multi-head setup. Init first next time. */ + x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2; + y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ; + } } X11_XMoveWindow( display, data->window, x, y ); @@ -437,6 +469,20 @@ X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data ) } X11_XMapRaised( display, data->window ); + +#if SDL_VIDEO_DRIVER_X11_XDBE + /* Initialise a back buffer for double buffering */ + if (SDL_X11_HAVE_XDBE) { + int xdbe_major, xdbe_minor; + if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) { + data->xdbe = SDL_TRUE; + data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined); + } else { + data->xdbe = SDL_FALSE; + } + } +#endif + return 0; } @@ -445,9 +491,16 @@ static void X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx ) { int i; - Window window = data->window; + Drawable window = data->window; Display *display = data->display; +#if SDL_VIDEO_DRIVER_X11_XDBE + if (SDL_X11_HAVE_XDBE && data->xdbe) { + window = data->buf; + X11_XdbeBeginIdiom(data->display); + } +#endif + X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ] ); X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height ); @@ -497,6 +550,23 @@ X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx ) buttondata->text, buttondatax11->length ); } } + +#if SDL_VIDEO_DRIVER_X11_XDBE + if (SDL_X11_HAVE_XDBE && data->xdbe) { + XdbeSwapInfo swap_info; + swap_info.swap_window = data->window; + swap_info.swap_action = XdbeUndefined; + X11_XdbeSwapBuffers(data->display, &swap_info, 1); + X11_XdbeEndIdiom(data->display); + } +#endif +} + +static Bool +X11_MessageBoxEventTest(Display *display, XEvent *event, XPointer arg) +{ + const SDL_MessageBoxDataX11 *data = (const SDL_MessageBoxDataX11 *) arg; + return ((event->xany.display == data->display) && (event->xany.window == data->window)) ? True : False; } /* Loop and handle message box event messages until something kills it. */ @@ -531,7 +601,9 @@ X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data ) XEvent e; SDL_bool draw = SDL_TRUE; - X11_XWindowEvent( data->display, data->window, data->event_mask, &e ); + /* can't use XWindowEvent() because it can't handle ClientMessage events. */ + /* can't use XNextEvent() because we only want events for this window. */ + X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data ); /* If X11_XFilterEvent returns True, then some input method has filtered the event, and the client should discard the event. */ @@ -560,7 +632,7 @@ X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data ) case MotionNotify: if ( has_focus ) { /* Mouse moved... */ - int previndex = data->mouse_over_index; + const int previndex = data->mouse_over_index; data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y ); if (data->mouse_over_index == previndex) { draw = SDL_FALSE; @@ -710,9 +782,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_x11messagebox.h b/src/video/x11/SDL_x11messagebox.h index d2d171288..37d8312cf 100644 --- a/src/video/x11/SDL_x11messagebox.h +++ b/src/video/x11/SDL_x11messagebox.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index 0fc6d2386..eb4bf7e27 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -24,6 +24,7 @@ #include "SDL_hints.h" #include "SDL_x11video.h" +#include "SDL_timer.h" #include "edid.h" /* #define X11MODES_DEBUG */ @@ -191,6 +192,21 @@ CheckXinerama(Display * display, int *major, int *minor) #endif return SDL_TRUE; } + +/* !!! FIXME: remove this later. */ +/* we have a weird bug where XineramaQueryScreens() throws an X error, so this + is here to help track it down (and not crash, too!). */ +static SDL_bool xinerama_triggered_error = SDL_FALSE; +static int +X11_XineramaFailed(Display * d, XErrorEvent * e) +{ + xinerama_triggered_error = SDL_TRUE; + fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n", + e->type, e->serial, (unsigned int) e->error_code, + (unsigned int) e->request_code, (unsigned int) e->minor_code); + fflush(stderr); + return 0; +} #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ #if SDL_VIDEO_DRIVER_X11_XRANDR @@ -228,10 +244,12 @@ CheckXRandR(Display * display, int *major, int *minor) } /* Query the extension version */ + *major = 1; *minor = 3; /* we want 1.3 */ if (!X11_XRRQueryVersion(display, major, minor)) { #ifdef X11MODES_DEBUG printf("XRandR not active on the display\n"); #endif + *major = *minor = 0; return SDL_FALSE; } #ifdef X11MODES_DEBUG @@ -251,20 +269,20 @@ CalculateXRandRRefreshRate(const XRRModeInfo *info) } static SDL_bool -SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info, +SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc, RRMode modeID, SDL_DisplayMode *mode) { int i; for (i = 0; i < res->nmode; ++i) { - if (res->modes[i].id == modeID) { - XRRCrtcInfo *crtc; + const XRRModeInfo *info = &res->modes[i]; + if (info->id == modeID) { + XRRCrtcInfo *crtcinfo; Rotation rotation = 0; - const XRRModeInfo *info = &res->modes[i]; - crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc); - if (crtc) { - rotation = crtc->rotation; - X11_XRRFreeCrtcInfo(crtc); + crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc); + if (crtcinfo) { + rotation = crtcinfo->rotation; + X11_XRRFreeCrtcInfo(crtcinfo); } if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) { @@ -284,6 +302,203 @@ SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *outp } return SDL_FALSE; } + +static void +SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm) +{ + /* See if we can get the EDID data for the real monitor name */ + int inches; + int nprop; + Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop); + int i; + + for (i = 0; i < nprop; ++i) { + unsigned char *prop; + int actual_format; + unsigned long nitems, bytes_after; + Atom actual_type; + + if (props[i] == EDID) { + if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False, + False, AnyPropertyType, &actual_type, + &actual_format, &nitems, &bytes_after, + &prop) == Success) { + MonitorInfo *info = decode_edid(prop); + if (info) { +#ifdef X11MODES_DEBUG + printf("Found EDID data for %s\n", name); + dump_monitor_info(info); +#endif + SDL_strlcpy(name, info->dsc_product_name, namelen); + free(info); + } + X11_XFree(prop); + } + break; + } + } + + if (props) { + X11_XFree(props); + } + + inches = (int)((SDL_sqrt(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f); + if (*name && inches) { + const size_t len = SDL_strlen(name); + SDL_snprintf(&name[len], namelen-len, " %d\"", inches); + } + +#ifdef X11MODES_DEBUG + printf("Display name: %s\n", name); +#endif +} + + +int +X11_InitModes_XRandR(_THIS) +{ + /* In theory, you _could_ have multiple screens (like DISPLAY=:0.0 + and DISPLAY=:0.1) but no XRandR system we care about is like this, + as all the physical displays would be separate XRandR "outputs" on + the one X11 virtual "screen". So we don't use ScreenCount() here. */ + + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + Display *dpy = data->display; + Atom EDID = X11_XInternAtom(dpy, "EDID", False); + const int screen = DefaultScreen(dpy); + RROutput primary; + XRRScreenResources *res = NULL; + Uint32 pixelformat; + XVisualInfo vinfo; + XPixmapFormatValues *pixmapformats; + int looking_for_primary; + int scanline_pad; + int output; + int i, n; + + if (get_visualinfo(dpy, screen, &vinfo) < 0) { + return -1; + } + + pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo); + if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) { + return SDL_SetError("Palettized video modes are no longer supported"); + } + + scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8; + pixmapformats = X11_XListPixmapFormats(dpy, &n); + if (pixmapformats) { + for (i = 0; i < n; ++i) { + if (pixmapformats[i].depth == vinfo.depth) { + scanline_pad = pixmapformats[i].scanline_pad; + break; + } + } + X11_XFree(pixmapformats); + } + + res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen)); + if (!res) { + return -1; + } + + primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, screen)); + + for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) { + for (output = 0; output < res->noutput; output++) { + XRROutputInfo *output_info; + int display_x, display_y; + unsigned long display_mm_width, display_mm_height; + SDL_DisplayData *displaydata; + char display_name[128]; + SDL_DisplayMode mode; + SDL_DisplayModeData *modedata; + SDL_VideoDisplay display; + RRMode modeID; + RRCrtc output_crtc; + XRRCrtcInfo *crtc; + + /* The primary output _should_ always be sorted first, but just in case... */ + if ((looking_for_primary && (res->outputs[output] != primary)) || + (!looking_for_primary && (res->outputs[output] == primary))) { + continue; + } + + output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]); + if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) { + X11_XRRFreeOutputInfo(output_info); + continue; + } + + SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); + display_mm_width = output_info->mm_width; + display_mm_height = output_info->mm_height; + output_crtc = output_info->crtc; + X11_XRRFreeOutputInfo(output_info); + + crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc); + if (!crtc) { + continue; + } + + SDL_zero(mode); + modeID = crtc->mode; + mode.w = crtc->width; + mode.h = crtc->height; + mode.format = pixelformat; + + display_x = crtc->x; + display_y = crtc->y; + + X11_XRRFreeCrtcInfo(crtc); + + displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata)); + if (!displaydata) { + return SDL_OutOfMemory(); + } + + modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData)); + if (!modedata) { + SDL_free(displaydata); + return SDL_OutOfMemory(); + } + modedata->xrandr_mode = modeID; + mode.driverdata = modedata; + + displaydata->screen = screen; + displaydata->visual = vinfo.visual; + displaydata->depth = vinfo.depth; + displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width; + displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height; + displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f); + displaydata->scanline_pad = scanline_pad; + displaydata->x = display_x; + displaydata->y = display_y; + displaydata->use_xrandr = 1; + displaydata->xrandr_output = res->outputs[output]; + + SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode); + SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height); + + SDL_zero(display); + if (*display_name) { + display.name = display_name; + } + display.desktop_mode = mode; + display.current_mode = mode; + display.driverdata = displaydata; + SDL_AddVideoDisplay(&display); + } + } + + X11_XRRFreeScreenResources(res); + + if (_this->num_displays == 0) { + return SDL_SetError("No available displays"); + } + + return 0; +} #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #if SDL_VIDEO_DRIVER_X11_XVIDMODE @@ -383,21 +598,39 @@ X11_InitModes(_THIS) #endif #if SDL_VIDEO_DRIVER_X11_XRANDR int xrandr_major, xrandr_minor; - int use_xrandr = 0; - XRRScreenResources *res = NULL; #endif #if SDL_VIDEO_DRIVER_X11_XVIDMODE int vm_major, vm_minor; int use_vidmode = 0; #endif +/* XRandR is the One True Modern Way to do this on X11. If it's enabled and + available, don't even look at other ways of doing things. */ +#if SDL_VIDEO_DRIVER_X11_XRANDR + /* require at least XRandR v1.3 */ + if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) && + (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) { + return X11_InitModes_XRandR(_this); + } +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ + +/* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */ + #if SDL_VIDEO_DRIVER_X11_XINERAMA /* Query Xinerama extention * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012) * or newer of the Nvidia binary drivers */ if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) { + int (*handler) (Display *, XErrorEvent *); + X11_XSync(data->display, False); + handler = X11_XSetErrorHandler(X11_XineramaFailed); xinerama = X11_XineramaQueryScreens(data->display, &screencount); + X11_XSync(data->display, False); + X11_XSetErrorHandler(handler); + if (xinerama_triggered_error) { + xinerama = 0; + } if (xinerama) { use_xinerama = xinerama_major * 100 + xinerama_minor; } @@ -409,14 +642,6 @@ X11_InitModes(_THIS) screencount = ScreenCount(data->display); #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ -#if SDL_VIDEO_DRIVER_X11_XRANDR - /* require at least XRandR v1.2 */ - if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) && - (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) { - use_xrandr = xrandr_major * 100 + xrandr_minor; - } -#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ - #if SDL_VIDEO_DRIVER_X11_XVIDMODE if (CheckVidMode(data->display, &vm_major, &vm_minor)) { use_vidmode = vm_major * 100 + vm_minor; @@ -509,6 +734,18 @@ X11_InitModes(_THIS) displaydata->visual = vinfo.visual; displaydata->depth = vinfo.depth; + // We use the displaydata screen index here so that this works + // for both the Xinerama case, where we get the overall DPI, + // and the regular X11 screen info case. + displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f / + DisplayWidthMM(data->display, displaydata->screen); + displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f / + DisplayHeightMM(data->display, displaydata->screen); + displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen), + DisplayHeight(data->display, displaydata->screen), + (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f, + (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f); + displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8; pixmapFormats = X11_XListPixmapFormats(data->display, &n); if (pixmapFormats) { @@ -533,106 +770,6 @@ X11_InitModes(_THIS) displaydata->y = 0; } -#if SDL_VIDEO_DRIVER_X11_XRANDR - if (use_xrandr) { - res = X11_XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen)); - } - if (res) { - XRROutputInfo *output_info; - XRRCrtcInfo *crtc; - int output; - Atom EDID = X11_XInternAtom(data->display, "EDID", False); - Atom *props; - int nprop; - unsigned long width_mm; - unsigned long height_mm; - int inches = 0; - - for (output = 0; output < res->noutput; output++) { - output_info = X11_XRRGetOutputInfo(data->display, res, res->outputs[output]); - if (!output_info || !output_info->crtc || - output_info->connection == RR_Disconnected) { - X11_XRRFreeOutputInfo(output_info); - continue; - } - - /* Is this the output that corresponds to the current screen? - We're checking the crtc position, but that may not be a valid test - in all cases. Anybody want to give this some love? - */ - crtc = X11_XRRGetCrtcInfo(data->display, res, output_info->crtc); - if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y || - crtc->width != mode.w || crtc->height != mode.h) { - X11_XRRFreeOutputInfo(output_info); - X11_XRRFreeCrtcInfo(crtc); - continue; - } - - displaydata->use_xrandr = use_xrandr; - displaydata->xrandr_output = res->outputs[output]; - SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode); - - /* Get the name of this display */ - width_mm = output_info->mm_width; - height_mm = output_info->mm_height; - inches = (int)((sqrt(width_mm * width_mm + - height_mm * height_mm) / 25.4f) + 0.5f); - SDL_strlcpy(display_name, output_info->name, sizeof(display_name)); - - /* See if we can get the EDID data for the real monitor name */ - props = X11_XRRListOutputProperties(data->display, res->outputs[output], &nprop); - for (i = 0; i < nprop; ++i) { - unsigned char *prop; - int actual_format; - unsigned long nitems, bytes_after; - Atom actual_type; - - if (props[i] == EDID) { - if (X11_XRRGetOutputProperty(data->display, - res->outputs[output], props[i], - 0, 100, False, False, - AnyPropertyType, - &actual_type, &actual_format, - &nitems, &bytes_after, &prop) == Success ) { - MonitorInfo *info = decode_edid(prop); - if (info) { - #ifdef X11MODES_DEBUG - printf("Found EDID data for %s\n", output_info->name); - dump_monitor_info(info); - #endif - SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name)); - free(info); - } - X11_XFree(prop); - } - break; - } - } - if (props) { - X11_XFree(props); - } - - if (*display_name && inches) { - size_t len = SDL_strlen(display_name); - SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches); - } -#ifdef X11MODES_DEBUG - printf("Display name: %s\n", display_name); -#endif - - X11_XRRFreeOutputInfo(output_info); - X11_XRRFreeCrtcInfo(crtc); - break; - } -#ifdef X11MODES_DEBUG - if (output == res->noutput) { - printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y); - } -#endif - X11_XRRFreeScreenResources(res); - } -#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ - #if SDL_VIDEO_DRIVER_X11_XVIDMODE if (!displaydata->use_xrandr && #if SDL_VIDEO_DRIVER_X11_XINERAMA @@ -712,7 +849,9 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; } mode.driverdata = modedata; - SDL_AddDisplayMode(sdl_display, &mode); + if (!SDL_AddDisplayMode(sdl_display, &mode)) { + SDL_free(modedata); + } } else if (!data->use_xrandr) { @@ -726,7 +865,9 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; } mode.driverdata = modedata; - SDL_AddDisplayMode(sdl_display, &mode); + if (!SDL_AddDisplayMode(sdl_display, &mode)) { + SDL_free(modedata); + } } } @@ -751,9 +892,8 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) } mode.driverdata = modedata; - if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) { - SDL_AddDisplayMode(sdl_display, &mode); - } else { + if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) || + !SDL_AddDisplayMode(sdl_display, &mode)) { SDL_free(modedata); } } @@ -786,9 +926,7 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) } mode.driverdata = modedata; - if (SetXVidModeModeInfo(modes[i], &mode)) { - SDL_AddDisplayMode(sdl_display, &mode); - } else { + if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) { SDL_free(modedata); } } @@ -806,17 +944,22 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display) *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata; } mode.driverdata = modedata; - SDL_AddDisplayMode(sdl_display, &mode); + if (!SDL_AddDisplayMode(sdl_display, &mode)) { + SDL_free(modedata); + } } } 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; @@ -896,6 +1039,24 @@ X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) return 0; } +int +X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi) +{ + SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata; + + if (ddpi) { + *ddpi = data->ddpi; + } + if (hdpi) { + *hdpi = data->hdpi; + } + if (vdpi) { + *vdpi = data->vdpi; + } + + return data->ddpi != 0.0f ? 0 : -1; +} + #endif /* SDL_VIDEO_DRIVER_X11 */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11modes.h b/src/video/x11/SDL_x11modes.h index 82af1d2d8..769da5a56 100644 --- a/src/video/x11/SDL_x11modes.h +++ b/src/video/x11/SDL_x11modes.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -31,6 +31,9 @@ typedef struct int scanline_pad; int x; int y; + float ddpi; + float hdpi; + float vdpi; int use_xinerama; int use_xrandr; @@ -74,6 +77,7 @@ extern int X11_GetVisualInfoFromVisual(Display * display, Visual * visual, extern Uint32 X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo); extern int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect); +extern int X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi); #endif /* _SDL_x11modes_h */ diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 02d96da77..6cef0a4ea 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -318,13 +318,14 @@ X11_WarpMouse(SDL_Window * window, int x, int y) X11_XSync(display, False); } -static void +static int X11_WarpMouseGlobal(int x, int y) { Display *display = GetDisplay(); X11_XWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, x, y); X11_XSync(display, False); + return 0; } static int @@ -378,12 +379,18 @@ X11_GetGlobalMouseState(int *x, int *y) int rootx, rooty, winx, winy; unsigned int mask; if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) { + XWindowAttributes root_attrs; Uint32 retval = 0; retval |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0; retval |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0; retval |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0; - *x = data->x + rootx; - *y = data->y + rooty; + /* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing + * (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right). + * + * Adding root position to root-relative coordinates seems to be a better way to get absolute position. */ + X11_XGetWindowAttributes(display, root, &root_attrs); + *x = root_attrs.x + rootx; + *y = root_attrs.y + rooty; return retval; } } diff --git a/src/video/x11/SDL_x11mouse.h b/src/video/x11/SDL_x11mouse.h index 8a2dac0ea..7c6a54438 100644 --- a/src/video/x11/SDL_x11mouse.h +++ b/src/video/x11/SDL_x11mouse.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 1e94b041c..a431ae742 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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 && @@ -538,10 +529,11 @@ X11_GL_GetVisual(_THIS, Display * display, int screen) #define GLXBadProfileARB 13 #endif static int (*handler) (Display *, XErrorEvent *) = NULL; +static const char *errorHandlerOperation = NULL; static int errorBase = 0; static int errorCode = 0; static int -X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e) +X11_GL_ErrorHandler(Display * d, XErrorEvent * e) { char *x11_error = NULL; char x11_error_locale[256]; @@ -554,12 +546,12 @@ X11_GL_CreateContextErrorHandler(Display * d, XErrorEvent * e) if (x11_error) { - SDL_SetError("Could not create GL context: %s", x11_error); + SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error); SDL_free(x11_error); } else { - SDL_SetError("Could not create GL context: %i (Base %i)\n", errorCode, errorBase); + SDL_SetError("Could not %s: %i (Base %i)\n", errorHandlerOperation, errorCode, errorBase); } return (0); @@ -576,7 +568,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(); @@ -586,9 +577,10 @@ X11_GL_CreateContext(_THIS, SDL_Window * window) /* We do this to create a clean separation between X and GLX errors. */ X11_XSync(display, False); + errorHandlerOperation = "create GL context"; errorBase = _this->gl_data->errorBase; errorCode = Success; - handler = X11_XSetErrorHandler(X11_GL_CreateContextErrorHandler); + handler = X11_XSetErrorHandler(X11_GL_ErrorHandler); X11_XGetWindowAttributes(display, data->xwindow, &xattr); v.screen = screen; v.visualid = X11_XVisualIDFromVisual(xattr.visual); @@ -601,78 +593,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; - - /* 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; - } + /* 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 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; + } + + /* 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; + } - attribs[iattr++] = 0; + attribs[iattr++] = 0; - /* 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; + /* 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); - } } } } @@ -703,12 +678,24 @@ X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) Window drawable = (context ? ((SDL_WindowData *) window->driverdata)->xwindow : None); GLXContext glx_context = (GLXContext) context; + int rc; if (!_this->gl_data) { return SDL_SetError("OpenGL not initialized"); } - if (!_this->gl_data->glXMakeCurrent(display, drawable, glx_context)) { + /* We do this to create a clean separation between X and GLX errors. */ + X11_XSync(display, False); + errorHandlerOperation = "make GL context current"; + errorBase = _this->gl_data->errorBase; + errorCode = Success; + handler = X11_XSetErrorHandler(X11_GL_ErrorHandler); + rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context); + X11_XSetErrorHandler(handler); + + if (errorCode != Success) { /* uhoh, an X error was thrown! */ + return -1; /* the error handler called SDL_SetError() already. */ + } else if (!rc) { /* glxMakeCurrent() failed without throwing an X error */ return SDL_SetError("Unable to make GL context current"); } diff --git a/src/video/x11/SDL_x11opengl.h b/src/video/x11/SDL_x11opengl.h index ed7f292d4..de2297356 100644 --- a/src/video/x11/SDL_x11opengl.h +++ b/src/video/x11/SDL_x11opengl.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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_x11opengles.c b/src/video/x11/SDL_x11opengles.c index 5310420c8..ca57af387 100644 --- a/src/video/x11/SDL_x11opengles.c +++ b/src/video/x11/SDL_x11opengles.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11opengles.h b/src/video/x11/SDL_x11opengles.h index f6ea71eb7..e39e3c01c 100644 --- a/src/video/x11/SDL_x11opengles.h +++ b/src/video/x11/SDL_x11opengles.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11shape.c b/src/video/x11/SDL_x11shape.c index 515209464..19c7942d8 100644 --- a/src/video/x11/SDL_x11shape.c +++ b/src/video/x11/SDL_x11shape.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11shape.h b/src/video/x11/SDL_x11shape.h index 68118cfeb..0d3c2107b 100644 --- a/src/video/x11/SDL_x11shape.h +++ b/src/video/x11/SDL_x11shape.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 9678bac54..d9843f090 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -152,6 +152,7 @@ SDL_X11_SYM(unsigned long,_XSetLastRequestRead,(Display* a,xGenericReply* b),(a, SDL_X11_SYM(SDL_X11_XSynchronizeRetType,XSynchronize,(Display* a,Bool b),(a,b),return) SDL_X11_SYM(SDL_X11_XESetWireToEventRetType,XESetWireToEvent,(Display* a,int b,SDL_X11_XESetWireToEventRetType c),(a,b,c),return) SDL_X11_SYM(SDL_X11_XESetEventToWireRetType,XESetEventToWire,(Display* a,int b,SDL_X11_XESetEventToWireRetType c),(a,b,c),return) +SDL_X11_SYM(void,XRefreshKeyboardMapping,(XMappingEvent *a),(a),) #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return) @@ -203,11 +204,7 @@ SDL_X11_SYM(Bool,XShmQueryExtension,(Display* a),(a),return) */ #ifdef LONG64 SDL_X11_MODULE(IO_32BIT) -#if SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32 SDL_X11_SYM(int,_XData32,(Display *dpy,register _Xconst long *data,unsigned len),(dpy,data,len),return) -#else -SDL_X11_SYM(int,_XData32,(Display *dpy,register long *data,unsigned len),(dpy,data,len),return) -#endif SDL_X11_SYM(void,_XRead32,(Display *dpy,register long *data,long len),(dpy,data,len),) #endif @@ -230,6 +227,20 @@ SDL_X11_SYM(void,XcursorImageDestroy,(XcursorImage *a),(a),) SDL_X11_SYM(Cursor,XcursorImageLoadCursor,(Display *a,const XcursorImage *b),(a,b),return) #endif +/* Xdbe support */ +#if SDL_VIDEO_DRIVER_X11_XDBE +SDL_X11_MODULE(XDBE) +SDL_X11_SYM(Status,XdbeQueryExtension,(Display *dpy,int *major_version_return,int *minor_version_return),(dpy,major_version_return,minor_version_return),return) +SDL_X11_SYM(XdbeBackBuffer,XdbeAllocateBackBufferName,(Display *dpy,Window window,XdbeSwapAction swap_action),(dpy,window,swap_action),return) +SDL_X11_SYM(Status,XdbeDeallocateBackBufferName,(Display *dpy,XdbeBackBuffer buffer),(dpy,buffer),return) +SDL_X11_SYM(Status,XdbeSwapBuffers,(Display *dpy,XdbeSwapInfo *swap_info,int num_windows),(dpy,swap_info,num_windows),return) +SDL_X11_SYM(Status,XdbeBeginIdiom,(Display *dpy),(dpy),return) +SDL_X11_SYM(Status,XdbeEndIdiom,(Display *dpy),(dpy),return) +SDL_X11_SYM(XdbeScreenVisualInfo*,XdbeGetVisualInfo,(Display *dpy,Drawable *screen_specifiers,int *num_screens),(dpy,screen_specifiers,num_screens),return) +SDL_X11_SYM(void,XdbeFreeVisualInfo,(XdbeScreenVisualInfo *visual_info),(visual_info),) +SDL_X11_SYM(XdbeBackBufferAttributes*,XdbeGetBackBufferAttributes,(Display *dpy,XdbeBackBuffer buffer),(dpy,buffer),return) +#endif + /* Xinerama support */ #if SDL_VIDEO_DRIVER_X11_XINERAMA SDL_X11_MODULE(XINERAMA) @@ -272,6 +283,7 @@ SDL_X11_SYM(Status,XRRSetCrtcConfig,(Display *dpy, XRRScreenResources *resources SDL_X11_SYM(Atom*,XRRListOutputProperties,(Display *dpy, RROutput output, int *nprop),(dpy,output,nprop),return) SDL_X11_SYM(XRRPropertyInfo*,XRRQueryOutputProperty,(Display *dpy,RROutput output, Atom property),(dpy,output,property),return) SDL_X11_SYM(int,XRRGetOutputProperty,(Display *dpy,RROutput output, Atom property, long offset, long length, Bool _delete, Bool pending, Atom req_type, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytes_after, unsigned char **prop),(dpy,output,property,offset,length, _delete, pending, req_type, actual_type, actual_format, nitems, bytes_after, prop),return) +SDL_X11_SYM(RROutput,XRRGetOutputPrimary,(Display *dpy,Window window),(dpy,window),return) #endif /* MIT-SCREEN-SAVER support */ diff --git a/src/video/x11/SDL_x11touch.c b/src/video/x11/SDL_x11touch.c index a6da04633..2b24027aa 100644 --- a/src/video/x11/SDL_x11touch.c +++ b/src/video/x11/SDL_x11touch.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11touch.h b/src/video/x11/SDL_x11touch.h index 84de8d63d..47645e8ff 100644 --- a/src/video/x11/SDL_x11touch.h +++ b/src/video/x11/SDL_x11touch.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 4ede655e3..bc0eabdc9 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -216,6 +216,7 @@ X11_CreateDevice(int devindex) device->VideoQuit = X11_VideoQuit; device->GetDisplayModes = X11_GetDisplayModes; device->GetDisplayBounds = X11_GetDisplayBounds; + device->GetDisplayDPI = X11_GetDisplayDPI; device->SetDisplayMode = X11_SetDisplayMode; device->SuspendScreenSaver = X11_SuspendScreenSaver; device->PumpEvents = X11_PumpEvents; diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index f076ccec1..3fc273e2f 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -34,6 +34,9 @@ #if SDL_VIDEO_DRIVER_X11_XCURSOR #include #endif +#if SDL_VIDEO_DRIVER_X11_XDBE +#include +#endif #if SDL_VIDEO_DRIVER_X11_XINERAMA #include #endif @@ -112,6 +115,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..6db968ace 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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); - X11_XFree(titleprop.value); - } + 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, + if (SDL_X11_HAVE_UTF8) { + status = X11_Xutf8TextListToTextProperty(display, (char **) &title, 1, XUTF8StringStyle, &titleprop); - if (status == Success) { - X11_XSetTextProperty(display, data->xwindow, &titleprop, + if (status == Success) { + X11_XSetTextProperty(display, data->xwindow, &titleprop, _NET_WM_NAME); - X11_XFree(titleprop.value); - } + 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); } @@ -927,6 +899,12 @@ X11_ShowWindow(_THIS, SDL_Window * window) X11_XIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow); X11_XFlush(display); } + + if (!data->videodata->net_wm) { + /* no WM means no FocusIn event, which confuses us. Force it. */ + X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime); + X11_XFlush(display); + } } void diff --git a/src/video/x11/SDL_x11window.h b/src/video/x11/SDL_x11window.h index 789d2f7cc..a3424ff62 100644 --- a/src/video/x11/SDL_x11window.h +++ b/src/video/x11/SDL_x11window.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -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/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c index 7c149922f..c74e027ce 100644 --- a/src/video/x11/SDL_x11xinput2.c +++ b/src/video/x11/SDL_x11xinput2.c @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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 @@ -136,15 +136,25 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) case XI_RawMotion: { const XIRawEvent *rawev = (const XIRawEvent*)cookie->data; SDL_Mouse *mouse = SDL_GetMouse(); - double relative_cords[2]; + double relative_coords[2]; + static Time prev_time = 0; + static double prev_rel_coords[2]; if (!mouse->relative_mode || mouse->relative_mode_warp) { return 0; } parse_valuators(rawev->raw_values,rawev->valuators.mask, - rawev->valuators.mask_len,relative_cords,2); - SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_cords[0],(int)relative_cords[1]); + rawev->valuators.mask_len,relative_coords,2); + + if ((rawev->time == prev_time) && (relative_coords[0] == prev_rel_coords[0]) && (relative_coords[1] == prev_rel_coords[1])) { + return 0; /* duplicate event, drop it. */ + } + + SDL_SendMouseMotion(mouse->focus,mouse->mouseID,1,(int)relative_coords[0],(int)relative_coords[1]); + prev_rel_coords[0] = relative_coords[0]; + prev_rel_coords[1] = relative_coords[1]; + prev_time = rawev->time; return 1; } break; @@ -183,7 +193,7 @@ X11_InitXinput2Multitouch(_THIS) SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; XIDeviceInfo *info; int ndevices,i,j; - info = X11_XIQueryDevice(data->display, XIAllMasterDevices, &ndevices); + info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices); for (i = 0; i < ndevices; i++) { XIDeviceInfo *dev = &info[i]; @@ -197,9 +207,7 @@ X11_InitXinput2Multitouch(_THIS) continue; touchId = t->sourceid; - if (!SDL_GetTouch(touchId)) { - SDL_AddTouch(touchId, dev->name); - } + SDL_AddTouch(touchId, dev->name); } } X11_XIFreeDeviceInfo(info); diff --git a/src/video/x11/SDL_x11xinput2.h b/src/video/x11/SDL_x11xinput2.h index 3e7178cb9..06d3c9905 100644 --- a/src/video/x11/SDL_x11xinput2.h +++ b/src/video/x11/SDL_x11xinput2.h @@ -1,6 +1,6 @@ /* Simple DirectMedia Layer - Copyright (C) 1997-2014 Sam Lantinga + Copyright (C) 1997-2015 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