From 1e671bfc7a283640e34d3c2a327b229f107f10a1 Mon Sep 17 00:00:00 2001 From: Areloch Date: Tue, 8 Nov 2016 20:49:49 -0600 Subject: [PATCH] Updates SDL to 2.0.5 --- Engine/lib/sdl/include/SDL.h | 20 +- Engine/lib/sdl/include/SDL_audio.h | 95 +- Engine/lib/sdl/include/SDL_config.h.cmake | 2 + Engine/lib/sdl/include/SDL_config.h.in | 4 + Engine/lib/sdl/include/SDL_config_android.h | 3 + Engine/lib/sdl/include/SDL_config_iphoneos.h | 6 +- Engine/lib/sdl/include/SDL_events.h | 8 +- Engine/lib/sdl/include/SDL_gamecontroller.h | 6 +- Engine/lib/sdl/include/SDL_haptic.h | 32 +- Engine/lib/sdl/include/SDL_hints.h | 112 +- Engine/lib/sdl/include/SDL_joystick.h | 2 +- Engine/lib/sdl/include/SDL_keyboard.h | 2 +- Engine/lib/sdl/include/SDL_main.h | 2 +- Engine/lib/sdl/include/SDL_mouse.h | 6 +- Engine/lib/sdl/include/SDL_opengles.h | 1 + Engine/lib/sdl/include/SDL_opengles2.h | 2 + Engine/lib/sdl/include/SDL_pixels.h | 14 + Engine/lib/sdl/include/SDL_platform.h | 14 +- Engine/lib/sdl/include/SDL_render.h | 27 +- Engine/lib/sdl/include/SDL_revision.h | 4 +- Engine/lib/sdl/include/SDL_rwops.h | 12 +- Engine/lib/sdl/include/SDL_stdinc.h | 10 +- Engine/lib/sdl/include/SDL_surface.h | 10 + Engine/lib/sdl/include/SDL_syswm.h | 22 +- Engine/lib/sdl/include/SDL_version.h | 2 +- Engine/lib/sdl/include/SDL_video.h | 133 ++- Engine/lib/sdl/src/SDL.c | 22 +- Engine/lib/sdl/src/SDL_error.c | 7 + Engine/lib/sdl/src/SDL_hints.c | 13 + Engine/lib/sdl/src/SDL_log.c | 8 +- Engine/lib/sdl/src/audio/SDL_audio.c | 551 ++++++---- Engine/lib/sdl/src/audio/SDL_audio_c.h | 3 - Engine/lib/sdl/src/audio/SDL_mixer.c | 50 +- Engine/lib/sdl/src/audio/SDL_sysaudio.h | 24 +- Engine/lib/sdl/src/audio/SDL_wave.c | 2 +- .../lib/sdl/src/audio/alsa/SDL_alsa_audio.c | 452 +++++++-- .../sdl/src/audio/android/SDL_androidaudio.c | 109 +- .../sdl/src/audio/android/SDL_androidaudio.h | 2 - Engine/lib/sdl/src/audio/arts/SDL_artsaudio.c | 33 +- Engine/lib/sdl/src/audio/bsd/SDL_bsdaudio.c | 165 ++- .../sdl/src/audio/coreaudio/SDL_coreaudio.h | 16 +- .../sdl/src/audio/coreaudio/SDL_coreaudio.m | 849 ++++++++++++++++ .../src/audio/directsound/SDL_directsound.c | 284 ++++-- .../src/audio/directsound/SDL_directsound.h | 3 +- Engine/lib/sdl/src/audio/disk/SDL_diskaudio.c | 161 +-- Engine/lib/sdl/src/audio/disk/SDL_diskaudio.h | 5 +- Engine/lib/sdl/src/audio/dsp/SDL_dspaudio.c | 74 +- .../lib/sdl/src/audio/dummy/SDL_dummyaudio.c | 27 +- .../audio/emscripten/SDL_emscriptenaudio.c | 288 ++++-- Engine/lib/sdl/src/audio/esd/SDL_esdaudio.c | 22 +- .../sdl/src/audio/fusionsound/SDL_fsaudio.c | 39 +- .../lib/sdl/src/audio/haiku/SDL_haikuaudio.cc | 24 +- Engine/lib/sdl/src/audio/nacl/SDL_naclaudio.c | 37 +- Engine/lib/sdl/src/audio/nas/SDL_nasaudio.c | 166 ++- Engine/lib/sdl/src/audio/paudio/SDL_paudio.c | 24 +- Engine/lib/sdl/src/audio/psp/SDL_pspaudio.c | 63 +- .../sdl/src/audio/pulseaudio/SDL_pulseaudio.c | 203 ++-- .../sdl/src/audio/pulseaudio/SDL_pulseaudio.h | 3 + Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c | 92 +- Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.h | 2 +- .../lib/sdl/src/audio/sndio/SDL_sndioaudio.c | 31 +- Engine/lib/sdl/src/audio/sun/SDL_sunaudio.c | 21 +- Engine/lib/sdl/src/audio/winmm/SDL_winmm.c | 192 ++-- .../lib/sdl/src/audio/xaudio2/SDL_xaudio2.c | 84 +- Engine/lib/sdl/src/core/android/SDL_android.c | 330 ++++-- Engine/lib/sdl/src/core/android/SDL_android.h | 6 +- Engine/lib/sdl/src/core/linux/SDL_dbus.c | 2 +- Engine/lib/sdl/src/core/linux/SDL_evdev.c | 955 ++++++++++-------- Engine/lib/sdl/src/core/linux/SDL_evdev.h | 20 - Engine/lib/sdl/src/core/linux/SDL_fcitx.c | 553 ++++++++++ Engine/lib/sdl/src/core/linux/SDL_fcitx.h | 40 + Engine/lib/sdl/src/core/linux/SDL_ibus.c | 6 +- Engine/lib/sdl/src/core/linux/SDL_ime.c | 138 +++ Engine/lib/sdl/src/core/linux/SDL_ime.h | 38 + Engine/lib/sdl/src/core/linux/SDL_udev.c | 9 +- Engine/lib/sdl/src/core/linux/SDL_udev.h | 6 +- Engine/lib/sdl/src/core/windows/SDL_windows.c | 78 ++ Engine/lib/sdl/src/core/windows/SDL_windows.h | 3 + .../src/core/winrt/SDL_winrtapp_direct3d.cpp | 31 +- .../src/core/winrt/SDL_winrtapp_direct3d.h | 4 + Engine/lib/sdl/src/dynapi/SDL_dynapi.c | 2 +- Engine/lib/sdl/src/dynapi/SDL_dynapi.h | 10 +- .../lib/sdl/src/dynapi/SDL_dynapi_overrides.h | 15 + Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h | 13 + Engine/lib/sdl/src/events/SDL_dropevents.c | 68 +- Engine/lib/sdl/src/events/SDL_dropevents_c.h | 4 +- Engine/lib/sdl/src/events/SDL_events.c | 117 +-- Engine/lib/sdl/src/events/SDL_gesture.c | 2 +- Engine/lib/sdl/src/events/SDL_mouse.c | 70 +- Engine/lib/sdl/src/events/SDL_mouse_c.h | 3 + Engine/lib/sdl/src/events/SDL_quit.c | 4 +- Engine/lib/sdl/src/events/SDL_windowevents.c | 18 +- Engine/lib/sdl/src/events/scancodes_linux.h | 14 +- Engine/lib/sdl/src/events/scancodes_xfree86.h | 85 ++ .../src/filesystem/dummy/SDL_sysfilesystem.c | 4 +- .../src/filesystem/unix/SDL_sysfilesystem.c | 23 +- .../lib/sdl/src/haptic/linux/SDL_syshaptic.c | 4 +- .../sdl/src/haptic/windows/SDL_dinputhaptic.c | 19 +- .../src/haptic/windows/SDL_windowshaptic.c | 2 +- .../src/haptic/windows/SDL_windowshaptic_c.h | 4 +- .../sdl/src/haptic/windows/SDL_xinputhaptic.c | 19 +- .../lib/sdl/src/joystick/SDL_gamecontroller.c | 66 +- .../sdl/src/joystick/SDL_gamecontrollerdb.h | 14 + Engine/lib/sdl/src/joystick/SDL_joystick.c | 76 +- Engine/lib/sdl/src/joystick/SDL_joystick_c.h | 6 +- Engine/lib/sdl/src/joystick/SDL_sysjoystick.h | 1 + .../src/joystick/android/SDL_sysjoystick.c | 49 +- .../src/joystick/android/SDL_sysjoystick_c.h | 38 +- .../sdl/src/joystick/bsd/SDL_sysjoystick.c | 10 +- .../sdl/src/joystick/darwin/SDL_sysjoystick.c | 54 +- .../src/joystick/emscripten/SDL_sysjoystick.c | 41 +- .../joystick/emscripten/SDL_sysjoystick_c.h | 32 +- .../src/joystick/haiku/SDL_haikujoystick.cc | 4 +- .../src/joystick/iphoneos/SDL_sysjoystick.m | 132 ++- .../sdl/src/joystick/linux/SDL_sysjoystick.c | 37 +- .../sdl/src/joystick/psp/SDL_sysjoystick.c | 4 +- .../src/joystick/windows/SDL_dinputjoystick.c | 20 +- .../joystick/windows/SDL_windowsjoystick.c | 47 +- .../joystick/windows/SDL_windowsjoystick_c.h | 4 + .../src/joystick/windows/SDL_xinputjoystick.c | 10 +- .../lib/sdl/src/loadso/dlopen/SDL_sysloadso.c | 18 +- .../sdl/src/main/android/SDL_android_main.c | 11 +- Engine/lib/sdl/src/main/haiku/SDL_BApp.h | 14 +- Engine/lib/sdl/src/main/haiku/SDL_BeApp.cc | 6 +- .../sdl/src/main/windows/SDL_windows_main.c | 84 +- Engine/lib/sdl/src/main/windows/version.rc | 8 +- .../winrt/SDL2-WinRTResource_BlankCursor.cur | Bin 0 -> 326 bytes .../sdl/src/main/winrt/SDL2-WinRTResources.rc | 3 + Engine/lib/sdl/src/power/uikit/SDL_syspower.m | 17 +- Engine/lib/sdl/src/render/SDL_render.c | 72 +- Engine/lib/sdl/src/render/SDL_sysrender.h | 3 + .../sdl/src/render/direct3d/SDL_render_d3d.c | 16 +- .../src/render/direct3d11/SDL_render_d3d11.c | 157 +-- .../lib/sdl/src/render/opengl/SDL_render_gl.c | 72 +- .../sdl/src/render/opengles/SDL_render_gles.c | 178 ++-- .../src/render/opengles2/SDL_render_gles2.c | 58 +- .../lib/sdl/src/render/psp/SDL_render_psp.c | 10 +- .../sdl/src/render/software/SDL_render_sw.c | 4 +- .../lib/sdl/src/render/software/SDL_rotate.c | 167 ++- Engine/lib/sdl/src/stdlib/SDL_iconv.c | 3 +- Engine/lib/sdl/src/stdlib/SDL_qsort.c | 481 +++++---- Engine/lib/sdl/src/stdlib/SDL_stdlib.c | 14 +- Engine/lib/sdl/src/stdlib/SDL_string.c | 16 +- Engine/lib/sdl/src/test/SDL_test_assert.c | 14 +- Engine/lib/sdl/src/test/SDL_test_common.c | 24 + Engine/lib/sdl/src/test/SDL_test_compare.c | 2 +- Engine/lib/sdl/src/test/SDL_test_harness.c | 51 +- Engine/lib/sdl/src/test/SDL_test_log.c | 3 +- Engine/lib/sdl/src/thread/SDL_systhread.h | 5 + Engine/lib/sdl/src/thread/SDL_thread.c | 59 +- Engine/lib/sdl/src/thread/SDL_thread_c.h | 1 + Engine/lib/sdl/src/thread/psp/SDL_systhread.c | 4 +- .../sdl/src/thread/pthread/SDL_systhread.c | 23 +- .../sdl/src/thread/stdcpp/SDL_systhread.cpp | 1 + .../sdl/src/thread/windows/SDL_systhread.c | 66 +- Engine/lib/sdl/src/timer/SDL_timer.c | 59 +- .../lib/sdl/src/timer/windows/SDL_systimer.c | 10 +- Engine/lib/sdl/src/video/SDL_blit_copy.c | 18 +- Engine/lib/sdl/src/video/SDL_blit_slow.c | 5 +- Engine/lib/sdl/src/video/SDL_bmp.c | 68 +- Engine/lib/sdl/src/video/SDL_egl.c | 5 +- Engine/lib/sdl/src/video/SDL_surface.c | 65 +- Engine/lib/sdl/src/video/SDL_sysvideo.h | 13 + Engine/lib/sdl/src/video/SDL_video.c | 220 +++- .../sdl/src/video/android/SDL_androidevents.c | 14 +- .../src/video/android/SDL_androidkeyboard.c | 20 +- .../sdl/src/video/android/SDL_androidmouse.c | 18 +- .../sdl/src/video/android/SDL_androidmouse.h | 1 + .../sdl/src/video/android/SDL_androidtouch.c | 2 +- .../sdl/src/video/android/SDL_androidvideo.c | 29 +- .../sdl/src/video/cocoa/SDL_cocoaclipboard.m | 16 +- .../lib/sdl/src/video/cocoa/SDL_cocoaevents.m | 114 ++- .../sdl/src/video/cocoa/SDL_cocoakeyboard.m | 160 ++- .../lib/sdl/src/video/cocoa/SDL_cocoamodes.h | 4 +- .../lib/sdl/src/video/cocoa/SDL_cocoamodes.m | 222 ++-- .../lib/sdl/src/video/cocoa/SDL_cocoamouse.m | 30 +- .../sdl/src/video/cocoa/SDL_cocoamousetap.m | 15 +- .../lib/sdl/src/video/cocoa/SDL_cocoaopengl.m | 2 + .../lib/sdl/src/video/cocoa/SDL_cocoashape.m | 4 +- .../lib/sdl/src/video/cocoa/SDL_cocoavideo.m | 15 +- .../lib/sdl/src/video/cocoa/SDL_cocoawindow.h | 2 + .../lib/sdl/src/video/cocoa/SDL_cocoawindow.m | 186 ++-- .../src/video/directfb/SDL_DirectFB_video.c | 1 + .../src/video/directfb/SDL_DirectFB_window.c | 13 + .../src/video/directfb/SDL_DirectFB_window.h | 1 + .../video/emscripten/SDL_emscriptenevents.c | 238 +++-- .../video/emscripten/SDL_emscriptenevents.h | 3 + .../emscripten/SDL_emscriptenframebuffer.c | 76 +- .../video/emscripten/SDL_emscriptenmouse.c | 4 + .../video/emscripten/SDL_emscriptenvideo.c | 80 +- .../video/emscripten/SDL_emscriptenvideo.h | 8 +- Engine/lib/sdl/src/video/haiku/SDL_BWin.h | 40 +- Engine/lib/sdl/src/video/haiku/SDL_bvideo.cc | 1 + Engine/lib/sdl/src/video/haiku/SDL_bwindow.cc | 6 + Engine/lib/sdl/src/video/haiku/SDL_bwindow.h | 1 + Engine/lib/sdl/src/video/mir/SDL_mirdyn.c | 15 +- Engine/lib/sdl/src/video/mir/SDL_mirdyn.h | 6 +- Engine/lib/sdl/src/video/mir/SDL_mirevents.c | 249 +++-- Engine/lib/sdl/src/video/mir/SDL_mirevents.h | 2 +- .../sdl/src/video/mir/SDL_mirframebuffer.c | 37 +- Engine/lib/sdl/src/video/mir/SDL_mirmouse.c | 149 ++- Engine/lib/sdl/src/video/mir/SDL_mirsym.h | 117 ++- Engine/lib/sdl/src/video/mir/SDL_mirvideo.c | 229 +++-- Engine/lib/sdl/src/video/mir/SDL_mirvideo.h | 13 +- Engine/lib/sdl/src/video/mir/SDL_mirwindow.c | 254 ++++- Engine/lib/sdl/src/video/mir/SDL_mirwindow.h | 32 +- .../lib/sdl/src/video/pandora/SDL_pandora.c | 32 +- .../lib/sdl/src/video/pandora/SDL_pandora.h | 2 +- Engine/lib/sdl/src/video/psp/SDL_pspevents.c | 4 +- Engine/lib/sdl/src/video/psp/SDL_pspvideo.c | 5 +- .../sdl/src/video/raspberry/SDL_rpimouse.c | 146 ++- .../sdl/src/video/raspberry/SDL_rpivideo.c | 23 +- .../src/video/uikit/SDL_uikitappdelegate.h | 2 +- .../src/video/uikit/SDL_uikitappdelegate.m | 100 +- .../sdl/src/video/uikit/SDL_uikitclipboard.h | 35 + .../sdl/src/video/uikit/SDL_uikitclipboard.m | 111 ++ .../lib/sdl/src/video/uikit/SDL_uikitevents.m | 4 + .../lib/sdl/src/video/uikit/SDL_uikitmodes.h | 1 + .../lib/sdl/src/video/uikit/SDL_uikitmodes.m | 49 +- .../sdl/src/video/uikit/SDL_uikitopengles.h | 2 + .../sdl/src/video/uikit/SDL_uikitopengles.m | 29 +- .../sdl/src/video/uikit/SDL_uikitopenglview.m | 2 +- .../lib/sdl/src/video/uikit/SDL_uikitvideo.h | 17 +- .../lib/sdl/src/video/uikit/SDL_uikitvideo.m | 122 ++- .../lib/sdl/src/video/uikit/SDL_uikitview.m | 71 +- .../src/video/uikit/SDL_uikitviewcontroller.h | 49 +- .../src/video/uikit/SDL_uikitviewcontroller.m | 36 + .../lib/sdl/src/video/uikit/SDL_uikitwindow.m | 14 +- .../sdl/src/video/vivante/SDL_vivantevideo.c | 8 +- .../sdl/src/video/wayland/SDL_waylanddyn.c | 17 - .../sdl/src/video/wayland/SDL_waylanddyn.h | 9 +- .../sdl/src/video/wayland/SDL_waylandevents.c | 201 +++- .../src/video/wayland/SDL_waylandevents_c.h | 9 + .../sdl/src/video/wayland/SDL_waylandmouse.c | 35 +- .../sdl/src/video/wayland/SDL_waylandsym.h | 19 +- .../sdl/src/video/wayland/SDL_waylandvideo.c | 79 +- .../sdl/src/video/wayland/SDL_waylandvideo.h | 7 +- .../sdl/src/video/wayland/SDL_waylandwindow.c | 64 ++ .../sdl/src/video/wayland/SDL_waylandwindow.h | 4 + .../sdl/src/video/windows/SDL_windowsevents.c | 125 ++- .../src/video/windows/SDL_windowskeyboard.c | 46 +- .../src/video/windows/SDL_windowskeyboard.h | 2 + .../src/video/windows/SDL_windowsmessagebox.c | 6 +- .../sdl/src/video/windows/SDL_windowsmodes.c | 123 ++- .../sdl/src/video/windows/SDL_windowsmodes.h | 1 + .../sdl/src/video/windows/SDL_windowsvideo.c | 3 + .../sdl/src/video/windows/SDL_windowswindow.c | 52 +- .../sdl/src/video/windows/SDL_windowswindow.h | 4 +- .../sdl/src/video/winrt/SDL_winrtevents.cpp | 3 +- .../sdl/src/video/winrt/SDL_winrtevents_c.h | 7 + .../sdl/src/video/winrt/SDL_winrtgamebar.cpp | 196 ++++ .../src/video/winrt/SDL_winrtgamebar_cpp.h | 35 + .../sdl/src/video/winrt/SDL_winrtkeyboard.cpp | 44 + .../sdl/src/video/winrt/SDL_winrtmouse.cpp | 63 +- .../sdl/src/video/winrt/SDL_winrtvideo.cpp | 98 +- .../sdl/src/video/winrt/SDL_winrtvideo_cpp.h | 11 + Engine/lib/sdl/src/video/x11/SDL_x11dyn.c | 15 - Engine/lib/sdl/src/video/x11/SDL_x11dyn.h | 6 - Engine/lib/sdl/src/video/x11/SDL_x11events.c | 215 ++-- .../lib/sdl/src/video/x11/SDL_x11keyboard.c | 154 ++- .../lib/sdl/src/video/x11/SDL_x11keyboard.h | 1 + Engine/lib/sdl/src/video/x11/SDL_x11modes.c | 74 +- Engine/lib/sdl/src/video/x11/SDL_x11modes.h | 1 + Engine/lib/sdl/src/video/x11/SDL_x11mouse.c | 57 +- Engine/lib/sdl/src/video/x11/SDL_x11opengl.c | 12 +- Engine/lib/sdl/src/video/x11/SDL_x11sym.h | 18 + Engine/lib/sdl/src/video/x11/SDL_x11video.c | 79 +- Engine/lib/sdl/src/video/x11/SDL_x11video.h | 18 +- Engine/lib/sdl/src/video/x11/SDL_x11window.c | 198 +++- Engine/lib/sdl/src/video/x11/SDL_x11window.h | 11 + Engine/lib/sdl/src/video/x11/SDL_x11xinput2.c | 10 + Engine/lib/sdl/src/video/x11/edid-parse.c | 4 +- Engine/lib/sdl/src/video/x11/imKStoUCS.c | 496 ++++----- Engine/lib/sdl/src/video/x11/imKStoUCS.h | 39 +- 274 files changed, 11502 insertions(+), 4656 deletions(-) create mode 100644 Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m create mode 100644 Engine/lib/sdl/src/core/linux/SDL_fcitx.c create mode 100644 Engine/lib/sdl/src/core/linux/SDL_fcitx.h create mode 100644 Engine/lib/sdl/src/core/linux/SDL_ime.c create mode 100644 Engine/lib/sdl/src/core/linux/SDL_ime.h create mode 100644 Engine/lib/sdl/src/main/winrt/SDL2-WinRTResource_BlankCursor.cur create mode 100644 Engine/lib/sdl/src/main/winrt/SDL2-WinRTResources.rc create mode 100644 Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.h create mode 100644 Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.m create mode 100644 Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar.cpp create mode 100644 Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar_cpp.h diff --git a/Engine/lib/sdl/include/SDL.h b/Engine/lib/sdl/include/SDL.h index 7647b5111..1a3fa285c 100644 --- a/Engine/lib/sdl/include/SDL.h +++ b/Engine/lib/sdl/include/SDL.h @@ -72,14 +72,14 @@ extern "C" { * specify the subsystems which you will be using in your application. */ /* @{ */ -#define SDL_INIT_TIMER 0x00000001 -#define SDL_INIT_AUDIO 0x00000010 -#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ -#define SDL_INIT_JOYSTICK 0x00000200 /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */ -#define SDL_INIT_HAPTIC 0x00001000 -#define SDL_INIT_GAMECONTROLLER 0x00002000 /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */ -#define SDL_INIT_EVENTS 0x00004000 -#define SDL_INIT_NOPARACHUTE 0x00100000 /**< compatibility; this flag is ignored. */ +#define SDL_INIT_TIMER 0x00000001u +#define SDL_INIT_AUDIO 0x00000010u +#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ +#define SDL_INIT_JOYSTICK 0x00000200u /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */ +#define SDL_INIT_HAPTIC 0x00001000u +#define SDL_INIT_GAMECONTROLLER 0x00002000u /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */ +#define SDL_INIT_EVENTS 0x00004000u +#define SDL_INIT_NOPARACHUTE 0x00100000u /**< compatibility; this flag is ignored. */ #define SDL_INIT_EVERYTHING ( \ SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \ SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \ @@ -95,8 +95,8 @@ extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags); * This function initializes specific SDL subsystems * * Subsystem initialization is ref-counted, you must call - * SDL_QuitSubSystem for each SDL_InitSubSystem to correctly - * shutdown a subsystem manually (or call SDL_Quit to force shutdown). + * SDL_QuitSubSystem() for each SDL_InitSubSystem() to correctly + * shutdown a subsystem manually (or call SDL_Quit() to force shutdown). * If a subsystem is already loaded then this call will * increase the ref-count and return. */ diff --git a/Engine/lib/sdl/include/SDL_audio.h b/Engine/lib/sdl/include/SDL_audio.h index 4f6552146..d51f0d1ce 100644 --- a/Engine/lib/sdl/include/SDL_audio.h +++ b/Engine/lib/sdl/include/SDL_audio.h @@ -278,7 +278,8 @@ extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void); * protect data structures that it accesses by calling SDL_LockAudio() * and SDL_UnlockAudio() in your code. Alternately, you may pass a NULL * pointer here, and call SDL_QueueAudio() with some frequency, to queue - * more audio samples to be played. + * more audio samples to be played (or for capture devices, call + * SDL_DequeueAudio() with some frequency, to obtain audio samples). * - \c desired->userdata is passed as the first parameter to your callback * function. If you passed a NULL callback, this value is ignored. * @@ -482,6 +483,10 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst, /** * Queue more audio on non-callback devices. * + * (If you are looking to retrieve queued audio from a non-callback capture + * device, you want SDL_DequeueAudio() instead. This will return -1 to + * signify an error if you use it with capture devices.) + * * SDL offers two ways to feed audio to the device: you can either supply a * callback that SDL triggers with some frequency to obtain more audio * (pull method), or you can supply no callback, and then SDL will expect @@ -516,21 +521,76 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst, */ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len); +/** + * Dequeue more audio on non-callback devices. + * + * (If you are looking to queue audio for output on a non-callback playback + * device, you want SDL_QueueAudio() instead. This will always return 0 + * if you use it with playback devices.) + * + * SDL offers two ways to retrieve audio from a capture device: you can + * either supply a callback that SDL triggers with some frequency as the + * device records more audio data, (push method), or you can supply no + * callback, and then SDL will expect you to retrieve data at regular + * intervals (pull method) with this function. + * + * There are no limits on the amount of data you can queue, short of + * exhaustion of address space. Data from the device will keep queuing as + * necessary without further intervention from you. This means you will + * eventually run out of memory if you aren't routinely dequeueing data. + * + * Capture devices will not queue data when paused; if you are expecting + * to not need captured audio for some length of time, use + * SDL_PauseAudioDevice() to stop the capture device from queueing more + * data. This can be useful during, say, level loading times. When + * unpaused, capture devices will start queueing data from that point, + * having flushed any capturable data available while paused. + * + * This function is thread-safe, but dequeueing from the same device from + * two threads at once does not promise which thread will dequeued data + * first. + * + * You may not dequeue audio from a device that is using an + * application-supplied callback; doing so returns an error. You have to use + * the audio callback, or dequeue audio with this function, but not both. + * + * You should not call SDL_LockAudio() on the device before queueing; SDL + * handles locking internally for this function. + * + * \param dev The device ID from which we will dequeue audio. + * \param data A pointer into where audio data should be copied. + * \param len The number of bytes (not samples!) to which (data) points. + * \return number of bytes dequeued, which could be less than requested. + * + * \sa SDL_GetQueuedAudioSize + * \sa SDL_ClearQueuedAudio + */ +extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 len); + /** * Get the number of bytes of still-queued audio. * - * This is the number of bytes that have been queued for playback with - * SDL_QueueAudio(), but have not yet been sent to the hardware. + * For playback device: * - * Once we've sent it to the hardware, this function can not decide the exact - * byte boundary of what has been played. It's possible that we just gave the - * hardware several kilobytes right before you called this function, but it - * hasn't played any of it yet, or maybe half of it, etc. + * This is the number of bytes that have been queued for playback with + * SDL_QueueAudio(), but have not yet been sent to the hardware. This + * number may shrink at any time, so this only informs of pending data. + * + * Once we've sent it to the hardware, this function can not decide the + * exact byte boundary of what has been played. It's possible that we just + * gave the hardware several kilobytes right before you called this + * function, but it hasn't played any of it yet, or maybe half of it, etc. + * + * For capture devices: + * + * This is the number of bytes that have been captured by the device and + * are waiting for you to dequeue. This number may grow at any time, so + * this only informs of the lower-bound of available data. * * You may not queue audio on a device that is using an application-supplied * callback; calling this function on such a device always returns 0. - * You have to use the audio callback or queue audio with SDL_QueueAudio(), - * but not both. + * You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use + * the audio callback, but not both. * * You should not call SDL_LockAudio() on the device before querying; SDL * handles locking internally for this function. @@ -544,10 +604,17 @@ extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *da extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev); /** - * Drop any queued audio data waiting to be sent to the hardware. + * Drop any queued audio data. For playback devices, this is any queued data + * still waiting to be submitted to the hardware. For capture devices, this + * is any data that was queued by the device that hasn't yet been dequeued by + * the application. * - * Immediately after this call, SDL_GetQueuedAudioSize() will return 0 and - * the hardware will start playing silence if more audio isn't queued. + * Immediately after this call, SDL_GetQueuedAudioSize() will return 0. For + * playback devices, the hardware will start playing silence if more audio + * isn't queued. Unpaused capture devices will start filling the queue again + * as soon as they have more data available (which, depending on the state + * of the hardware and the thread, could be before this function call + * returns!). * * This will not prevent playback of queued audio that's already been sent * to the hardware, as we can not undo that, so expect there to be some @@ -557,8 +624,8 @@ extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev); * * You may not queue audio on a device that is using an application-supplied * callback; calling this function on such a device is always a no-op. - * You have to use the audio callback or queue audio with SDL_QueueAudio(), - * but not both. + * You have to queue audio with SDL_QueueAudio()/SDL_DequeueAudio(), or use + * the audio callback, but not both. * * You should not call SDL_LockAudio() on the device before clearing the * queue; SDL handles locking internally for this function. diff --git a/Engine/lib/sdl/include/SDL_config.h.cmake b/Engine/lib/sdl/include/SDL_config.h.cmake index 44173a053..98c62a994 100644 --- a/Engine/lib/sdl/include/SDL_config.h.cmake +++ b/Engine/lib/sdl/include/SDL_config.h.cmake @@ -81,6 +81,8 @@ #cmakedefine HAVE_PTHREAD_NP_H 1 #cmakedefine HAVE_LIBUDEV_H 1 #cmakedefine HAVE_DBUS_DBUS_H 1 +#cmakedefine HAVE_IBUS_IBUS_H 1 +#cmakedefine HAVE_FCITX_FRONTEND_H 1 /* C library functions */ #cmakedefine HAVE_MALLOC 1 diff --git a/Engine/lib/sdl/include/SDL_config.h.in b/Engine/lib/sdl/include/SDL_config.h.in index 2071be4e5..d610cd6ba 100644 --- a/Engine/lib/sdl/include/SDL_config.h.in +++ b/Engine/lib/sdl/include/SDL_config.h.in @@ -82,6 +82,7 @@ #undef HAVE_LIBUDEV_H #undef HAVE_DBUS_DBUS_H #undef HAVE_IBUS_IBUS_H +#undef HAVE_FCITX_FRONTEND_H /* C library functions */ #undef HAVE_MALLOC @@ -356,4 +357,7 @@ #undef SDL_ASSEMBLY_ROUTINES #undef SDL_ALTIVEC_BLITTERS +/* Enable ime support */ +#undef SDL_USE_IME + #endif /* _SDL_config_h */ diff --git a/Engine/lib/sdl/include/SDL_config_android.h b/Engine/lib/sdl/include/SDL_config_android.h index a388ba8de..996cf76c9 100644 --- a/Engine/lib/sdl/include/SDL_config_android.h +++ b/Engine/lib/sdl/include/SDL_config_android.h @@ -43,6 +43,7 @@ #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 @@ -75,6 +76,7 @@ #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 @@ -101,6 +103,7 @@ #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 diff --git a/Engine/lib/sdl/include/SDL_config_iphoneos.h b/Engine/lib/sdl/include/SDL_config_iphoneos.h index 304c89201..470985f80 100644 --- a/Engine/lib/sdl/include/SDL_config_iphoneos.h +++ b/Engine/lib/sdl/include/SDL_config_iphoneos.h @@ -119,11 +119,7 @@ #define SDL_JOYSTICK_MFI 1 /* Enable Unix style SO loading */ -/* Technically this works, but violates the iOS dev agreement prior to iOS 8 */ -/* #define SDL_LOADSO_DLOPEN 1 */ - -/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */ -#define SDL_LOADSO_DISABLED 1 +#define SDL_LOADSO_DLOPEN 1 /* Enable various threading systems */ #define SDL_THREAD_PTHREAD 1 diff --git a/Engine/lib/sdl/include/SDL_events.h b/Engine/lib/sdl/include/SDL_events.h index 1437f4c70..edb89ef49 100644 --- a/Engine/lib/sdl/include/SDL_events.h +++ b/Engine/lib/sdl/include/SDL_events.h @@ -136,6 +136,9 @@ typedef enum /* Drag and drop events */ SDL_DROPFILE = 0x1000, /**< The system requests a file open */ + SDL_DROPTEXT, /**< text/plain drag-and-drop event */ + SDL_DROPBEGIN, /**< A new set of drops is beginning (NULL filename) */ + SDL_DROPCOMPLETE, /**< Current set of drops is now complete (NULL filename) */ /* Audio hotplug events */ SDL_AUDIODEVICEADDED = 0x1100, /**< A new audio device is available */ @@ -461,9 +464,10 @@ typedef struct SDL_DollarGestureEvent */ typedef struct SDL_DropEvent { - Uint32 type; /**< ::SDL_DROPFILE */ + Uint32 type; /**< ::SDL_DROPBEGIN or ::SDL_DROPFILE or ::SDL_DROPTEXT or ::SDL_DROPCOMPLETE */ Uint32 timestamp; - char *file; /**< The file name, which should be freed with SDL_free() */ + char *file; /**< The file name, which should be freed with SDL_free(), is NULL on begin/complete */ + Uint32 windowID; /**< The window that was dropped on, if any */ } SDL_DropEvent; diff --git a/Engine/lib/sdl/include/SDL_gamecontroller.h b/Engine/lib/sdl/include/SDL_gamecontroller.h index 42087eea1..e67fd9fd0 100644 --- a/Engine/lib/sdl/include/SDL_gamecontroller.h +++ b/Engine/lib/sdl/include/SDL_gamecontroller.h @@ -93,7 +93,7 @@ typedef struct SDL_GameControllerButtonBind * } * } * - * Using the SDL_HINT_GAMECONTROLLERCONFIG hint or the SDL_GameControllerAddMapping you can add support for controllers SDL is unaware of or cause an existing controller to have a different binding. The format is: + * Using the SDL_HINT_GAMECONTROLLERCONFIG hint or the SDL_GameControllerAddMapping() you can add support for controllers SDL is unaware of or cause an existing controller to have a different binding. The format is: * guid,name,mappings * * Where GUID is the string value from SDL_JoystickGetGUIDString(), name is the human readable string for the device and mappings are controller mappings to joystick ones. @@ -136,14 +136,14 @@ extern DECLSPEC int SDLCALL SDL_GameControllerAddMapping( const char* mappingStr /** * Get a mapping string for a GUID * - * \return the mapping string. Must be freed with SDL_free. Returns NULL if no mapping is available + * \return the mapping string. Must be freed with SDL_free(). Returns NULL if no mapping is available */ extern DECLSPEC char * SDLCALL SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid ); /** * Get a mapping string for an open GameController * - * \return the mapping string. Must be freed with SDL_free. Returns NULL if no mapping is available + * \return the mapping string. Must be freed with SDL_free(). Returns NULL if no mapping is available */ extern DECLSPEC char * SDLCALL SDL_GameControllerMapping( SDL_GameController * gamecontroller ); diff --git a/Engine/lib/sdl/include/SDL_haptic.h b/Engine/lib/sdl/include/SDL_haptic.h index b36d78b12..9421c8f17 100644 --- a/Engine/lib/sdl/include/SDL_haptic.h +++ b/Engine/lib/sdl/include/SDL_haptic.h @@ -149,7 +149,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticCondition */ -#define SDL_HAPTIC_CONSTANT (1<<0) +#define SDL_HAPTIC_CONSTANT (1u<<0) /** * \brief Sine wave effect supported. @@ -158,7 +158,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticPeriodic */ -#define SDL_HAPTIC_SINE (1<<1) +#define SDL_HAPTIC_SINE (1u<<1) /** * \brief Left/Right effect supported. @@ -169,7 +169,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * \warning this value was SDL_HAPTIC_SQUARE right before 2.0.0 shipped. Sorry, * we ran out of bits, and this is important for XInput devices. */ -#define SDL_HAPTIC_LEFTRIGHT (1<<2) +#define SDL_HAPTIC_LEFTRIGHT (1u<<2) /* !!! FIXME: put this back when we have more bits in 2.1 */ /* #define SDL_HAPTIC_SQUARE (1<<2) */ @@ -181,7 +181,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticPeriodic */ -#define SDL_HAPTIC_TRIANGLE (1<<3) +#define SDL_HAPTIC_TRIANGLE (1u<<3) /** * \brief Sawtoothup wave effect supported. @@ -190,7 +190,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticPeriodic */ -#define SDL_HAPTIC_SAWTOOTHUP (1<<4) +#define SDL_HAPTIC_SAWTOOTHUP (1u<<4) /** * \brief Sawtoothdown wave effect supported. @@ -199,7 +199,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticPeriodic */ -#define SDL_HAPTIC_SAWTOOTHDOWN (1<<5) +#define SDL_HAPTIC_SAWTOOTHDOWN (1u<<5) /** * \brief Ramp effect supported. @@ -208,7 +208,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticRamp */ -#define SDL_HAPTIC_RAMP (1<<6) +#define SDL_HAPTIC_RAMP (1u<<6) /** * \brief Spring effect supported - uses axes position. @@ -218,7 +218,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticCondition */ -#define SDL_HAPTIC_SPRING (1<<7) +#define SDL_HAPTIC_SPRING (1u<<7) /** * \brief Damper effect supported - uses axes velocity. @@ -228,7 +228,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticCondition */ -#define SDL_HAPTIC_DAMPER (1<<8) +#define SDL_HAPTIC_DAMPER (1u<<8) /** * \brief Inertia effect supported - uses axes acceleration. @@ -238,7 +238,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticCondition */ -#define SDL_HAPTIC_INERTIA (1<<9) +#define SDL_HAPTIC_INERTIA (1u<<9) /** * \brief Friction effect supported - uses axes movement. @@ -248,14 +248,14 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticCondition */ -#define SDL_HAPTIC_FRICTION (1<<10) +#define SDL_HAPTIC_FRICTION (1u<<10) /** * \brief Custom effect is supported. * * User defined custom haptic effect. */ -#define SDL_HAPTIC_CUSTOM (1<<11) +#define SDL_HAPTIC_CUSTOM (1u<<11) /* @} *//* Haptic effects */ @@ -268,7 +268,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticSetGain */ -#define SDL_HAPTIC_GAIN (1<<12) +#define SDL_HAPTIC_GAIN (1u<<12) /** * \brief Device can set autocenter. @@ -277,7 +277,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticSetAutocenter */ -#define SDL_HAPTIC_AUTOCENTER (1<<13) +#define SDL_HAPTIC_AUTOCENTER (1u<<13) /** * \brief Device can be queried for effect status. @@ -286,7 +286,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * * \sa SDL_HapticGetEffectStatus */ -#define SDL_HAPTIC_STATUS (1<<14) +#define SDL_HAPTIC_STATUS (1u<<14) /** * \brief Device can be paused. @@ -294,7 +294,7 @@ typedef struct _SDL_Haptic SDL_Haptic; * \sa SDL_HapticPause * \sa SDL_HapticUnpause */ -#define SDL_HAPTIC_PAUSE (1<<15) +#define SDL_HAPTIC_PAUSE (1u<<15) /** diff --git a/Engine/lib/sdl/include/SDL_hints.h b/Engine/lib/sdl/include/SDL_hints.h index 3bd5435fb..dd1546431 100644 --- a/Engine/lib/sdl/include/SDL_hints.h +++ b/Engine/lib/sdl/include/SDL_hints.h @@ -233,16 +233,27 @@ extern "C" { #define SDL_HINT_GRAB_KEYBOARD "SDL_GRAB_KEYBOARD" /** -* \brief A variable controlling whether relative mouse mode is implemented using mouse warping -* -* This variable can be set to the following values: -* "0" - Relative mouse mode uses raw input -* "1" - Relative mouse mode uses mouse warping -* -* By default SDL will use raw input for relative mouse mode -*/ + * \brief A variable controlling whether relative mouse mode is implemented using mouse warping + * + * This variable can be set to the following values: + * "0" - Relative mouse mode uses raw input + * "1" - Relative mouse mode uses mouse warping + * + * By default SDL will use raw input for relative mouse mode + */ #define SDL_HINT_MOUSE_RELATIVE_MODE_WARP "SDL_MOUSE_RELATIVE_MODE_WARP" +/** + * \brief Allow mouse click events when clicking to focus an SDL window + * + * This variable can be set to the following values: + * "0" - Ignore mouse clicks that activate a window + * "1" - Generate events for mouse clicks that activate a window + * + * By default SDL will ignore mouse clicks that activate a window + */ +#define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH "SDL_MOUSE_FOCUS_CLICKTHROUGH" + /** * \brief Minimize your SDL_Window if it loses key focus when in fullscreen mode. Defaults to true. * @@ -257,8 +268,8 @@ 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. + * 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 @@ -276,7 +287,35 @@ extern "C" { * "LandscapeLeft", "LandscapeRight", "Portrait" "PortraitUpsideDown" */ #define SDL_HINT_ORIENTATIONS "SDL_IOS_ORIENTATIONS" - + +/** + * \brief A variable controlling whether controllers used with the Apple TV + * generate UI events. + * + * When UI events are generated by controller input, the app will be + * backgrounded when the Apple TV remote's menu button is pressed, and when the + * pause or B buttons on gamepads are pressed. + * + * More information about properly making use of controllers for the Apple TV + * can be found here: + * https://developer.apple.com/tvos/human-interface-guidelines/remote-and-controllers/ + * + * This variable can be set to the following values: + * "0" - Controller input does not generate UI events (the default). + * "1" - Controller input generates UI events. + */ +#define SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS "SDL_APPLE_TV_CONTROLLER_UI_EVENTS" + +/** + * \brief A variable controlling whether the Apple TV remote's joystick axes + * will automatically match the rotation of the remote. + * + * This variable can be set to the following values: + * "0" - Remote orientation does not affect joystick axes (the default). + * "1" - Joystick axes are based on the orientation of the remote. + */ +#define SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION" + /** * \brief A variable controlling whether the Android / iOS built-in * accelerometer should be listed as a joystick device, rather than listing @@ -369,7 +408,7 @@ extern "C" { * 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. +* Support for this hint is currently available only in the pthread, Windows, and PSP backend. */ #define SDL_HINT_THREAD_STACK_SIZE "SDL_THREAD_STACK_SIZE" @@ -431,7 +470,7 @@ extern "C" { * privacy policy. * * To setup a URL to an app's privacy policy, set SDL_HINT_WINRT_PRIVACY_POLICY_URL - * before calling any SDL_Init functions. The contents of the hint should + * before calling any SDL_Init() functions. The contents of the hint should * be a valid URL. For example, "http://www.example.com". * * The default value is "", which will prevent SDL from adding a privacy policy @@ -461,7 +500,7 @@ extern "C" { * The contents of this hint should be encoded as a UTF8 string. * * The default value is "Privacy Policy". This hint should only be set during app - * initialization, preferably before any calls to SDL_Init. + * initialization, preferably before any calls to SDL_Init(). * * For additional information on linking to a privacy policy, see the documentation for * SDL_HINT_WINRT_PRIVACY_POLICY_URL. @@ -630,6 +669,44 @@ extern "C" { */ #define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4" +/** + * \brief Prevent SDL from using version 4 of the bitmap header when saving BMPs. + * + * The bitmap header version 4 is required for proper alpha channel support and + * SDL will use it when required. Should this not be desired, this hint can + * force the use of the 40 byte header version which is supported everywhere. + * + * The variable can be set to the following values: + * "0" - Surfaces with a colorkey or an alpha channel are saved to a + * 32-bit BMP file with an alpha mask. SDL will use the bitmap + * header version 4 and set the alpha mask accordingly. + * "1" - Surfaces with a colorkey or an alpha channel are saved to a + * 32-bit BMP file without an alpha mask. The alpha channel data + * will be in the file, but applications are going to ignore it. + * + * The default value is "0". + */ +#define SDL_HINT_BMP_SAVE_LEGACY_FORMAT "SDL_BMP_SAVE_LEGACY_FORMAT" + +/** + * \brief Tell SDL not to name threads on Windows. + * + * The variable can be set to the following values: + * "0" - SDL will raise the 0x406D1388 Exception to name threads. + * This is the default behavior of SDL <= 2.0.4. (default) + * "1" - SDL will not raise this exception, and threads will be unnamed. + * For .NET languages this is required when running under a debugger. + */ +#define SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING "SDL_WINDOWS_DISABLE_THREAD_NAMING" + +/** + * \brief Tell SDL which Dispmanx layer to use on a Raspberry PI + * + * Also known as Z-order. The variable can take a negative or positive value. + * The default is 10000. + */ +#define SDL_HINT_RPI_VIDEO_LAYER "SDL_RPI_VIDEO_LAYER" + /** * \brief An enumeration of hint priorities */ @@ -669,6 +746,13 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SetHint(const char *name, */ extern DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); +/** + * \brief Get a hint + * + * \return The boolean value of a hint variable. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_GetHintBoolean(const char *name, SDL_bool default_value); + /** * \brief Add a function to watch a particular hint * diff --git a/Engine/lib/sdl/include/SDL_joystick.h b/Engine/lib/sdl/include/SDL_joystick.h index 266f3b387..f5dbc9487 100644 --- a/Engine/lib/sdl/include/SDL_joystick.h +++ b/Engine/lib/sdl/include/SDL_joystick.h @@ -24,7 +24,7 @@ * * Include file for SDL joystick event handling * - * The term "device_index" identifies currently plugged in joystick devices between 0 and SDL_NumJoysticks, with the exact joystick + * The term "device_index" identifies currently plugged in joystick devices between 0 and SDL_NumJoysticks(), with the exact joystick * behind a device_index changing as joysticks are plugged and unplugged. * * The term "instance_id" is the current instantiation of a joystick device in the system, if the joystick is removed and then re-inserted diff --git a/Engine/lib/sdl/include/SDL_keyboard.h b/Engine/lib/sdl/include/SDL_keyboard.h index bbba0f07b..f80b6d2de 100644 --- a/Engine/lib/sdl/include/SDL_keyboard.h +++ b/Engine/lib/sdl/include/SDL_keyboard.h @@ -136,7 +136,7 @@ extern DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromName(const char *name); * copy it. If the key doesn't have a name, this function returns an * empty string (""). * - * \sa SDL_Key + * \sa SDL_Keycode */ extern DECLSPEC const char *SDLCALL SDL_GetKeyName(SDL_Keycode key); diff --git a/Engine/lib/sdl/include/SDL_main.h b/Engine/lib/sdl/include/SDL_main.h index 9ce3754e9..67afea5e7 100644 --- a/Engine/lib/sdl/include/SDL_main.h +++ b/Engine/lib/sdl/include/SDL_main.h @@ -63,7 +63,7 @@ /* On Android SDL provides a Java class in SDLActivity.java that is the main activity entry point. - See README-android.txt for more details on extending that class. + See README-android.md for more details on extending that class. */ #define SDL_MAIN_NEEDED diff --git a/Engine/lib/sdl/include/SDL_mouse.h b/Engine/lib/sdl/include/SDL_mouse.h index ea9622f0f..46f046d0c 100644 --- a/Engine/lib/sdl/include/SDL_mouse.h +++ b/Engine/lib/sdl/include/SDL_mouse.h @@ -41,7 +41,7 @@ extern "C" { typedef struct SDL_Cursor SDL_Cursor; /* Implementation dependent */ /** - * \brief Cursor types for SDL_CreateSystemCursor. + * \brief Cursor types for SDL_CreateSystemCursor(). */ typedef enum { @@ -254,9 +254,11 @@ extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetCursor(void); extern DECLSPEC SDL_Cursor *SDLCALL SDL_GetDefaultCursor(void); /** - * \brief Frees a cursor created with SDL_CreateCursor(). + * \brief Frees a cursor created with SDL_CreateCursor() or similar functions. * * \sa SDL_CreateCursor() + * \sa SDL_CreateColorCursor() + * \sa SDL_CreateSystemCursor() */ extern DECLSPEC void SDLCALL SDL_FreeCursor(SDL_Cursor * cursor); diff --git a/Engine/lib/sdl/include/SDL_opengles.h b/Engine/lib/sdl/include/SDL_opengles.h index bcc127779..15abee796 100644 --- a/Engine/lib/sdl/include/SDL_opengles.h +++ b/Engine/lib/sdl/include/SDL_opengles.h @@ -24,6 +24,7 @@ * * This is a simple file to encapsulate the OpenGL ES 1.X API headers. */ +#include "SDL_config.h" #ifdef __IPHONEOS__ #include diff --git a/Engine/lib/sdl/include/SDL_opengles2.h b/Engine/lib/sdl/include/SDL_opengles2.h index edcd1a24a..c961f0f7d 100644 --- a/Engine/lib/sdl/include/SDL_opengles2.h +++ b/Engine/lib/sdl/include/SDL_opengles2.h @@ -24,6 +24,8 @@ * * This is a simple file to encapsulate the OpenGL ES 2.0 API headers. */ +#include "SDL_config.h" + #ifndef _MSC_VER #ifdef __IPHONEOS__ diff --git a/Engine/lib/sdl/include/SDL_pixels.h b/Engine/lib/sdl/include/SDL_pixels.h index 8499c3289..cf6a33f08 100644 --- a/Engine/lib/sdl/include/SDL_pixels.h +++ b/Engine/lib/sdl/include/SDL_pixels.h @@ -29,6 +29,7 @@ #define _SDL_pixels_h #include "SDL_stdinc.h" +#include "SDL_endian.h" #include "begin_code.h" /* Set up for C function definitions, even when using C++ */ @@ -260,6 +261,19 @@ enum SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_2101010, 32, 4), + /* Aliases for RGBA byte arrays of color data, for the current platform */ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888, + SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_BGRA8888, + SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_ABGR8888, +#else + SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888, + SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888, + SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888, + SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888, +#endif + SDL_PIXELFORMAT_YV12 = /**< Planar mode: Y + V + U (3 planes) */ SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'), SDL_PIXELFORMAT_IYUV = /**< Planar mode: Y + U + V (3 planes) */ diff --git a/Engine/lib/sdl/include/SDL_platform.h b/Engine/lib/sdl/include/SDL_platform.h index c6c21398b..03cf17061 100644 --- a/Engine/lib/sdl/include/SDL_platform.h +++ b/Engine/lib/sdl/include/SDL_platform.h @@ -70,18 +70,22 @@ /* lets us know what version of Mac OS X we're compiling on */ #include "AvailabilityMacros.h" #include "TargetConditionals.h" +#if TARGET_OS_TV +#undef __TVOS__ +#define __TVOS__ 1 +#endif #if TARGET_OS_IPHONE -/* if compiling for iPhone */ +/* if compiling for iOS */ #undef __IPHONEOS__ #define __IPHONEOS__ 1 #undef __MACOSX__ #else -/* if not compiling for iPhone */ +/* if not compiling for iOS */ #undef __MACOSX__ #define __MACOSX__ 1 -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 -# error SDL for Mac OS X only supports deploying on 10.5 and above. -#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1050 */ +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +# error SDL for Mac OS X only supports deploying on 10.6 and above. +#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */ #endif /* TARGET_OS_IPHONE */ #endif /* defined(__APPLE__) */ diff --git a/Engine/lib/sdl/include/SDL_render.h b/Engine/lib/sdl/include/SDL_render.h index e4ed2af69..60c87b66a 100644 --- a/Engine/lib/sdl/include/SDL_render.h +++ b/Engine/lib/sdl/include/SDL_render.h @@ -499,6 +499,30 @@ extern DECLSPEC int SDLCALL SDL_RenderSetLogicalSize(SDL_Renderer * renderer, in */ extern DECLSPEC void SDLCALL SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h); +/** + * \brief Set whether to force integer scales for resolution-independent rendering + * + * \param renderer The renderer for which integer scaling should be set. + * \param enable Enable or disable integer scaling + * + * This function restricts the logical viewport to integer values - that is, when + * a resolution is between two multiples of a logical size, the viewport size is + * rounded down to the lower multiple. + * + * \sa SDL_RenderSetLogicalSize() + */ +extern DECLSPEC int SDLCALL SDL_RenderSetIntegerScale(SDL_Renderer * renderer, + SDL_bool enable); + +/** + * \brief Get whether integer scales are forced for resolution-independent rendering + * + * \param renderer The renderer from which integer scaling should be queried. + * + * \sa SDL_RenderSetIntegerScale() + */ +extern DECLSPEC SDL_bool SDLCALL SDL_RenderGetIntegerScale(SDL_Renderer * renderer); + /** * \brief Set the drawing area for rendering on the current target. * @@ -658,7 +682,8 @@ extern DECLSPEC int SDLCALL SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, /** * \brief Clear the current rendering target with the drawing color * - * This function clears the entire rendering target, ignoring the viewport. + * This function clears the entire rendering target, ignoring the viewport and + * the clip rectangle. * * \return 0 on success, or -1 on error */ diff --git a/Engine/lib/sdl/include/SDL_revision.h b/Engine/lib/sdl/include/SDL_revision.h index 6d7163d4d..341dc5cce 100644 --- a/Engine/lib/sdl/include/SDL_revision.h +++ b/Engine/lib/sdl/include/SDL_revision.h @@ -1,2 +1,2 @@ -#define SDL_REVISION "hg-10001:e12c38730512" -#define SDL_REVISION_NUMBER 10001 +#define SDL_REVISION "hg-10556:007dfe83abf8" +#define SDL_REVISION_NUMBER 10556 diff --git a/Engine/lib/sdl/include/SDL_rwops.h b/Engine/lib/sdl/include/SDL_rwops.h index f460ae7d4..1ad3ac406 100644 --- a/Engine/lib/sdl/include/SDL_rwops.h +++ b/Engine/lib/sdl/include/SDL_rwops.h @@ -39,12 +39,12 @@ extern "C" { #endif /* RWops Types */ -#define SDL_RWOPS_UNKNOWN 0 /* Unknown stream type */ -#define SDL_RWOPS_WINFILE 1 /* Win32 file */ -#define SDL_RWOPS_STDFILE 2 /* Stdio file */ -#define SDL_RWOPS_JNIFILE 3 /* Android asset */ -#define SDL_RWOPS_MEMORY 4 /* Memory stream */ -#define SDL_RWOPS_MEMORY_RO 5 /* Read-Only memory stream */ +#define SDL_RWOPS_UNKNOWN 0U /* Unknown stream type */ +#define SDL_RWOPS_WINFILE 1U /* Win32 file */ +#define SDL_RWOPS_STDFILE 2U /* Stdio file */ +#define SDL_RWOPS_JNIFILE 3U /* Android asset */ +#define SDL_RWOPS_MEMORY 4U /* Memory stream */ +#define SDL_RWOPS_MEMORY_RO 5U /* Read-Only memory stream */ /** * This is the read/write operation structure -- very basic. diff --git a/Engine/lib/sdl/include/SDL_stdinc.h b/Engine/lib/sdl/include/SDL_stdinc.h index 887bcd2d4..fdf96415f 100644 --- a/Engine/lib/sdl/include/SDL_stdinc.h +++ b/Engine/lib/sdl/include/SDL_stdinc.h @@ -83,9 +83,6 @@ #ifdef HAVE_FLOAT_H # include #endif -#if defined(HAVE_ICONV) && defined(HAVE_ICONV_H) -# include -#endif /** * The number of elements in an array. @@ -93,6 +90,13 @@ #define SDL_arraysize(array) (sizeof(array)/sizeof(array[0])) #define SDL_TABLESIZE(table) SDL_arraysize(table) +/** + * Macro useful for building other macros with strings in them + * + * e.g. #define LOG_ERROR(X) OutputDebugString(SDL_STRINGIFY_ARG(__FUNCTION__) ": " X "\n") + */ +#define SDL_STRINGIFY_ARG(arg) #arg + /** * \name Cast operators * diff --git a/Engine/lib/sdl/include/SDL_surface.h b/Engine/lib/sdl/include/SDL_surface.h index e63ca8903..e4a06a204 100644 --- a/Engine/lib/sdl/include/SDL_surface.h +++ b/Engine/lib/sdl/include/SDL_surface.h @@ -118,6 +118,8 @@ typedef int (*SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect, extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurface (Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); +extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceWithFormat + (Uint32 flags, int width, int height, int depth, Uint32 format); extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, @@ -127,6 +129,8 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceFrom(void *pixels, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); +extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceWithFormatFrom + (void *pixels, int width, int height, int depth, int pitch, Uint32 format); extern DECLSPEC void SDLCALL SDL_FreeSurface(SDL_Surface * surface); /** @@ -184,6 +188,12 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_LoadBMP_RW(SDL_RWops * src, /** * Save a surface to a seekable SDL data stream (memory or file). * + * Surfaces with a 24-bit, 32-bit and paletted 8-bit format get saved in the + * BMP directly. Other RGB formats with 8-bit or higher get converted to a + * 24-bit surface or, if they have an alpha mask or a colorkey, to a 32-bit + * surface before they are saved. YUV and paletted 1-bit and 4-bit formats are + * not supported. + * * If \c freedst is non-zero, the stream will be closed after being written. * * \return 0 if successful or -1 if there was an error. diff --git a/Engine/lib/sdl/include/SDL_syswm.h b/Engine/lib/sdl/include/SDL_syswm.h index 1056e526b..71ba5f1f3 100644 --- a/Engine/lib/sdl/include/SDL_syswm.h +++ b/Engine/lib/sdl/include/SDL_syswm.h @@ -106,6 +106,10 @@ typedef struct ANativeWindow ANativeWindow; typedef void *EGLSurface; #endif +#if defined(SDL_VIDEO_DRIVER_VIVANTE) +#include "SDL_egl.h" +#endif + /** * These are the various supported windowing subsystems */ @@ -120,7 +124,8 @@ typedef enum SDL_SYSWM_WAYLAND, SDL_SYSWM_MIR, SDL_SYSWM_WINRT, - SDL_SYSWM_ANDROID + SDL_SYSWM_ANDROID, + SDL_SYSWM_VIVANTE } SDL_SYSWM_TYPE; /** @@ -166,6 +171,13 @@ struct SDL_SysWMmsg int dummy; /* No UIKit window events yet */ } uikit; +#endif +#if defined(SDL_VIDEO_DRIVER_VIVANTE) + struct + { + int dummy; + /* No Vivante window events yet */ + } vivante; #endif /* Can't have an empty union */ int dummy; @@ -259,6 +271,14 @@ struct SDL_SysWMinfo } android; #endif +#if defined(SDL_VIDEO_DRIVER_VIVANTE) + struct + { + EGLNativeDisplayType display; + EGLNativeWindowType window; + } vivante; +#endif + /* Can't have an empty union */ int dummy; } info; diff --git a/Engine/lib/sdl/include/SDL_version.h b/Engine/lib/sdl/include/SDL_version.h index de1f16056..1700efdd1 100644 --- a/Engine/lib/sdl/include/SDL_version.h +++ b/Engine/lib/sdl/include/SDL_version.h @@ -59,7 +59,7 @@ typedef struct SDL_version */ #define SDL_MAJOR_VERSION 2 #define SDL_MINOR_VERSION 0 -#define SDL_PATCHLEVEL 4 +#define SDL_PATCHLEVEL 5 /** * \brief Macro to determine SDL version program was compiled against. diff --git a/Engine/lib/sdl/include/SDL_video.h b/Engine/lib/sdl/include/SDL_video.h index 52dbbc765..73c33eb32 100644 --- a/Engine/lib/sdl/include/SDL_video.h +++ b/Engine/lib/sdl/include/SDL_video.h @@ -83,6 +83,7 @@ typedef struct * \sa SDL_SetWindowPosition() * \sa SDL_SetWindowSize() * \sa SDL_SetWindowBordered() + * \sa SDL_SetWindowResizable() * \sa SDL_SetWindowTitle() * \sa SDL_ShowWindow() */ @@ -95,6 +96,7 @@ typedef struct SDL_Window SDL_Window; */ typedef enum { + /* !!! FIXME: change this to name = (1<id) == device); - if (!device->enabled) { + if (!SDL_AtomicGet(&device->enabled)) { return; } /* Ends the audio callback and mark the device as STOPPED, but the app still needs to close the device to free resources. */ current_audio.impl.LockDevice(device); - device->enabled = 0; + SDL_AtomicSet(&device->enabled, 0); current_audio.impl.UnlockDevice(device); /* Post the event, if desired */ @@ -404,13 +421,26 @@ mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *remove void SDL_RemoveAudioDevice(const int iscapture, void *handle) { + int device_index; + SDL_AudioDevice *device = NULL; + 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); } + for (device_index = 0; device_index < SDL_arraysize(open_devices); device_index++) + { + device = open_devices[device_index]; + if (device != NULL && device->handle == handle) + { + SDL_OpenedAudioDeviceDisconnected(device); + break; + } + } SDL_UnlockMutex(current_audio.detectionLock); + current_audio.impl.FreeDeviceHandle(handle); } @@ -420,77 +450,24 @@ SDL_RemoveAudioDevice(const int iscapture, void *handle) /* this expects that you managed thread safety elsewhere. */ static void -free_audio_queue(SDL_AudioBufferQueue *buffer) +free_audio_queue(SDL_AudioBufferQueue *packet) { - while (buffer) { - SDL_AudioBufferQueue *next = buffer->next; - SDL_free(buffer); - buffer = next; + while (packet) { + SDL_AudioBufferQueue *next = packet->next; + SDL_free(packet); + packet = next; } } -static void SDLCALL -SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int _len) +/* NOTE: This assumes you'll hold the mixer lock before calling! */ +static int +queue_audio_to_device(SDL_AudioDevice *device, const Uint8 *data, Uint32 len) { - /* this function always holds the mixer lock before being called. */ - Uint32 len = (Uint32) _len; - SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; - SDL_AudioBufferQueue *buffer; - - SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ - SDL_assert(_len >= 0); /* this shouldn't ever happen, right?! */ - - while ((len > 0) && ((buffer = device->buffer_queue_head) != NULL)) { - const Uint32 avail = buffer->datalen - buffer->startpos; - const Uint32 cpy = SDL_min(len, avail); - SDL_assert(device->queued_bytes >= avail); - - SDL_memcpy(stream, buffer->data + buffer->startpos, cpy); - buffer->startpos += cpy; - stream += cpy; - device->queued_bytes -= cpy; - len -= cpy; - - if (buffer->startpos == buffer->datalen) { /* packet is done, put it in the pool. */ - device->buffer_queue_head = buffer->next; - SDL_assert((buffer->next != NULL) || (buffer == device->buffer_queue_tail)); - buffer->next = device->buffer_queue_pool; - device->buffer_queue_pool = buffer; - } - } - - SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0)); - - if (len > 0) { /* fill any remaining space in the stream with silence. */ - SDL_assert(device->buffer_queue_head == NULL); - SDL_memset(stream, device->spec.silence, len); - } - - if (device->buffer_queue_head == NULL) { - device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */ - } -} - -int -SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) -{ - SDL_AudioDevice *device = get_audio_device(devid); - const Uint8 *data = (const Uint8 *) _data; SDL_AudioBufferQueue *orighead; SDL_AudioBufferQueue *origtail; Uint32 origlen; Uint32 datalen; - if (!device) { - return -1; /* get_audio_device() will have set the error state */ - } - - if (device->spec.callback != SDL_BufferQueueDrainCallback) { - return SDL_SetError("Audio device has a callback, queueing not allowed"); - } - - current_audio.impl.LockDevice(device); - orighead = device->buffer_queue_head; origtail = device->buffer_queue_tail; origlen = origtail ? origtail->datalen : 0; @@ -520,8 +497,6 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) device->buffer_queue_tail = origtail; device->buffer_queue_pool = NULL; - current_audio.impl.UnlockDevice(device); - free_audio_queue(packet); /* give back what we can. */ return SDL_OutOfMemory(); @@ -548,22 +523,142 @@ SDL_QueueAudio(SDL_AudioDeviceID devid, const void *_data, Uint32 len) device->queued_bytes += datalen; } - current_audio.impl.UnlockDevice(device); - return 0; } +/* NOTE: This assumes you'll hold the mixer lock before calling! */ +static Uint32 +dequeue_audio_from_device(SDL_AudioDevice *device, Uint8 *stream, Uint32 len) +{ + SDL_AudioBufferQueue *packet; + Uint8 *ptr = stream; + + while ((len > 0) && ((packet = device->buffer_queue_head) != NULL)) { + const Uint32 avail = packet->datalen - packet->startpos; + const Uint32 cpy = SDL_min(len, avail); + SDL_assert(device->queued_bytes >= avail); + + SDL_memcpy(ptr, packet->data + packet->startpos, cpy); + packet->startpos += cpy; + ptr += cpy; + device->queued_bytes -= cpy; + len -= cpy; + + if (packet->startpos == packet->datalen) { /* packet is done, put it in the pool. */ + device->buffer_queue_head = packet->next; + SDL_assert((packet->next != NULL) || (packet == device->buffer_queue_tail)); + packet->next = device->buffer_queue_pool; + device->buffer_queue_pool = packet; + } + } + + SDL_assert((device->buffer_queue_head != NULL) == (device->queued_bytes != 0)); + + if (device->buffer_queue_head == NULL) { + device->buffer_queue_tail = NULL; /* in case we drained the queue entirely. */ + } + + return (Uint32) (ptr - stream); +} + +static void SDLCALL +SDL_BufferQueueDrainCallback(void *userdata, Uint8 *stream, int len) +{ + /* this function always holds the mixer lock before being called. */ + SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; + Uint32 written; + + SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ + SDL_assert(!device->iscapture); /* this shouldn't ever happen, right?! */ + SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */ + + written = dequeue_audio_from_device(device, stream, (Uint32) len); + stream += written; + len -= (int) written; + + if (len > 0) { /* fill any remaining space in the stream with silence. */ + SDL_assert(device->buffer_queue_head == NULL); + SDL_memset(stream, device->spec.silence, len); + } +} + +static void SDLCALL +SDL_BufferQueueFillCallback(void *userdata, Uint8 *stream, int len) +{ + /* this function always holds the mixer lock before being called. */ + SDL_AudioDevice *device = (SDL_AudioDevice *) userdata; + + SDL_assert(device != NULL); /* this shouldn't ever happen, right?! */ + SDL_assert(device->iscapture); /* this shouldn't ever happen, right?! */ + SDL_assert(len >= 0); /* this shouldn't ever happen, right?! */ + + /* note that if this needs to allocate more space and run out of memory, + we have no choice but to quietly drop the data and hope it works out + later, but you probably have bigger problems in this case anyhow. */ + queue_audio_to_device(device, stream, (Uint32) len); +} + +int +SDL_QueueAudio(SDL_AudioDeviceID devid, const void *data, Uint32 len) +{ + SDL_AudioDevice *device = get_audio_device(devid); + int rc = 0; + + if (!device) { + return -1; /* get_audio_device() will have set the error state */ + } else if (device->iscapture) { + return SDL_SetError("This is a capture device, queueing not allowed"); + } else if (device->spec.callback != SDL_BufferQueueDrainCallback) { + return SDL_SetError("Audio device has a callback, queueing not allowed"); + } + + if (len > 0) { + current_audio.impl.LockDevice(device); + rc = queue_audio_to_device(device, data, len); + current_audio.impl.UnlockDevice(device); + } + + return rc; +} + +Uint32 +SDL_DequeueAudio(SDL_AudioDeviceID devid, void *data, Uint32 len) +{ + SDL_AudioDevice *device = get_audio_device(devid); + Uint32 rc; + + if ( (len == 0) || /* nothing to do? */ + (!device) || /* called with bogus device id */ + (!device->iscapture) || /* playback devices can't dequeue */ + (device->spec.callback != SDL_BufferQueueFillCallback) ) { /* not set for queueing */ + return 0; /* just report zero bytes dequeued. */ + } + + current_audio.impl.LockDevice(device); + rc = dequeue_audio_from_device(device, data, len); + current_audio.impl.UnlockDevice(device); + return rc; +} + Uint32 SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid) { Uint32 retval = 0; SDL_AudioDevice *device = get_audio_device(devid); + if (!device) { + return 0; + } + /* Nothing to do unless we're set up for queueing. */ - if (device && (device->spec.callback == SDL_BufferQueueDrainCallback)) { + if (device->spec.callback == SDL_BufferQueueDrainCallback) { current_audio.impl.LockDevice(device); retval = device->queued_bytes + current_audio.impl.GetPendingBytes(device); current_audio.impl.UnlockDevice(device); + } else if (device->spec.callback == SDL_BufferQueueFillCallback) { + current_audio.impl.LockDevice(device); + retval = device->queued_bytes; + current_audio.impl.UnlockDevice(device); } return retval; @@ -573,25 +668,49 @@ void SDL_ClearQueuedAudio(SDL_AudioDeviceID devid) { SDL_AudioDevice *device = get_audio_device(devid); - SDL_AudioBufferQueue *buffer = NULL; + SDL_AudioBufferQueue *packet; + if (!device) { return; /* nothing to do. */ } /* Blank out the device and release the mutex. Free it afterwards. */ current_audio.impl.LockDevice(device); - buffer = device->buffer_queue_head; + + /* merge the available pool and the current queue into one list. */ + packet = device->buffer_queue_head; + if (packet) { + device->buffer_queue_tail->next = device->buffer_queue_pool; + } else { + packet = device->buffer_queue_pool; + } + + /* Remove the queued packets from the device. */ device->buffer_queue_tail = NULL; device->buffer_queue_head = NULL; device->queued_bytes = 0; + device->buffer_queue_pool = packet; + + /* Keep up to two packets in the pool to reduce future malloc pressure. */ + if (packet) { + if (!packet->next) { + packet = NULL; /* one packet (the only one) for the pool. */ + } else { + SDL_AudioBufferQueue *next = packet->next->next; + packet->next->next = NULL; /* two packets for the pool. */ + packet = next; /* rest will be freed. */ + } + } + current_audio.impl.UnlockDevice(device); - free_audio_queue(buffer); + /* free any extra packets we didn't keep in the pool. */ + free_audio_queue(packet); } /* The general mixing thread function */ -int SDLCALL +static int SDLCALL SDL_RunAudio(void *devicep) { SDL_AudioDevice *device = (SDL_AudioDevice *) devicep; @@ -600,7 +719,9 @@ SDL_RunAudio(void *devicep) const int stream_len = (device->convert.needed) ? device->convert.len : device->spec.size; Uint8 *stream; void *udata = device->spec.userdata; - void (SDLCALL *fill) (void *, Uint8 *, int) = device->spec.callback; + void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback; + + SDL_assert(!device->iscapture); /* The audio mixing is always a high priority thread */ SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); @@ -610,11 +731,11 @@ SDL_RunAudio(void *devicep) current_audio.impl.ThreadInit(device); /* Loop, filling the audio buffers */ - while (!device->shutdown) { + while (!SDL_AtomicGet(&device->shutdown)) { /* Fill the current buffer with sound */ if (device->convert.needed) { stream = device->convert.buf; - } else if (device->enabled) { + } else if (SDL_AtomicGet(&device->enabled)) { stream = current_audio.impl.GetDeviceBuf(device); } else { /* if the device isn't enabled, we still write to the @@ -630,16 +751,18 @@ SDL_RunAudio(void *devicep) } /* !!! 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); + if ( SDL_AtomicGet(&device->enabled) ) { + SDL_LockMutex(device->mixer_lock); + if (SDL_AtomicGet(&device->paused)) { + SDL_memset(stream, silence, stream_len); + } else { + (*callback) (udata, stream, stream_len); + } + SDL_UnlockMutex(device->mixer_lock); } - SDL_UnlockMutex(device->mixer_lock); /* Convert the audio if necessary */ - if (device->enabled && device->convert.needed) { + if (device->convert.needed && SDL_AtomicGet(&device->enabled)) { SDL_ConvertAudio(&device->convert); stream = current_audio.impl.GetDeviceBuf(device); if (stream == NULL) { @@ -659,8 +782,91 @@ SDL_RunAudio(void *devicep) } } + current_audio.impl.PrepareToClose(device); + /* Wait for the audio to drain. */ - current_audio.impl.WaitDone(device); + SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2); + + return 0; +} + +/* The general capture thread function */ +static int SDLCALL +SDL_CaptureAudio(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; + void *udata = device->spec.userdata; + void (SDLCALL *callback) (void *, Uint8 *, int) = device->spec.callback; + + SDL_assert(device->iscapture); + + /* The audio mixing is always a high priority thread */ + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + /* Perform any thread setup */ + device->threadid = SDL_ThreadID(); + current_audio.impl.ThreadInit(device); + + /* Loop, filling the audio buffers */ + while (!SDL_AtomicGet(&device->shutdown)) { + int still_need; + Uint8 *ptr; + + if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) { + SDL_Delay(delay); /* just so we don't cook the CPU. */ + current_audio.impl.FlushCapture(device); /* dump anything pending. */ + continue; + } + + /* Fill the current buffer with sound */ + still_need = stream_len; + if (device->convert.needed) { + ptr = stream = device->convert.buf; + } else { + /* just use the "fake" stream to hold data read from the device. */ + ptr = stream = device->fake_stream; + } + + /* We still read from the device when "paused" to keep the state sane, + and block when there isn't data so this thread isn't eating CPU. + But we don't process it further or call the app's callback. */ + + while (still_need > 0) { + const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need); + SDL_assert(rc <= still_need); /* device should not overflow buffer. :) */ + if (rc > 0) { + still_need -= rc; + ptr += rc; + } else { /* uhoh, device failed for some reason! */ + SDL_OpenedAudioDeviceDisconnected(device); + break; + } + } + + if (still_need > 0) { + /* Keep any data we already read, silence the rest. */ + SDL_memset(ptr, silence, still_need); + } + + if (device->convert.needed) { + SDL_ConvertAudio(&device->convert); + } + + /* !!! FIXME: this should be LockDevice. */ + SDL_LockMutex(device->mixer_lock); + if (SDL_AtomicGet(&device->paused)) { + current_audio.impl.FlushCapture(device); /* one snuck in! */ + } else { + (*callback)(udata, stream, stream_len); + } + SDL_UnlockMutex(device->mixer_lock); + } + + current_audio.impl.FlushCapture(device); return 0; } @@ -757,7 +963,7 @@ SDL_AudioInit(const char *driver_name) current_audio.detectionLock = SDL_CreateMutex(); - finalize_audio_entry_points(); + finish_audio_entry_points_init(); /* Make sure we have a list of devices available at startup. */ current_audio.impl.DetectDevices(); @@ -872,27 +1078,38 @@ SDL_GetAudioDeviceName(int index, int iscapture) static void close_audio_device(SDL_AudioDevice * device) { - device->enabled = 0; - device->shutdown = 1; + if (!device) { + return; + } + + if (device->id > 0) { + SDL_AudioDevice *opendev = open_devices[device->id - 1]; + SDL_assert((opendev == device) || (opendev == NULL)); + if (opendev == device) { + open_devices[device->id - 1] = NULL; + } + } + + SDL_AtomicSet(&device->shutdown, 1); + SDL_AtomicSet(&device->enabled, 0); if (device->thread != NULL) { SDL_WaitThread(device->thread, NULL); } if (device->mixer_lock != NULL) { SDL_DestroyMutex(device->mixer_lock); } - SDL_FreeAudioMem(device->fake_stream); + SDL_free(device->fake_stream); if (device->convert.needed) { - SDL_FreeAudioMem(device->convert.buf); + SDL_free(device->convert.buf); } - if (device->opened) { + if (device->hidden != NULL) { current_audio.impl.CloseDevice(device); - device->opened = 0; } free_audio_queue(device->buffer_queue_head); free_audio_queue(device->buffer_queue_pool); - SDL_FreeAudioMem(device); + SDL_free(device); } @@ -963,12 +1180,12 @@ open_audio_device(const char *devname, int iscapture, const SDL_AudioSpec * desired, SDL_AudioSpec * obtained, int allowed_changes, int min_id) { + const SDL_bool is_internal_thread = (desired->callback != NULL); SDL_AudioDeviceID id = 0; 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)) { @@ -981,6 +1198,7 @@ open_audio_device(const char *devname, int iscapture, return 0; } + /* !!! FIXME: there is a race condition here if two devices open from two threads at once. */ /* Find an available device ID... */ for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) { if (open_devices[id] == NULL) { @@ -1015,7 +1233,7 @@ open_audio_device(const char *devname, int iscapture, * opens of the default system device. */ - if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) { + if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) { if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) { SDL_SetError("No such device"); return 0; @@ -1067,17 +1285,19 @@ open_audio_device(const char *devname, int iscapture, } } - device = (SDL_AudioDevice *) SDL_AllocAudioMem(sizeof(SDL_AudioDevice)); + device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice)); if (device == NULL) { SDL_OutOfMemory(); return 0; } - SDL_zerop(device); device->id = id + 1; device->spec = *obtained; - device->enabled = 1; - device->paused = 1; - device->iscapture = iscapture; + device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; + device->handle = handle; + + SDL_AtomicSet(&device->shutdown, 0); /* just in case. */ + SDL_AtomicSet(&device->paused, 1); + SDL_AtomicSet(&device->enabled, 1); /* Create a mutex for locking the sound buffers */ if (!current_audio.impl.SkipMixerLock) { @@ -1093,7 +1313,10 @@ open_audio_device(const char *devname, int iscapture, close_audio_device(device); return 0; } - device->opened = 1; + + /* if your target really doesn't need it, set it to 0x1 or something. */ + /* otherwise, close_audio_device() won't call impl.CloseDevice(). */ + SDL_assert(device->hidden != NULL); /* See if we need to do any conversion */ build_cvt = SDL_FALSE; @@ -1143,7 +1366,7 @@ open_audio_device(const char *devname, int iscapture, device->convert.len_ratio); device->convert.buf = - (Uint8 *) SDL_AllocAudioMem(device->convert.len * + (Uint8 *) SDL_malloc(device->convert.len * device->convert.len_mult); if (device->convert.buf == NULL) { close_audio_device(device); @@ -1153,19 +1376,6 @@ 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; @@ -1181,7 +1391,7 @@ open_audio_device(const char *devname, int iscapture, } } - device->spec.callback = SDL_BufferQueueDrainCallback; + device->spec.callback = iscapture ? SDL_BufferQueueFillCallback : SDL_BufferQueueDrainCallback; device->spec.userdata = device; } @@ -1191,21 +1401,30 @@ open_audio_device(const char *devname, int iscapture, /* 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) device->id); -/* !!! FIXME: this is nasty. */ -#if defined(__WIN32__) && !defined(HAVE_LIBC) -#undef SDL_CreateThread -#if SDL_DYNAMIC_API - device->thread = SDL_CreateThread_REAL(SDL_RunAudio, name, device, NULL, NULL); -#else - device->thread = SDL_CreateThread(SDL_RunAudio, name, device, NULL, NULL); -#endif -#else - device->thread = SDL_CreateThread(SDL_RunAudio, name, device); -#endif + /* !!! FIXME: we don't force the audio thread stack size here if it calls into user code, but maybe we should? */ + /* buffer queueing callback only needs a few bytes, so make the stack tiny. */ + const size_t stacksize = is_internal_thread ? 64 * 1024 : 0; + char threadname[64]; + + /* Allocate a fake audio buffer; only used by our internal threads. */ + Uint32 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_malloc(stream_len); + if (device->fake_stream == NULL) { + close_audio_device(device); + SDL_OutOfMemory(); + return 0; + } + + SDL_snprintf(threadname, sizeof (threadname), "SDLAudioDev%d", (int) device->id); + device->thread = SDL_CreateThreadInternal(iscapture ? SDL_CaptureAudio : SDL_RunAudio, threadname, stacksize, device); + if (device->thread == NULL) { - SDL_CloseAudioDevice(device->id); + close_audio_device(device); SDL_SetError("Couldn't create audio thread"); return 0; } @@ -1258,8 +1477,8 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid) { SDL_AudioDevice *device = get_audio_device(devid); SDL_AudioStatus status = SDL_AUDIO_STOPPED; - if (device && device->enabled) { - if (device->paused) { + if (device && SDL_AtomicGet(&device->enabled)) { + if (SDL_AtomicGet(&device->paused)) { status = SDL_AUDIO_PAUSED; } else { status = SDL_AUDIO_PLAYING; @@ -1281,7 +1500,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on) SDL_AudioDevice *device = get_audio_device(devid); if (device) { current_audio.impl.LockDevice(device); - device->paused = pause_on; + SDL_AtomicSet(&device->paused, pause_on ? 1 : 0); current_audio.impl.UnlockDevice(device); } } @@ -1328,11 +1547,7 @@ SDL_UnlockAudio(void) void SDL_CloseAudioDevice(SDL_AudioDeviceID devid) { - SDL_AudioDevice *device = get_audio_device(devid); - if (device) { - close_audio_device(device); - open_devices[devid - 1] = NULL; - } + close_audio_device(get_audio_device(devid)); } void @@ -1351,9 +1566,7 @@ SDL_AudioQuit(void) } for (i = 0; i < SDL_arraysize(open_devices); i++) { - if (open_devices[i] != NULL) { - SDL_CloseAudioDevice(i+1); - } + close_audio_device(open_devices[i]); } free_device_list(¤t_audio.outputDevices, ¤t_audio.outputDeviceCount); diff --git a/Engine/lib/sdl/src/audio/SDL_audio_c.h b/Engine/lib/sdl/src/audio/SDL_audio_c.h index b03a9156f..7cde3a662 100644 --- a/Engine/lib/sdl/src/audio/SDL_audio_c.h +++ b/Engine/lib/sdl/src/audio/SDL_audio_c.h @@ -29,9 +29,6 @@ extern SDL_AudioFormat SDL_NextAudioFormat(void); /* Function to calculate the size and silence for a SDL_AudioSpec */ extern void SDL_CalculateAudioSpec(SDL_AudioSpec * spec); -/* The actual mixing thread function */ -extern int SDLCALL SDL_RunAudio(void *audiop); - /* this is used internally to access some autogenerated code. */ typedef struct { diff --git a/Engine/lib/sdl/src/audio/SDL_mixer.c b/Engine/lib/sdl/src/audio/SDL_mixer.c index b49c73dab..e0219392d 100644 --- a/Engine/lib/sdl/src/audio/SDL_mixer.c +++ b/Engine/lib/sdl/src/audio/SDL_mixer.c @@ -202,6 +202,54 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, } break; + case AUDIO_U16LSB: + { + Uint16 src1, src2; + int dst_sample; + const int max_audioval = 0xFFFF; + + len /= 2; + while (len--) { + src1 = ((src[1]) << 8 | src[0]); + ADJUST_VOLUME(src1, volume); + src2 = ((dst[1]) << 8 | dst[0]); + src += 2; + dst_sample = src1 + src2; + if (dst_sample > max_audioval) { + dst_sample = max_audioval; + } + dst[0] = dst_sample & 0xFF; + dst_sample >>= 8; + dst[1] = dst_sample & 0xFF; + dst += 2; + } + } + break; + + case AUDIO_U16MSB: + { + Uint16 src1, src2; + int dst_sample; + const int max_audioval = 0xFFFF; + + len /= 2; + while (len--) { + src1 = ((src[0]) << 8 | src[1]); + ADJUST_VOLUME(src1, volume); + src2 = ((dst[0]) << 8 | dst[1]); + src += 2; + dst_sample = src1 + src2; + if (dst_sample > max_audioval) { + dst_sample = max_audioval; + } + dst[1] = dst_sample & 0xFF; + dst_sample >>= 8; + dst[0] = dst_sample & 0xFF; + dst += 2; + } + } + break; + case AUDIO_S32LSB: { const Uint32 *src32 = (Uint32 *) src; @@ -313,7 +361,7 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, break; default: /* If this happens... FIXME! */ - SDL_SetError("SDL_MixAudio(): unknown audio format"); + SDL_SetError("SDL_MixAudioFormat(): unknown audio format"); return; } } diff --git a/Engine/lib/sdl/src/audio/SDL_sysaudio.h b/Engine/lib/sdl/src/audio/SDL_sysaudio.h index 426a190f1..943169bf7 100644 --- a/Engine/lib/sdl/src/audio/SDL_sysaudio.h +++ b/Engine/lib/sdl/src/audio/SDL_sysaudio.h @@ -26,6 +26,10 @@ #include "SDL_mutex.h" #include "SDL_thread.h" +/* !!! FIXME: These are wordy and unlocalized... */ +#define DEFAULT_OUTPUT_DEVNAME "System audio output device" +#define DEFAULT_INPUT_DEVNAME "System audio capture device" + /* The SDL audio driver */ typedef struct SDL_AudioDevice SDL_AudioDevice; #define _THIS SDL_AudioDevice *_this @@ -75,7 +79,9 @@ typedef struct SDL_AudioDriverImpl void (*PlayDevice) (_THIS); int (*GetPendingBytes) (_THIS); Uint8 *(*GetDeviceBuf) (_THIS); - void (*WaitDone) (_THIS); + int (*CaptureFromDevice) (_THIS, void *buffer, int buflen); + void (*FlushCapture) (_THIS); + void (*PrepareToClose) (_THIS); /**< Called between run and draining wait for playback devices */ void (*CloseDevice) (_THIS); void (*LockDevice) (_THIS); void (*UnlockDevice) (_THIS); @@ -87,10 +93,10 @@ typedef struct SDL_AudioDriverImpl /* 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 SkipMixerLock; int HasCaptureSupport; int OnlyHasDefaultOutputDevice; - int OnlyHasDefaultInputDevice; + int OnlyHasDefaultCaptureDevice; int AllowsArbitraryDeviceNames; } SDL_AudioDriverImpl; @@ -157,12 +163,10 @@ struct SDL_AudioDevice SDL_AudioStreamer streamer; /* Current state flags */ - /* !!! FIXME: should be SDL_bool */ - int iscapture; - 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; + SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */ + SDL_atomic_t enabled; /* true if device is functioning and connected. */ + SDL_atomic_t paused; + SDL_bool iscapture; /* Fake audio buffer for when the audio hardware is busy */ Uint8 *fake_stream; @@ -183,6 +187,8 @@ struct SDL_AudioDevice /* * * */ /* Data private to this driver */ struct SDL_PrivateAudioData *hidden; + + void *handle; }; #undef _THIS diff --git a/Engine/lib/sdl/src/audio/SDL_wave.c b/Engine/lib/sdl/src/audio/SDL_wave.c index 99daac64b..d173b4a92 100644 --- a/Engine/lib/sdl/src/audio/SDL_wave.c +++ b/Engine/lib/sdl/src/audio/SDL_wave.c @@ -504,7 +504,7 @@ SDL_LoadWAV_RW(SDL_RWops * src, int freesrc, was_error = 1; goto done; } - SDL_memset(spec, 0, (sizeof *spec)); + SDL_zerop(spec); spec->freq = SDL_SwapLE32(format->frequency); if (IEEE_float_encoded) { diff --git a/Engine/lib/sdl/src/audio/alsa/SDL_alsa_audio.c b/Engine/lib/sdl/src/audio/alsa/SDL_alsa_audio.c index af952371b..574d51bd5 100644 --- a/Engine/lib/sdl/src/audio/alsa/SDL_alsa_audio.c +++ b/Engine/lib/sdl/src/audio/alsa/SDL_alsa_audio.c @@ -29,9 +29,9 @@ #include #include +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_alsa_audio.h" @@ -42,8 +42,10 @@ static int (*ALSA_snd_pcm_open) (snd_pcm_t **, const char *, snd_pcm_stream_t, int); static int (*ALSA_snd_pcm_close) (snd_pcm_t * pcm); -static snd_pcm_sframes_t(*ALSA_snd_pcm_writei) +static snd_pcm_sframes_t (*ALSA_snd_pcm_writei) (snd_pcm_t *, const void *, snd_pcm_uframes_t); +static snd_pcm_sframes_t (*ALSA_snd_pcm_readi) + (snd_pcm_t *, void *, snd_pcm_uframes_t); static int (*ALSA_snd_pcm_recover) (snd_pcm_t *, int, int); static int (*ALSA_snd_pcm_prepare) (snd_pcm_t *); static int (*ALSA_snd_pcm_drain) (snd_pcm_t *); @@ -85,6 +87,10 @@ static int (*ALSA_snd_pcm_nonblock) (snd_pcm_t *, int); static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int); static int (*ALSA_snd_pcm_sw_params_set_avail_min) (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t); +static int (*ALSA_snd_pcm_reset)(snd_pcm_t *); +static int (*ALSA_snd_device_name_hint) (int, const char *, void ***); +static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *); +static int (*ALSA_snd_device_name_free_hint) (void **); #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof @@ -118,6 +124,7 @@ load_alsa_syms(void) SDL_ALSA_SYM(snd_pcm_open); SDL_ALSA_SYM(snd_pcm_close); SDL_ALSA_SYM(snd_pcm_writei); + SDL_ALSA_SYM(snd_pcm_readi); SDL_ALSA_SYM(snd_pcm_recover); SDL_ALSA_SYM(snd_pcm_prepare); SDL_ALSA_SYM(snd_pcm_drain); @@ -144,6 +151,11 @@ load_alsa_syms(void) SDL_ALSA_SYM(snd_pcm_nonblock); SDL_ALSA_SYM(snd_pcm_wait); SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min); + SDL_ALSA_SYM(snd_pcm_reset); + SDL_ALSA_SYM(snd_device_name_hint); + SDL_ALSA_SYM(snd_device_name_get_hint); + SDL_ALSA_SYM(snd_device_name_free_hint); + return 0; } @@ -196,25 +208,27 @@ LoadALSALibrary(void) #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */ static const char * -get_audio_device(int channels) +get_audio_device(void *handle, const int channels) { const char *device; - device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */ - if (device == NULL) { - switch (channels) { - case 6: - device = "plug:surround51"; - break; - case 4: - device = "plug:surround40"; - break; - default: - device = "default"; - break; - } + if (handle != NULL) { + return (const char *) handle; } - return device; + + /* !!! FIXME: we also check "SDL_AUDIO_DEVICE_NAME" at the higher level. */ + device = SDL_getenv("AUDIODEV"); /* Is there a standard variable name? */ + if (device != NULL) { + return device; + } + + if (channels == 6) { + return "plug:surround51"; + } else if (channels == 4) { + return "plug:surround40"; + } + + return "default"; } @@ -232,37 +246,37 @@ ALSA_WaitDevice(_THIS) * "For Linux ALSA, this is FL-FR-RL-RR-C-LFE * and for Windows DirectX [and CoreAudio], this is FL-FR-C-LFE-RL-RR" */ -#define SWIZ6(T) \ - T *ptr = (T *) this->hidden->mixbuf; \ +#define SWIZ6(T, buf, numframes) \ + T *ptr = (T *) buf; \ Uint32 i; \ - for (i = 0; i < this->spec.samples; i++, ptr += 6) { \ + for (i = 0; i < numframes; i++, ptr += 6) { \ T tmp; \ tmp = ptr[2]; ptr[2] = ptr[4]; ptr[4] = tmp; \ tmp = ptr[3]; ptr[3] = ptr[5]; ptr[5] = tmp; \ } static SDL_INLINE void -swizzle_alsa_channels_6_64bit(_THIS) +swizzle_alsa_channels_6_64bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint64); + SWIZ6(Uint64, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_32bit(_THIS) +swizzle_alsa_channels_6_32bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint32); + SWIZ6(Uint32, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_16bit(_THIS) +swizzle_alsa_channels_6_16bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint16); + SWIZ6(Uint16, buffer, bufferlen); } static SDL_INLINE void -swizzle_alsa_channels_6_8bit(_THIS) +swizzle_alsa_channels_6_8bit(void *buffer, Uint32 bufferlen) { - SWIZ6(Uint8); + SWIZ6(Uint8, buffer, bufferlen); } #undef SWIZ6 @@ -273,18 +287,16 @@ swizzle_alsa_channels_6_8bit(_THIS) * channels from Windows/Mac order to the format alsalib will want. */ static SDL_INLINE void -swizzle_alsa_channels(_THIS) +swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen) { if (this->spec.channels == 6) { - const Uint16 fmtsize = (this->spec.format & 0xFF); /* bits/channel. */ - if (fmtsize == 16) - swizzle_alsa_channels_6_16bit(this); - else if (fmtsize == 8) - swizzle_alsa_channels_6_8bit(this); - else if (fmtsize == 32) - swizzle_alsa_channels_6_32bit(this); - else if (fmtsize == 64) - swizzle_alsa_channels_6_64bit(this); + switch (SDL_AUDIO_BITSIZE(this->spec.format)) { + case 8: swizzle_alsa_channels_6_8bit(buffer, bufferlen); break; + case 16: swizzle_alsa_channels_6_16bit(buffer, bufferlen); break; + case 32: swizzle_alsa_channels_6_32bit(buffer, bufferlen); break; + case 64: swizzle_alsa_channels_6_64bit(buffer, bufferlen); break; + default: SDL_assert(!"unhandled bitsize"); break; + } } /* !!! FIXME: update this for 7.1 if needed, later. */ @@ -294,19 +306,29 @@ swizzle_alsa_channels(_THIS) static void ALSA_PlayDevice(_THIS) { - int status; const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf; - const int frame_size = (((int) (this->spec.format & 0xFF)) / 8) * + const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * this->spec.channels; snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples); - swizzle_alsa_channels(this); + swizzle_alsa_channels(this, this->hidden->mixbuf, frames_left); + + while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { + int status; + + /* This wait is a work-around for a hang when USB devices are + unplugged. Normally it should not result in any waiting, + but in the case of a USB unplug, it serves as a way to + join the playback thread after the timeout occurs */ + status = ALSA_snd_pcm_wait(this->hidden->pcm_handle, 1000); + if (status == 0) { + /*fprintf(stderr, "ALSA timeout waiting for available buffer space\n");*/ + SDL_OpenedAudioDeviceDisconnected(this); + return; + } - while ( frames_left > 0 && this->enabled ) { - /* !!! FIXME: This works, but needs more testing before going live */ - /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ status = ALSA_snd_pcm_writei(this->hidden->pcm_handle, - sample_buf, frames_left); + sample_buf, frames_left); if (status < 0) { if (status == -EAGAIN) { @@ -336,20 +358,71 @@ ALSA_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + Uint8 *sample_buf = (Uint8 *) buffer; + const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) * + this->spec.channels; + const int total_frames = buflen / frame_size; + snd_pcm_uframes_t frames_left = total_frames; + + SDL_assert((buflen % frame_size) == 0); + + while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) { + /* !!! FIXME: This works, but needs more testing before going live */ + /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */ + int status = ALSA_snd_pcm_readi(this->hidden->pcm_handle, + sample_buf, frames_left); + + if (status < 0) { + /*printf("ALSA: capture error %d\n", status);*/ + if (status == -EAGAIN) { + /* Apparently snd_pcm_recover() doesn't handle this case - + does it assume snd_pcm_wait() above? */ + SDL_Delay(1); + continue; + } + status = ALSA_snd_pcm_recover(this->hidden->pcm_handle, status, 0); + if (status < 0) { + /* Hmm, not much we can do - abort */ + fprintf(stderr, "ALSA read failed (unrecoverable): %s\n", + ALSA_snd_strerror(status)); + return -1; + } + continue; + } + + /*printf("ALSA: captured %d bytes\n", status * frame_size);*/ + sample_buf += status * frame_size; + frames_left -= status; + } + + swizzle_alsa_channels(this, buffer, total_frames - frames_left); + + return (total_frames - frames_left) * frame_size; +} + +static void +ALSA_FlushCapture(_THIS) +{ + ALSA_snd_pcm_reset(this->hidden->pcm_handle); +} + static void ALSA_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->pcm_handle) { - ALSA_snd_pcm_drain(this->hidden->pcm_handle); - ALSA_snd_pcm_close(this->hidden->pcm_handle); - this->hidden->pcm_handle = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->pcm_handle) { + /* Wait for the submitted audio to drain + ALSA_snd_pcm_drop() can hang, so don't use that. + */ + Uint32 delay = ((this->spec.samples * 1000) / this->spec.freq) * 2; + SDL_Delay(delay); + + ALSA_snd_pcm_close(this->hidden->pcm_handle); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -482,16 +555,16 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ /* Name of device should depend on # channels in spec */ status = ALSA_snd_pcm_open(&pcm_handle, - get_audio_device(this->spec.channels), - SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); + get_audio_device(handle, this->spec.channels), + iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't open audio device: %s", ALSA_snd_strerror(status)); } @@ -502,7 +575,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_hw_params_alloca(&hwparams); status = ALSA_snd_pcm_hw_params_any(pcm_handle, hwparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't get hardware config: %s", ALSA_snd_strerror(status)); } @@ -511,7 +583,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) status = ALSA_snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set interleaved access: %s", ALSA_snd_strerror(status)); } @@ -565,7 +636,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -577,7 +647,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (status < 0) { status = ALSA_snd_pcm_hw_params_get_channels(hwparams, &channels); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set audio channels"); } this->spec.channels = channels; @@ -588,7 +657,6 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) status = ALSA_snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, NULL); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set audio frequency: %s", ALSA_snd_strerror(status)); } @@ -598,8 +666,8 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if ( ALSA_set_period_size(this, hwparams, 0) < 0 && ALSA_set_buffer_size(this, hwparams, 0) < 0 ) { /* Failed to set desired buffer size, do the best you can... */ - if ( ALSA_set_period_size(this, hwparams, 1) < 0 ) { - ALSA_CloseDevice(this); + status = ALSA_set_period_size(this, hwparams, 1); + if (status < 0) { return SDL_SetError("Couldn't set hardware audio parameters: %s", ALSA_snd_strerror(status)); } } @@ -607,26 +675,22 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_sw_params_alloca(&swparams); status = ALSA_snd_pcm_sw_params_current(pcm_handle, swparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't get software config: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, this->spec.samples); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("Couldn't set minimum available samples: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, 1); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("ALSA: Couldn't set start threshold: %s", ALSA_snd_strerror(status)); } status = ALSA_snd_pcm_sw_params(pcm_handle, swparams); if (status < 0) { - ALSA_CloseDevice(this); return SDL_SetError("Couldn't set software audio parameters: %s", ALSA_snd_strerror(status)); } @@ -635,13 +699,14 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - ALSA_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); /* Switch to blocking mode for playback */ ALSA_snd_pcm_nonblock(pcm_handle, 0); @@ -650,9 +715,238 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; } +typedef struct ALSA_Device +{ + char *name; + SDL_bool iscapture; + struct ALSA_Device *next; +} ALSA_Device; + +static void +add_device(const int iscapture, const char *name, void *hint, ALSA_Device **pSeen) +{ + ALSA_Device *dev = SDL_malloc(sizeof (ALSA_Device)); + char *desc = ALSA_snd_device_name_get_hint(hint, "DESC"); + char *handle = NULL; + char *ptr; + + if (!desc) { + SDL_free(dev); + return; + } else if (!dev) { + free(desc); + return; + } + + SDL_assert(name != NULL); + + /* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output". + just chop the extra lines off, this seems to get a reasonable device + name without extra details. */ + if ((ptr = strchr(desc, '\n')) != NULL) { + *ptr = '\0'; + } + + /*printf("ALSA: adding %s device '%s' (%s)\n", iscapture ? "capture" : "output", name, desc);*/ + + handle = SDL_strdup(name); + if (!handle) { + free(desc); + SDL_free(dev); + return; + } + + SDL_AddAudioDevice(iscapture, desc, handle); + free(desc); + + dev->name = handle; + dev->iscapture = iscapture; + dev->next = *pSeen; + *pSeen = dev; +} + + +static SDL_atomic_t ALSA_hotplug_shutdown; +static SDL_Thread *ALSA_hotplug_thread; + +static int SDLCALL +ALSA_HotplugThread(void *arg) +{ + SDL_sem *first_run_semaphore = (SDL_sem *) arg; + ALSA_Device *devices = NULL; + ALSA_Device *next; + ALSA_Device *dev; + Uint32 ticks; + + while (!SDL_AtomicGet(&ALSA_hotplug_shutdown)) { + void **hints = NULL; + if (ALSA_snd_device_name_hint(-1, "pcm", &hints) != -1) { + ALSA_Device *unseen = devices; + ALSA_Device *seen = NULL; + ALSA_Device *prev; + int i, j; + const char *match = NULL; + int bestmatch = 0xFFFF; + size_t match_len = 0; + int defaultdev = -1; + static const char * const prefixes[] = { + "hw:", "sysdefault:", "default:", NULL + }; + + /* Apparently there are several different ways that ALSA lists + actual hardware. It could be prefixed with "hw:" or "default:" + or "sysdefault:" and maybe others. Go through the list and see + if we can find a preferred prefix for the system. */ + for (i = 0; hints[i]; i++) { + char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME"); + if (!name) { + continue; + } + + /* full name, not a prefix */ + if ((defaultdev == -1) && (SDL_strcmp(name, "default") == 0)) { + defaultdev = i; + } + + for (j = 0; prefixes[j]; j++) { + const char *prefix = prefixes[j]; + const size_t prefixlen = SDL_strlen(prefix); + if (SDL_strncmp(name, prefix, prefixlen) == 0) { + if (j < bestmatch) { + bestmatch = j; + match = prefix; + match_len = prefixlen; + } + } + } + + free(name); + } + + /* look through the list of device names to find matches */ + for (i = 0; hints[i]; i++) { + char *name; + + /* if we didn't find a device name prefix we like at all... */ + if ((!match) && (defaultdev != i)) { + continue; /* ...skip anything that isn't the default device. */ + } + + name = ALSA_snd_device_name_get_hint(hints[i], "NAME"); + if (!name) { + continue; + } + + /* only want physical hardware interfaces */ + if (!match || (SDL_strncmp(name, match, match_len) == 0)) { + char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID"); + const SDL_bool isoutput = (ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0); + const SDL_bool isinput = (ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0); + SDL_bool have_output = SDL_FALSE; + SDL_bool have_input = SDL_FALSE; + + free(ioid); + + if (!isoutput && !isinput) { + free(name); + continue; + } + + prev = NULL; + for (dev = unseen; dev; dev = next) { + next = dev->next; + if ( (SDL_strcmp(dev->name, name) == 0) && (((isinput) && dev->iscapture) || ((isoutput) && !dev->iscapture)) ) { + if (prev) { + prev->next = next; + } else { + unseen = next; + } + dev->next = seen; + seen = dev; + if (isinput) have_input = SDL_TRUE; + if (isoutput) have_output = SDL_TRUE; + } else { + prev = dev; + } + } + + if (isinput && !have_input) { + add_device(SDL_TRUE, name, hints[i], &seen); + } + if (isoutput && !have_output) { + add_device(SDL_FALSE, name, hints[i], &seen); + } + } + + free(name); + } + + ALSA_snd_device_name_free_hint(hints); + + devices = seen; /* now we have a known-good list of attached devices. */ + + /* report anything still in unseen as removed. */ + for (dev = unseen; dev; dev = next) { + /*printf("ALSA: removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/ + next = dev->next; + SDL_RemoveAudioDevice(dev->iscapture, dev->name); + SDL_free(dev->name); + SDL_free(dev); + } + } + + /* On first run, tell ALSA_DetectDevices() that we have a complete device list so it can return. */ + if (first_run_semaphore) { + SDL_SemPost(first_run_semaphore); + first_run_semaphore = NULL; /* let other thread clean it up. */ + } + + /* Block awhile before checking again, unless we're told to stop. */ + ticks = SDL_GetTicks() + 5000; + while (!SDL_AtomicGet(&ALSA_hotplug_shutdown) && !SDL_TICKS_PASSED(SDL_GetTicks(), ticks)) { + SDL_Delay(100); + } + } + + /* Shutting down! Clean up any data we've gathered. */ + for (dev = devices; dev; dev = next) { + /*printf("ALSA: at shutdown, removing %s device '%s'\n", dev->iscapture ? "capture" : "output", dev->name);*/ + next = dev->next; + SDL_free(dev->name); + SDL_free(dev); + } + + return 0; +} + +static void +ALSA_DetectDevices(void) +{ + /* Start the device detection thread here, wait for an initial iteration to complete. */ + SDL_sem *semaphore = SDL_CreateSemaphore(0); + if (!semaphore) { + return; /* oh well. */ + } + + SDL_AtomicSet(&ALSA_hotplug_shutdown, 0); + + ALSA_hotplug_thread = SDL_CreateThread(ALSA_HotplugThread, "SDLHotplugALSA", semaphore); + if (ALSA_hotplug_thread) { + SDL_SemWait(semaphore); /* wait for the first iteration to finish. */ + } + + SDL_DestroySemaphore(semaphore); +} + static void ALSA_Deinitialize(void) { + if (ALSA_hotplug_thread != NULL) { + SDL_AtomicSet(&ALSA_hotplug_shutdown, 1); + SDL_WaitThread(ALSA_hotplug_thread, NULL); + ALSA_hotplug_thread = NULL; + } + UnloadALSALibrary(); } @@ -664,13 +958,17 @@ ALSA_Init(SDL_AudioDriverImpl * impl) } /* Set the function pointers */ + impl->DetectDevices = ALSA_DetectDevices; impl->OpenDevice = ALSA_OpenDevice; impl->WaitDevice = ALSA_WaitDevice; impl->GetDeviceBuf = ALSA_GetDeviceBuf; impl->PlayDevice = ALSA_PlayDevice; impl->CloseDevice = ALSA_CloseDevice; impl->Deinitialize = ALSA_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: Add device enum! */ + impl->CaptureFromDevice = ALSA_CaptureFromDevice; + impl->FlushCapture = ALSA_FlushCapture; + + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/android/SDL_androidaudio.c b/Engine/lib/sdl/src/audio/android/SDL_androidaudio.c index 4a4faadcf..96f6d631a 100644 --- a/Engine/lib/sdl/src/audio/android/SDL_androidaudio.c +++ b/Engine/lib/sdl/src/audio/android/SDL_androidaudio.c @@ -24,6 +24,7 @@ /* Output audio to Android */ +#include "SDL_assert.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "SDL_androidaudio.h" @@ -33,23 +34,22 @@ #include static SDL_AudioDevice* audioDevice = NULL; +static SDL_AudioDevice* captureDevice = NULL; static int -AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_AudioFormat test_format; + SDL_assert((captureDevice == NULL) || !iscapture); + SDL_assert((audioDevice == NULL) || iscapture); + if (iscapture) { - /* TODO: implement capture */ - return SDL_SetError("Capture not supported on Android"); + captureDevice = this; + } else { + audioDevice = this; } - if (audioDevice != NULL) { - return SDL_SetError("Only one audio device at a time please!"); - } - - audioDevice = this; - this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); @@ -82,100 +82,137 @@ AndroidAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.freq = 48000; } - /* TODO: pass in/return a (Java) device ID, also whether we're opening for input or output */ - this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples); - SDL_CalculateAudioSpec(&this->spec); + /* TODO: pass in/return a (Java) device ID */ + this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples); if (this->spec.samples == 0) { /* Init failed? */ return SDL_SetError("Java-side initialization failed!"); } + SDL_CalculateAudioSpec(&this->spec); + return 0; } static void -AndroidAUD_PlayDevice(_THIS) +ANDROIDAUDIO_PlayDevice(_THIS) { Android_JNI_WriteAudioBuffer(); } static Uint8 * -AndroidAUD_GetDeviceBuf(_THIS) +ANDROIDAUDIO_GetDeviceBuf(_THIS) { return Android_JNI_GetAudioBuffer(); } +static int +ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + return Android_JNI_CaptureAudioBuffer(buffer, buflen); +} + static void -AndroidAUD_CloseDevice(_THIS) +ANDROIDAUDIO_FlushCapture(_THIS) +{ + Android_JNI_FlushCapturedAudio(); +} + +static void +ANDROIDAUDIO_CloseDevice(_THIS) { /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread so it's safe to terminate the Java side buffer and AudioTrack */ - Android_JNI_CloseAudioDevice(); - - if (audioDevice == this) { - if (audioDevice->hidden != NULL) { - SDL_free(this->hidden); - this->hidden = NULL; - } + Android_JNI_CloseAudioDevice(this->iscapture); + if (this->iscapture) { + SDL_assert(captureDevice == this); + captureDevice = NULL; + } else { + SDL_assert(audioDevice == this); audioDevice = NULL; } + SDL_free(this->hidden); } static int -AndroidAUD_Init(SDL_AudioDriverImpl * impl) +ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ - impl->OpenDevice = AndroidAUD_OpenDevice; - impl->PlayDevice = AndroidAUD_PlayDevice; - impl->GetDeviceBuf = AndroidAUD_GetDeviceBuf; - impl->CloseDevice = AndroidAUD_CloseDevice; + impl->OpenDevice = ANDROIDAUDIO_OpenDevice; + impl->PlayDevice = ANDROIDAUDIO_PlayDevice; + impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf; + impl->CloseDevice = ANDROIDAUDIO_CloseDevice; + impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice; + impl->FlushCapture = ANDROIDAUDIO_FlushCapture; /* and the capabilities */ - impl->HasCaptureSupport = 0; /* TODO */ + impl->HasCaptureSupport = SDL_TRUE; impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; return 1; /* this audio target is available. */ } -AudioBootStrap ANDROIDAUD_bootstrap = { - "android", "SDL Android audio driver", AndroidAUD_Init, 0 +AudioBootStrap ANDROIDAUDIO_bootstrap = { + "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0 }; /* Pause (block) all non already paused audio devices by taking their mixer lock */ -void AndroidAUD_PauseDevices(void) +void ANDROIDAUDIO_PauseDevices(void) { /* TODO: Handle multiple devices? */ struct SDL_PrivateAudioData *private; if(audioDevice != NULL && audioDevice->hidden != NULL) { private = (struct SDL_PrivateAudioData *) audioDevice->hidden; - if (audioDevice->paused) { + if (SDL_AtomicGet(&audioDevice->paused)) { /* The device is already paused, leave it alone */ private->resume = SDL_FALSE; } else { SDL_LockMutex(audioDevice->mixer_lock); - audioDevice->paused = SDL_TRUE; + SDL_AtomicSet(&audioDevice->paused, 1); + private->resume = SDL_TRUE; + } + } + + if(captureDevice != NULL && captureDevice->hidden != NULL) { + private = (struct SDL_PrivateAudioData *) captureDevice->hidden; + if (SDL_AtomicGet(&captureDevice->paused)) { + /* The device is already paused, leave it alone */ + private->resume = SDL_FALSE; + } + else { + SDL_LockMutex(captureDevice->mixer_lock); + SDL_AtomicSet(&captureDevice->paused, 1); private->resume = SDL_TRUE; } } } /* Resume (unblock) all non already paused audio devices by releasing their mixer lock */ -void AndroidAUD_ResumeDevices(void) +void ANDROIDAUDIO_ResumeDevices(void) { /* TODO: Handle multiple devices? */ struct SDL_PrivateAudioData *private; if(audioDevice != NULL && audioDevice->hidden != NULL) { private = (struct SDL_PrivateAudioData *) audioDevice->hidden; if (private->resume) { - audioDevice->paused = SDL_FALSE; + SDL_AtomicSet(&audioDevice->paused, 0); private->resume = SDL_FALSE; SDL_UnlockMutex(audioDevice->mixer_lock); } } + + if(captureDevice != NULL && captureDevice->hidden != NULL) { + private = (struct SDL_PrivateAudioData *) captureDevice->hidden; + if (private->resume) { + SDL_AtomicSet(&captureDevice->paused, 0); + private->resume = SDL_FALSE; + SDL_UnlockMutex(captureDevice->mixer_lock); + } + } } diff --git a/Engine/lib/sdl/src/audio/android/SDL_androidaudio.h b/Engine/lib/sdl/src/audio/android/SDL_androidaudio.h index 639be9c08..133615302 100644 --- a/Engine/lib/sdl/src/audio/android/SDL_androidaudio.h +++ b/Engine/lib/sdl/src/audio/android/SDL_androidaudio.h @@ -34,8 +34,6 @@ struct SDL_PrivateAudioData int resume; }; -static void AndroidAUD_CloseDevice(_THIS); - #endif /* _SDL_androidaudio_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/audio/arts/SDL_artsaudio.c b/Engine/lib/sdl/src/audio/arts/SDL_artsaudio.c index 5d40cd14e..6054e36b6 100644 --- a/Engine/lib/sdl/src/audio/arts/SDL_artsaudio.c +++ b/Engine/lib/sdl/src/audio/arts/SDL_artsaudio.c @@ -32,7 +32,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_artsaudio.h" @@ -186,13 +185,6 @@ ARTS_PlayDevice(_THIS) #endif } -static void -ARTS_WaitDone(_THIS) -{ - /* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */ -} - - static Uint8 * ARTS_GetDeviceBuf(_THIS) { @@ -203,17 +195,12 @@ ARTS_GetDeviceBuf(_THIS) static void ARTS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - SDL_NAME(arts_close_stream) (this->hidden->stream); - this->hidden->stream = 0; - } - SDL_NAME(arts_free) (); - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->stream) { + SDL_NAME(arts_close_stream) (this->hidden->stream); } + SDL_NAME(arts_free) (); + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -241,7 +228,7 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ for (test_format = SDL_FirstAudioFormat(this->spec.format); @@ -267,19 +254,16 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - ARTS_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; if ((rc = SDL_NAME(arts_init) ()) != 0) { - ARTS_CloseDevice(this); return SDL_SetError("Unable to initialize ARTS: %s", SDL_NAME(arts_error_text) (rc)); } if (!ARTS_Suspend()) { - ARTS_CloseDevice(this); return SDL_SetError("ARTS can not open audio device"); } @@ -297,7 +281,6 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Determine the power of two of the fragment size */ for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); if ((0x01 << frag_spec) != this->spec.size) { - ARTS_CloseDevice(this); return SDL_SetError("Fragment size must be a power of two"); } frag_spec |= 0x00020000; /* two fragments, for low latency */ @@ -316,9 +299,8 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - ARTS_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); @@ -367,7 +349,6 @@ ARTS_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = ARTS_WaitDevice; impl->GetDeviceBuf = ARTS_GetDeviceBuf; impl->CloseDevice = ARTS_CloseDevice; - impl->WaitDone = ARTS_WaitDone; impl->Deinitialize = ARTS_Deinitialize; impl->OnlyHasDefaultOutputDevice = 1; diff --git a/Engine/lib/sdl/src/audio/bsd/SDL_bsdaudio.c b/Engine/lib/sdl/src/audio/bsd/SDL_bsdaudio.c index eeb257371..6a970b9c7 100644 --- a/Engine/lib/sdl/src/audio/bsd/SDL_bsdaudio.c +++ b/Engine/lib/sdl/src/audio/bsd/SDL_bsdaudio.c @@ -38,7 +38,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_bsdaudio.h" @@ -63,13 +62,17 @@ BSDAUDIO_Status(_THIS) #ifdef DEBUG_AUDIO /* *INDENT-OFF* */ audio_info_t info; + const audio_prinfo *prinfo; if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { fprintf(stderr, "AUDIO_GETINFO failed.\n"); return; } + + prinfo = this->iscapture ? &info.play : &info.record; + fprintf(stderr, "\n" - "[play/record info]\n" + "[%s info]\n" "buffer size : %d bytes\n" "sample rate : %i Hz\n" "channels : %i\n" @@ -83,18 +86,19 @@ BSDAUDIO_Status(_THIS) "waiting : %s\n" "active : %s\n" "", - info.play.buffer_size, - info.play.sample_rate, - info.play.channels, - info.play.precision, - info.play.encoding, - info.play.seek, - info.play.samples, - info.play.eof, - info.play.pause ? "yes" : "no", - info.play.error ? "yes" : "no", - info.play.waiting ? "yes" : "no", - info.play.active ? "yes" : "no"); + this->iscapture ? "record" : "play", + prinfo->buffer_size, + prinfo->sample_rate, + prinfo->channels, + prinfo->precision, + prinfo->encoding, + prinfo->seek, + prinfo->samples, + prinfo->eof, + prinfo->pause ? "yes" : "no", + prinfo->error ? "yes" : "no", + prinfo->waiting ? "yes" : "no", + prinfo->active ? "yes" : "no"); fprintf(stderr, "\n" "[audio info]\n" @@ -182,11 +186,15 @@ BSDAUDIO_PlayDevice(_THIS) break; } - if (p < written +#ifdef DEBUG_AUDIO + fprintf(stderr, "Wrote %d bytes of audio data\n", written); +#endif + + if (p < this->hidden->mixlen || ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) { SDL_Delay(1); /* Let a little CPU time go by */ } - } while (p < written); + } while (p < this->hidden->mixlen); /* If timer synchronization is enabled, set the next write frame */ if (this->hidden->frame_ticks) { @@ -197,9 +205,6 @@ BSDAUDIO_PlayDevice(_THIS) if (written < 0) { SDL_OpenedAudioDeviceDisconnected(this); } -#ifdef DEBUG_AUDIO - fprintf(stderr, "Wrote %d bytes of audio data\n", written); -#endif } static Uint8 * @@ -208,27 +213,74 @@ BSDAUDIO_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } + +static int +BSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen) +{ + Uint8 *buffer = (Uint8 *) _buffer; + int br, p = 0; + + /* Write the audio data, checking for EAGAIN on broken audio drivers */ + do { + br = read(this->hidden->audio_fd, buffer + p, buflen - p); + if (br > 0) + p += br; + if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) { + /* Non recoverable error has occurred. It should be reported!!! */ + perror("audio"); + return p ? p : -1; + } + +#ifdef DEBUG_AUDIO + fprintf(stderr, "Captured %d bytes of audio data\n", br); +#endif + + if (p < buflen + || ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) { + SDL_Delay(1); /* Let a little CPU time go by */ + } + } while (p < buflen); +} + +static void +BSDAUDIO_FlushCapture(_THIS) +{ + audio_info_t info; + size_t remain; + Uint8 buf[512]; + + if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) { + return; /* oh well. */ + } + + remain = (size_t) (info.record.samples * (SDL_AUDIO_BITSIZE(this->spec.format) / 8)); + while (remain > 0) { + const size_t len = SDL_min(sizeof (buf), remain); + const int br = read(this->hidden->audio_fd, buf, len); + if (br <= 0) { + return; /* oh well. */ + } + remain -= br; + } +} + static void BSDAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { - const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); + const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT; SDL_AudioFormat format = 0; audio_info_t info; + audio_prinfo *prinfo = iscapture ? &info.play : &info.record; /* We don't care what the devname is...we'll try to open anything. */ /* ...but default to first name in the list... */ @@ -245,7 +297,7 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); @@ -259,9 +311,8 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Set to play mode */ - info.mode = AUMODE_PLAY; + info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) { - BSDAUDIO_CloseDevice(this); return SDL_SetError("Couldn't put device into play mode"); } @@ -270,28 +321,28 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) format; format = SDL_NextAudioFormat()) { switch (format) { case AUDIO_U8: - info.play.encoding = AUDIO_ENCODING_ULINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_ULINEAR; + prinfo->precision = 8; break; case AUDIO_S8: - info.play.encoding = AUDIO_ENCODING_SLINEAR; - info.play.precision = 8; + prinfo->encoding = AUDIO_ENCODING_SLINEAR; + prinfo->precision = 8; break; case AUDIO_S16LSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; + prinfo->precision = 16; break; case AUDIO_S16MSB: - info.play.encoding = AUDIO_ENCODING_SLINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; + prinfo->precision = 16; break; case AUDIO_U16LSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_LE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE; + prinfo->precision = 16; break; case AUDIO_U16MSB: - info.play.encoding = AUDIO_ENCODING_ULINEAR_BE; - info.play.precision = 16; + prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE; + prinfo->precision = 16; break; default: continue; @@ -303,33 +354,34 @@ BSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!format) { - BSDAUDIO_CloseDevice(this); return SDL_SetError("No supported encoding for 0x%x", this->spec.format); } this->spec.format = format; AUDIO_INITINFO(&info); - info.play.channels = this->spec.channels; + prinfo->channels = this->spec.channels; if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) { this->spec.channels = 1; } AUDIO_INITINFO(&info); - info.play.sample_rate = this->spec.freq; + prinfo->sample_rate = this->spec.freq; info.blocksize = this->spec.size; info.hiwat = 5; info.lowat = 3; (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info); (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info); - this->spec.freq = info.play.sample_rate; - /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - BSDAUDIO_CloseDevice(this); - return SDL_OutOfMemory(); + this->spec.freq = prinfo->sample_rate; + + if (!iscapture) { + /* Allocate mixing buffer */ + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); BSDAUDIO_Status(this); @@ -347,7 +399,10 @@ BSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = BSDAUDIO_WaitDevice; impl->GetDeviceBuf = BSDAUDIO_GetDeviceBuf; impl->CloseDevice = BSDAUDIO_CloseDevice; + impl->CaptureFromDevice = BSDAUDIO_CaptureFromDevice; + impl->FlushCapture = BSDAUDIO_FlushCapture; + impl->HasCaptureSupport = SDL_TRUE; impl->AllowsArbitraryDeviceNames = 1; return 1; /* this audio target is available. */ diff --git a/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.h b/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.h index 577f9fb32..b7e5b8e21 100644 --- a/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.h +++ b/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.h @@ -33,9 +33,11 @@ #include #include #else -#include +#import +#import #endif +#include #include /* Hidden "this" pointer for the audio functions */ @@ -43,13 +45,21 @@ struct SDL_PrivateAudioData { - AudioUnit audioUnit; - int audioUnitOpened; + SDL_Thread *thread; + AudioQueueRef audioQueue; + AudioQueueBufferRef audioBuffer[2]; void *buffer; UInt32 bufferOffset; UInt32 bufferSize; + AudioStreamBasicDescription strdesc; + SDL_sem *ready_semaphore; + char *thread_error; + SDL_atomic_t shutdown; #if MACOSX_COREAUDIO AudioDeviceID deviceID; +#else + SDL_bool interrupted; + CFTypeRef interruption_listener; #endif }; diff --git a/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m b/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m new file mode 100644 index 000000000..85129050f --- /dev/null +++ b/Engine/lib/sdl/src/audio/coreaudio/SDL_coreaudio.m @@ -0,0 +1,849 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_COREAUDIO + +/* !!! FIXME: clean out some of the macro salsa in here. */ + +#include "SDL_audio.h" +#include "../SDL_audio_c.h" +#include "../SDL_sysaudio.h" +#include "SDL_coreaudio.h" +#include "SDL_assert.h" +#include "../../thread/SDL_systhread.h" + +#define DEBUG_COREAUDIO 0 + +#define CHECK_RESULT(msg) \ + if (result != noErr) { \ + SDL_SetError("CoreAudio error (%s): %d", msg, (int) result); \ + return 0; \ + } + +#if MACOSX_COREAUDIO +static const AudioObjectPropertyAddress devlist_address = { + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; + +typedef void (*addDevFn)(const char *name, const int iscapture, AudioDeviceID devId, void *data); + +typedef struct AudioDeviceList +{ + AudioDeviceID devid; + SDL_bool alive; + struct AudioDeviceList *next; +} AudioDeviceList; + +static AudioDeviceList *output_devs = NULL; +static AudioDeviceList *capture_devs = NULL; + +static SDL_bool +add_to_internal_dev_list(const int iscapture, AudioDeviceID devId) +{ + AudioDeviceList *item = (AudioDeviceList *) SDL_malloc(sizeof (AudioDeviceList)); + if (item == NULL) { + return SDL_FALSE; + } + item->devid = devId; + item->alive = SDL_TRUE; + item->next = iscapture ? capture_devs : output_devs; + if (iscapture) { + capture_devs = item; + } else { + output_devs = item; + } + + return SDL_TRUE; +} + +static void +addToDevList(const char *name, const int iscapture, AudioDeviceID devId, void *data) +{ + if (add_to_internal_dev_list(iscapture, devId)) { + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); + } +} + +static void +build_device_list(int iscapture, addDevFn addfn, void *addfndata) +{ + OSStatus result = noErr; + UInt32 size = 0; + AudioDeviceID *devs = NULL; + UInt32 i = 0; + UInt32 max = 0; + + result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size); + if (result != kAudioHardwareNoError) + return; + + devs = (AudioDeviceID *) alloca(size); + if (devs == NULL) + return; + + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &devlist_address, 0, NULL, &size, devs); + if (result != kAudioHardwareNoError) + return; + + max = size / sizeof (AudioDeviceID); + for (i = 0; i < max; i++) { + CFStringRef cfstr = NULL; + char *ptr = NULL; + AudioDeviceID dev = devs[i]; + AudioBufferList *buflist = NULL; + int usable = 0; + CFIndex len = 0; + 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) + continue; + + buflist = (AudioBufferList *) SDL_malloc(size); + if (buflist == NULL) + continue; + + result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, + &size, buflist); + + if (result == noErr) { + UInt32 j; + for (j = 0; j < buflist->mNumberBuffers; j++) { + if (buflist->mBuffers[j].mNumberChannels > 0) { + usable = 1; + break; + } + } + } + + SDL_free(buflist); + + if (!usable) + continue; + + + size = sizeof (CFStringRef); + result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr); + if (result != kAudioHardwareNoError) + continue; + + len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr), + kCFStringEncodingUTF8); + + ptr = (char *) SDL_malloc(len + 1); + usable = ((ptr != NULL) && + (CFStringGetCString + (cfstr, ptr, len + 1, kCFStringEncodingUTF8))); + + CFRelease(cfstr); + + if (usable) { + len = strlen(ptr); + /* Some devices have whitespace at the end...trim it. */ + while ((len > 0) && (ptr[len - 1] == ' ')) { + len--; + } + usable = (len > 0); + } + + if (usable) { + ptr[len] = '\0'; + +#if DEBUG_COREAUDIO + printf("COREAUDIO: Found %s device #%d: '%s' (devid %d)\n", + ((iscapture) ? "capture" : "output"), + (int) i, ptr, (int) dev); +#endif + addfn(ptr, iscapture, dev, addfndata); + } + SDL_free(ptr); /* addfn() would have copied the string. */ + } +} + +static void +free_audio_device_list(AudioDeviceList **list) +{ + AudioDeviceList *item = *list; + while (item) { + AudioDeviceList *next = item->next; + SDL_free(item); + item = next; + } + *list = NULL; +} + +static void +COREAUDIO_DetectDevices(void) +{ + build_device_list(SDL_TRUE, addToDevList, NULL); + build_device_list(SDL_FALSE, addToDevList, NULL); +} + +static void +build_device_change_list(const char *name, const int iscapture, AudioDeviceID devId, void *data) +{ + AudioDeviceList **list = (AudioDeviceList **) data; + AudioDeviceList *item; + for (item = *list; item != NULL; item = item->next) { + if (item->devid == devId) { + item->alive = SDL_TRUE; + return; + } + } + + add_to_internal_dev_list(iscapture, devId); /* new device, add it. */ + SDL_AddAudioDevice(iscapture, name, (void *) ((size_t) devId)); +} + +static 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; + } + + 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 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 + + +static int open_playback_devices = 0; +static int open_capture_devices = 0; + +#if !MACOSX_COREAUDIO + +static void interruption_begin(_THIS) +{ + if (this != NULL && this->hidden->audioQueue != NULL) { + this->hidden->interrupted = SDL_TRUE; + AudioQueuePause(this->hidden->audioQueue); + } +} + +static void interruption_end(_THIS) +{ + if (this != NULL && this->hidden != NULL && this->hidden->audioQueue != NULL + && this->hidden->interrupted) { + this->hidden->interrupted = SDL_FALSE; + AudioQueueStart(this->hidden->audioQueue, NULL); + } +} + +@interface SDLInterruptionListener : NSObject + +@property (nonatomic, assign) SDL_AudioDevice *device; + +@end + +@implementation SDLInterruptionListener + +- (void)audioSessionInterruption:(NSNotification *)note +{ + @synchronized (self) { + NSNumber *type = note.userInfo[AVAudioSessionInterruptionTypeKey]; + if (type.unsignedIntegerValue == AVAudioSessionInterruptionTypeBegan) { + interruption_begin(self.device); + } else { + interruption_end(self.device); + } + } +} + +- (void)applicationBecameActive:(NSNotification *)note +{ + @synchronized (self) { + interruption_end(self.device); + } +} + +@end + +static BOOL update_audio_session(_THIS, SDL_bool open) +{ + @autoreleasepool { + AVAudioSession *session = [AVAudioSession sharedInstance]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + NSString *category; + NSError *err = nil; + + if (open_playback_devices && open_capture_devices) { + category = AVAudioSessionCategoryPlayAndRecord; + } else if (open_capture_devices) { + category = AVAudioSessionCategoryRecord; + } else { + /* Set category to ambient so that other music continues playing. + You can change this at runtime in your own code if you need different + behavior. If this is common, we can add an SDL hint for this. */ + category = AVAudioSessionCategoryAmbient; + } + + if (![session setCategory:category error:&err]) { + NSString *desc = err.description; + SDL_SetError("Could not set Audio Session category: %s", desc.UTF8String); + return NO; + } + + if (open_playback_devices + open_capture_devices == 1) { + if (![session setActive:YES error:&err]) { + NSString *desc = err.description; + SDL_SetError("Could not activate Audio Session: %s", desc.UTF8String); + return NO; + } + } else if (!open_playback_devices && !open_capture_devices) { + [session setActive:NO error:nil]; + } + + if (open) { + SDLInterruptionListener *listener = [SDLInterruptionListener new]; + listener.device = this; + + [center addObserver:listener + selector:@selector(audioSessionInterruption:) + name:AVAudioSessionInterruptionNotification + object:session]; + + /* An interruption end notification is not guaranteed to be sent if + we were previously interrupted... resuming if needed when the app + becomes active seems to be the way to go. */ + [center addObserver:listener + selector:@selector(applicationBecameActive:) + name:UIApplicationDidBecomeActiveNotification + object:session]; + + [center addObserver:listener + selector:@selector(applicationBecameActive:) + name:UIApplicationWillEnterForegroundNotification + object:session]; + + this->hidden->interruption_listener = CFBridgingRetain(listener); + } else { + if (this->hidden->interruption_listener != NULL) { + SDLInterruptionListener *listener = nil; + listener = (SDLInterruptionListener *) CFBridgingRelease(this->hidden->interruption_listener); + @synchronized (listener) { + listener.device = NULL; + } + [center removeObserver:listener]; + } + } + } + + return YES; +} +#endif + + +/* The AudioQueue callback */ +static void +outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData; + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { + /* Supply silence if audio is enabled and not paused */ + SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity); + } else { + UInt32 remaining = inBuffer->mAudioDataBytesCapacity; + Uint8 *ptr = (Uint8 *) inBuffer->mAudioData; + + while (remaining > 0) { + UInt32 len; + if (this->hidden->bufferOffset >= this->hidden->bufferSize) { + /* Generate the data */ + SDL_LockMutex(this->mixer_lock); + (*this->spec.callback)(this->spec.userdata, + this->hidden->buffer, this->hidden->bufferSize); + SDL_UnlockMutex(this->mixer_lock); + this->hidden->bufferOffset = 0; + } + + len = this->hidden->bufferSize - this->hidden->bufferOffset; + if (len > remaining) { + len = remaining; + } + SDL_memcpy(ptr, (char *)this->hidden->buffer + + this->hidden->bufferOffset, len); + ptr = ptr + len; + remaining -= len; + this->hidden->bufferOffset += len; + } + } + + if (!SDL_AtomicGet(&this->hidden->shutdown)) { + AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL); + } + + inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity; +} + +static void +inputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, + const AudioTimeStamp *inStartTime, UInt32 inNumberPacketDescriptions, + const AudioStreamPacketDescription *inPacketDescs ) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) inUserData; + if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) { /* ignore unless we're active. */ + const Uint8 *ptr = (const Uint8 *) inBuffer->mAudioData; + UInt32 remaining = inBuffer->mAudioDataByteSize; + while (remaining > 0) { + UInt32 len = this->hidden->bufferSize - this->hidden->bufferOffset; + if (len > remaining) { + len = remaining; + } + + SDL_memcpy((char *)this->hidden->buffer + this->hidden->bufferOffset, ptr, len); + ptr += len; + remaining -= len; + this->hidden->bufferOffset += len; + + if (this->hidden->bufferOffset >= this->hidden->bufferSize) { + SDL_LockMutex(this->mixer_lock); + (*this->spec.callback)(this->spec.userdata, this->hidden->buffer, this->hidden->bufferSize); + SDL_UnlockMutex(this->mixer_lock); + this->hidden->bufferOffset = 0; + } + } + } + + if (!SDL_AtomicGet(&this->hidden->shutdown)) { + AudioQueueEnqueueBuffer(this->hidden->audioQueue, inBuffer, 0, NULL); + } +} + + +#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 (!SDL_AtomicGet(&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) +{ + const SDL_bool iscapture = this->iscapture; + int i; + +/* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */ +/* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */ +#if MACOSX_COREAUDIO + /* Fire a callback if the device stops being "alive" (disconnected, etc). */ + AudioObjectRemovePropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); +#endif + +#if !MACOSX_COREAUDIO + update_audio_session(this, SDL_FALSE); +#endif + + if (this->hidden->thread) { + SDL_AtomicSet(&this->hidden->shutdown, 1); + SDL_WaitThread(this->hidden->thread, NULL); + } + + if (this->hidden->audioQueue) { + for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) { + if (this->hidden->audioBuffer[i]) { + AudioQueueFreeBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i]); + } + } + AudioQueueDispose(this->hidden->audioQueue, 1); + } + + if (this->hidden->ready_semaphore) { + SDL_DestroySemaphore(this->hidden->ready_semaphore); + } + + SDL_free(this->hidden->thread_error); + SDL_free(this->hidden->buffer); + SDL_free(this->hidden); + + if (iscapture) { + open_capture_devices--; + } else { + open_playback_devices--; + } +} + +#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_audioqueue(_THIS) +{ + const AudioStreamBasicDescription *strdesc = &this->hidden->strdesc; + const int iscapture = this->iscapture; + OSStatus result; + int i; + + SDL_assert(CFRunLoopGetCurrent() != NULL); + + if (iscapture) { + result = AudioQueueNewInput(strdesc, inputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue); + CHECK_RESULT("AudioQueueNewInput"); + } else { + result = AudioQueueNewOutput(strdesc, outputCallback, this, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &this->hidden->audioQueue); + CHECK_RESULT("AudioQueueNewOutput"); + } + +#if MACOSX_COREAUDIO +{ + const AudioObjectPropertyAddress prop = { + kAudioDevicePropertyDeviceUID, + iscapture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + CFStringRef devuid; + UInt32 devuidsize = sizeof (devuid); + result = AudioObjectGetPropertyData(this->hidden->deviceID, &prop, 0, NULL, &devuidsize, &devuid); + CHECK_RESULT("AudioObjectGetPropertyData (kAudioDevicePropertyDeviceUID)"); + result = AudioQueueSetProperty(this->hidden->audioQueue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize); + CHECK_RESULT("AudioQueueSetProperty (kAudioQueueProperty_CurrentDevice)"); + + /* !!! FIXME: what does iOS do when a bluetooth audio device vanishes? Headphones unplugged? */ + /* !!! FIXME: (we only do a "default" device on iOS right now...can we do more?) */ + /* Fire a callback if the device stops being "alive" (disconnected, etc). */ + AudioObjectAddPropertyListener(this->hidden->deviceID, &alive_address, device_unplugged, this); +} +#endif + + /* Calculate the final parameters for this audio specification */ + SDL_CalculateAudioSpec(&this->spec); + + /* Allocate a sample buffer */ + this->hidden->bufferSize = this->spec.size; + this->hidden->bufferOffset = iscapture ? 0 : this->hidden->bufferSize; + + this->hidden->buffer = SDL_malloc(this->hidden->bufferSize); + if (this->hidden->buffer == NULL) { + SDL_OutOfMemory(); + return 0; + } + + for (i = 0; i < SDL_arraysize(this->hidden->audioBuffer); i++) { + result = AudioQueueAllocateBuffer(this->hidden->audioQueue, this->spec.size, &this->hidden->audioBuffer[i]); + CHECK_RESULT("AudioQueueAllocateBuffer"); + SDL_memset(this->hidden->audioBuffer[i]->mAudioData, this->spec.silence, this->hidden->audioBuffer[i]->mAudioDataBytesCapacity); + this->hidden->audioBuffer[i]->mAudioDataByteSize = this->hidden->audioBuffer[i]->mAudioDataBytesCapacity; + result = AudioQueueEnqueueBuffer(this->hidden->audioQueue, this->hidden->audioBuffer[i], 0, NULL); + CHECK_RESULT("AudioQueueEnqueueBuffer"); + } + + result = AudioQueueStart(this->hidden->audioQueue, NULL); + CHECK_RESULT("AudioQueueStart"); + + /* We're running! */ + return 1; +} + +static int +audioqueue_thread(void *arg) +{ + SDL_AudioDevice *this = (SDL_AudioDevice *) arg; + const int rc = prepare_audioqueue(this); + if (!rc) { + this->hidden->thread_error = SDL_strdup(SDL_GetError()); + SDL_SemPost(this->hidden->ready_semaphore); + return 0; + } + + /* init was successful, alert parent thread and start running... */ + SDL_SemPost(this->hidden->ready_semaphore); + while (!SDL_AtomicGet(&this->hidden->shutdown)) { + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1); + } + + if (this->iscapture) { /* just stop immediately for capture devices. */ + AudioQueueStop(this->hidden->audioQueue, 1); + } else { /* Drain off any pending playback. */ + AudioQueueStop(this->hidden->audioQueue, 0); + const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0; + CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0); + } + + return 0; +} + +static int +COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +{ + AudioStreamBasicDescription *strdesc; + SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + int valid_datatype = 0; + + /* 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_zerop(this->hidden); + + strdesc = &this->hidden->strdesc; + + if (iscapture) { + open_capture_devices++; + } else { + open_playback_devices++; + } + +#if !MACOSX_COREAUDIO + if (!update_audio_session(this, SDL_TRUE)) { + return -1; + } +#endif + + /* Setup a AudioStreamBasicDescription with the requested format */ + SDL_zerop(strdesc); + strdesc->mFormatID = kAudioFormatLinearPCM; + strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked; + strdesc->mChannelsPerFrame = this->spec.channels; + strdesc->mSampleRate = this->spec.freq; + strdesc->mFramesPerPacket = 1; + + while ((!valid_datatype) && (test_format)) { + this->spec.format = test_format; + /* Just a list of valid SDL formats, so people don't pass junk here. */ + switch (test_format) { + case AUDIO_U8: + case AUDIO_S8: + case AUDIO_U16LSB: + case AUDIO_S16LSB: + case AUDIO_U16MSB: + case AUDIO_S16MSB: + case AUDIO_S32LSB: + case AUDIO_S32MSB: + case AUDIO_F32LSB: + case AUDIO_F32MSB: + valid_datatype = 1; + strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(this->spec.format); + if (SDL_AUDIO_ISBIGENDIAN(this->spec.format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + + if (SDL_AUDIO_ISFLOAT(this->spec.format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat; + else if (SDL_AUDIO_ISSIGNED(this->spec.format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; + break; + } + } + + if (!valid_datatype) { /* shouldn't happen, but just in case... */ + return SDL_SetError("Unsupported audio format"); + } + + strdesc->mBytesPerFrame = strdesc->mBitsPerChannel * strdesc->mChannelsPerFrame / 8; + strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket; + +#if MACOSX_COREAUDIO + if (!prepare_device(this, handle, iscapture)) { + return -1; + } +#endif + + /* This has to init in a new thread so it can get its own CFRunLoop. :/ */ + SDL_AtomicSet(&this->hidden->shutdown, 0); + this->hidden->ready_semaphore = SDL_CreateSemaphore(0); + if (!this->hidden->ready_semaphore) { + return -1; /* oh well. */ + } + + this->hidden->thread = SDL_CreateThreadInternal(audioqueue_thread, "AudioQueue thread", 512 * 1024, this); + if (!this->hidden->thread) { + return -1; + } + + SDL_SemWait(this->hidden->ready_semaphore); + SDL_DestroySemaphore(this->hidden->ready_semaphore); + this->hidden->ready_semaphore = NULL; + + if ((this->hidden->thread != NULL) && (this->hidden->thread_error != NULL)) { + SDL_SetError("%s", this->hidden->thread_error); + return -1; + } + + return (this->hidden->thread != NULL) ? 0 : -1; +} + +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; + impl->OnlyHasDefaultCaptureDevice = 1; +#endif + + impl->ProvidesOwnCallbackThread = 1; + impl->HasCaptureSupport = 1; + + return 1; /* this audio target is available. */ +} + +AudioBootStrap COREAUDIO_bootstrap = { + "coreaudio", "CoreAudio", COREAUDIO_Init, 0 +}; + +#endif /* SDL_AUDIO_DRIVER_COREAUDIO */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/audio/directsound/SDL_directsound.c b/Engine/lib/sdl/src/audio/directsound/SDL_directsound.c index 065e163a6..5d261c92e 100644 --- a/Engine/lib/sdl/src/audio/directsound/SDL_directsound.c +++ b/Engine/lib/sdl/src/audio/directsound/SDL_directsound.c @@ -24,6 +24,7 @@ /* Allow access to a raw mixing buffer */ +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_loadso.h" #include "SDL_audio.h" @@ -36,11 +37,13 @@ /* DirectX function pointers for audio */ static void* DSoundDLL = NULL; -typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN); -typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); -typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID); +typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN); +typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); +typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN); +typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID); static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL; static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL; +static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL; static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL; static void @@ -48,6 +51,7 @@ DSOUND_Unload(void) { pDirectSoundCreate8 = NULL; pDirectSoundEnumerateW = NULL; + pDirectSoundCaptureCreate8 = NULL; pDirectSoundCaptureEnumerateW = NULL; if (DSoundDLL != NULL) { @@ -76,6 +80,7 @@ DSOUND_Load(void) loaded = 1; /* will reset if necessary. */ DSOUNDLOAD(DirectSoundCreate8); DSOUNDLOAD(DirectSoundEnumerateW); + DSOUNDLOAD(DirectSoundCaptureCreate8); DSOUNDLOAD(DirectSoundCaptureEnumerateW); #undef DSOUNDLOAD @@ -155,7 +160,7 @@ FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data) { const int iscapture = (int) ((size_t) data); if (guid != NULL) { /* skip default device */ - char *str = WIN_StringToUTF8(desc); + char *str = WIN_LookupAudioDeviceName(desc, guid); if (str != NULL) { LPGUID cpyguid = (LPGUID) SDL_malloc(sizeof (GUID)); SDL_memcpy(cpyguid, guid, sizeof (GUID)); @@ -197,7 +202,7 @@ DSOUND_WaitDevice(_THIS) return; } - while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) { + while ((cursor / this->spec.size) == this->hidden->lastchunk) { /* FIXME: find out how much time is left and sleep that long */ SDL_Delay(1); @@ -239,9 +244,8 @@ DSOUND_PlayDevice(_THIS) if (this->hidden->locked_buf) { IDirectSoundBuffer_Unlock(this->hidden->mixbuf, this->hidden->locked_buf, - this->hidden->mixlen, NULL, 0); + this->spec.size, NULL, 0); } - } static Uint8 * @@ -265,7 +269,7 @@ DSOUND_GetDeviceBuf(_THIS) SetDSerror("DirectSound GetCurrentPosition", result); return (NULL); } - cursor /= this->hidden->mixlen; + cursor /= this->spec.size; #ifdef DEBUG_SOUND /* Detect audio dropouts */ { @@ -281,17 +285,17 @@ DSOUND_GetDeviceBuf(_THIS) #endif this->hidden->lastchunk = cursor; cursor = (cursor + 1) % this->hidden->num_buffers; - cursor *= this->hidden->mixlen; + cursor *= this->spec.size; /* Lock the audio buffer */ result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor, - this->hidden->mixlen, + this->spec.size, (LPVOID *) & this->hidden->locked_buf, &rawlen, NULL, &junk, 0); if (result == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(this->hidden->mixbuf); result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor, - this->hidden->mixlen, + this->spec.size, (LPVOID *) & this-> hidden->locked_buf, &rawlen, NULL, &junk, 0); @@ -303,109 +307,106 @@ DSOUND_GetDeviceBuf(_THIS) return (this->hidden->locked_buf); } -static void -DSOUND_WaitDone(_THIS) +static int +DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen) { - Uint8 *stream = DSOUND_GetDeviceBuf(this); + struct SDL_PrivateAudioData *h = this->hidden; + DWORD junk, cursor, ptr1len, ptr2len; + VOID *ptr1, *ptr2; - /* Wait for the playing chunk to finish */ - if (stream != NULL) { - SDL_memset(stream, this->spec.silence, this->hidden->mixlen); - DSOUND_PlayDevice(this); + SDL_assert(buflen == this->spec.size); + + while (SDL_TRUE) { + if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */ + SDL_memset(buffer, this->spec.silence, buflen); + return buflen; + } + + if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) { + return -1; + } + if ((cursor / this->spec.size) == h->lastchunk) { + SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */ + } else { + break; + } } - DSOUND_WaitDevice(this); - /* Stop the looping sound buffer */ - IDirectSoundBuffer_Stop(this->hidden->mixbuf); + if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) { + return -1; + } + + SDL_assert(ptr1len == this->spec.size); + SDL_assert(ptr2 == NULL); + SDL_assert(ptr2len == 0); + + SDL_memcpy(buffer, ptr1, ptr1len); + + if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) { + return -1; + } + + h->lastchunk = (h->lastchunk + 1) % h->num_buffers; + + return ptr1len; +} + +static void +DSOUND_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + DWORD junk, cursor; + if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) { + h->lastchunk = cursor / this->spec.size; + } } static void DSOUND_CloseDevice(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->sound != NULL) { - if (this->hidden->mixbuf != NULL) { - /* Clean up the audio buffer */ - IDirectSoundBuffer_Release(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - } - IDirectSound_Release(this->hidden->sound); - this->hidden->sound = NULL; - } - - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->mixbuf != NULL) { + IDirectSoundBuffer_Stop(this->hidden->mixbuf); + IDirectSoundBuffer_Release(this->hidden->mixbuf); } + if (this->hidden->sound != NULL) { + IDirectSound_Release(this->hidden->sound); + } + if (this->hidden->capturebuf != NULL) { + IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf); + IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf); + } + if (this->hidden->capture != NULL) { + IDirectSoundCapture_Release(this->hidden->capture); + } + SDL_free(this->hidden); } /* This function tries to create a secondary audio buffer, and returns the - number of audio chunks available in the created buffer. + number of audio chunks available in the created buffer. This is for + playback devices, not capture. */ static int -CreateSecondary(_THIS, HWND focus) +CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt) { LPDIRECTSOUND sndObj = this->hidden->sound; LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf; - Uint32 chunksize = this->spec.size; - const int numchunks = 8; HRESULT result = DS_OK; DSBUFFERDESC format; LPVOID pvAudioPtr1, pvAudioPtr2; DWORD dwAudioBytes1, dwAudioBytes2; - WAVEFORMATEX wfmt; - - SDL_zero(wfmt); - - if (SDL_AUDIO_ISFLOAT(this->spec.format)) { - wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - } else { - wfmt.wFormatTag = WAVE_FORMAT_PCM; - } - - wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); - wfmt.nChannels = this->spec.channels; - wfmt.nSamplesPerSec = this->spec.freq; - wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8); - wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; - - /* Update the fragment size as size in bytes */ - SDL_CalculateAudioSpec(&this->spec); - - /* Try to set primary mixing privileges */ - if (focus) { - result = IDirectSound_SetCooperativeLevel(sndObj, - focus, DSSCL_PRIORITY); - } else { - result = IDirectSound_SetCooperativeLevel(sndObj, - GetDesktopWindow(), - DSSCL_NORMAL); - } - if (result != DS_OK) { - return SetDSerror("DirectSound SetCooperativeLevel", result); - } /* Try to create the secondary buffer */ SDL_zero(format); format.dwSize = sizeof(format); format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; - if (!focus) { - format.dwFlags |= DSBCAPS_GLOBALFOCUS; - } else { - format.dwFlags |= DSBCAPS_STICKYFOCUS; - } - format.dwBufferBytes = numchunks * chunksize; - if ((format.dwBufferBytes < DSBSIZE_MIN) || - (format.dwBufferBytes > DSBSIZE_MAX)) { - return SDL_SetError("Sound buffer size must be between %d and %d", - DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks); - } - format.dwReserved = 0; - format.lpwfxFormat = &wfmt; + format.dwFlags |= DSBCAPS_GLOBALFOCUS; + format.dwBufferBytes = bufsize; + format.lpwfxFormat = wfmt; result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); if (result != DS_OK) { return SetDSerror("DirectSound CreateSoundBuffer", result); } - IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt); + IDirectSoundBuffer_SetFormat(*sndbuf, wfmt); /* Silence the initial audio buffer */ result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, @@ -420,31 +421,90 @@ CreateSecondary(_THIS, HWND focus) } /* We're ready to go */ - return (numchunks); + return 0; +} + +/* This function tries to create a capture buffer, and returns the + number of audio chunks available in the created buffer. This is for + capture devices, not playback. +*/ +static int +CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt) +{ + LPDIRECTSOUNDCAPTURE capture = this->hidden->capture; + LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf; + DSCBUFFERDESC format; +// DWORD junk, cursor; + HRESULT result; + + SDL_zero(format); + format.dwSize = sizeof (format); + format.dwFlags = DSCBCAPS_WAVEMAPPED; + format.dwBufferBytes = bufsize; + format.lpwfxFormat = wfmt; + + result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSound CreateCaptureBuffer", result); + } + + result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING); + if (result != DS_OK) { + IDirectSoundCaptureBuffer_Release(*capturebuf); + return SetDSerror("DirectSound Start", result); + } + +#if 0 + /* presumably this starts at zero, but just in case... */ + result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor); + if (result != DS_OK) { + IDirectSoundCaptureBuffer_Stop(*capturebuf); + IDirectSoundCaptureBuffer_Release(*capturebuf); + return SetDSerror("DirectSound GetCurrentPosition", result); + } + + this->hidden->lastchunk = cursor / this->spec.size; +#endif + + return 0; } static int DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { + const DWORD numchunks = 8; HRESULT result; SDL_bool valid_format = SDL_FALSE; SDL_bool tried_format = SDL_FALSE; SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); LPGUID guid = (LPGUID) handle; - + DWORD bufsize; + /* 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)); + SDL_zerop(this->hidden); /* Open the audio device */ - result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); - if (result != DS_OK) { - DSOUND_CloseDevice(this); - return SetDSerror("DirectSoundCreate", result); + if (iscapture) { + result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSoundCaptureCreate8", result); + } + } else { + result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL); + if (result != DS_OK) { + return SetDSerror("DirectSoundCreate8", result); + } + result = IDirectSound_SetCooperativeLevel(this->hidden->sound, + GetDesktopWindow(), + DSSCL_NORMAL); + if (result != DS_OK) { + return SetDSerror("DirectSound SetCooperativeLevel", result); + } } while ((!valid_format) && (test_format)) { @@ -454,10 +514,38 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) case AUDIO_S32: case AUDIO_F32: tried_format = SDL_TRUE; + this->spec.format = test_format; - this->hidden->num_buffers = CreateSecondary(this, NULL); - if (this->hidden->num_buffers > 0) { - valid_format = SDL_TRUE; + + /* Update the fragment size as size in bytes */ + SDL_CalculateAudioSpec(&this->spec); + + bufsize = numchunks * this->spec.size; + if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) { + SDL_SetError("Sound buffer size must be between %d and %d", + (DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks, + DSBSIZE_MAX / numchunks); + } else { + int rc; + WAVEFORMATEX wfmt; + SDL_zero(wfmt); + if (SDL_AUDIO_ISFLOAT(this->spec.format)) { + wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + } else { + wfmt.wFormatTag = WAVE_FORMAT_PCM; + } + + wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format); + wfmt.nChannels = this->spec.channels; + wfmt.nSamplesPerSec = this->spec.freq; + wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8); + wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign; + + rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt); + if (rc == 0) { + this->hidden->num_buffers = numchunks; + valid_format = SDL_TRUE; + } } break; } @@ -465,15 +553,13 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_format) { - DSOUND_CloseDevice(this); if (tried_format) { return -1; /* CreateSecondary() should have called SDL_SetError(). */ } return SDL_SetError("DirectSound: Unsupported audio format"); } - /* The buffer will auto-start playing in DSOUND_WaitDevice() */ - this->hidden->mixlen = this->spec.size; + /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */ return 0; /* good to go. */ } @@ -498,13 +584,15 @@ DSOUND_Init(SDL_AudioDriverImpl * impl) impl->OpenDevice = DSOUND_OpenDevice; impl->PlayDevice = DSOUND_PlayDevice; impl->WaitDevice = DSOUND_WaitDevice; - impl->WaitDone = DSOUND_WaitDone; impl->GetDeviceBuf = DSOUND_GetDeviceBuf; + impl->CaptureFromDevice = DSOUND_CaptureFromDevice; + impl->FlushCapture = DSOUND_FlushCapture; impl->CloseDevice = DSOUND_CloseDevice; impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; - impl->Deinitialize = DSOUND_Deinitialize; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/directsound/SDL_directsound.h b/Engine/lib/sdl/src/audio/directsound/SDL_directsound.h index 0d5f6bd76..d646c303f 100644 --- a/Engine/lib/sdl/src/audio/directsound/SDL_directsound.h +++ b/Engine/lib/sdl/src/audio/directsound/SDL_directsound.h @@ -35,8 +35,9 @@ struct SDL_PrivateAudioData { LPDIRECTSOUND sound; LPDIRECTSOUNDBUFFER mixbuf; + LPDIRECTSOUNDCAPTURE capture; + LPDIRECTSOUNDCAPTUREBUFFER capturebuf; int num_buffers; - int mixlen; DWORD lastchunk; Uint8 *locked_buf; }; diff --git a/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.c b/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.c index 28745f9d0..ee5368844 100644 --- a/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.c +++ b/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.c @@ -31,46 +31,33 @@ #include "SDL_rwops.h" #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_diskaudio.h" +/* !!! FIXME: these should be SDL hints, not environment variables. */ /* environment variables and defaults. */ #define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE" #define DISKDEFAULT_OUTFILE "sdlaudio.raw" -#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY" -#define DISKDEFAULT_WRITEDELAY 150 - -static const char * -DISKAUD_GetOutputFilename(const char *devname) -{ - if (devname == NULL) { - devname = SDL_getenv(DISKENVR_OUTFILE); - if (devname == NULL) { - devname = DISKDEFAULT_OUTFILE; - } - } - return devname; -} +#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN" +#define DISKDEFAULT_INFILE "sdlaudio-in.raw" +#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY" /* This function waits until it is possible to write a full sound buffer */ static void -DISKAUD_WaitDevice(_THIS) +DISKAUDIO_WaitDevice(_THIS) { - SDL_Delay(this->hidden->write_delay); + SDL_Delay(this->hidden->io_delay); } static void -DISKAUD_PlayDevice(_THIS) +DISKAUDIO_PlayDevice(_THIS) { - size_t written; - - /* Write the audio data */ - written = SDL_RWwrite(this->hidden->output, - this->hidden->mixbuf, 1, this->hidden->mixlen); + const size_t written = SDL_RWwrite(this->hidden->io, + this->hidden->mixbuf, + 1, this->spec.size); /* If we couldn't write, assume fatal error for now */ - if (written != this->hidden->mixlen) { + if (written != this->spec.size) { SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO @@ -79,63 +66,105 @@ DISKAUD_PlayDevice(_THIS) } static Uint8 * -DISKAUD_GetDeviceBuf(_THIS) +DISKAUDIO_GetDeviceBuf(_THIS) { return (this->hidden->mixbuf); } -static void -DISKAUD_CloseDevice(_THIS) +static int +DISKAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->output != NULL) { - SDL_RWclose(this->hidden->output); - this->hidden->output = NULL; + struct SDL_PrivateAudioData *h = this->hidden; + const int origbuflen = buflen; + + SDL_Delay(h->io_delay); + + if (h->io) { + const size_t br = SDL_RWread(h->io, buffer, 1, buflen); + buflen -= (int) br; + buffer = ((Uint8 *) buffer) + br; + if (buflen > 0) { /* EOF (or error, but whatever). */ + SDL_RWclose(h->io); + h->io = NULL; } - SDL_free(this->hidden); - this->hidden = NULL; } + + /* if we ran out of file, just write silence. */ + SDL_memset(buffer, this->spec.silence, buflen); + + return origbuflen; +} + +static void +DISKAUDIO_FlushCapture(_THIS) +{ + /* no op...we don't advance the file pointer or anything. */ +} + + +static void +DISKAUDIO_CloseDevice(_THIS) +{ + if (this->hidden->io != NULL) { + SDL_RWclose(this->hidden->io); + } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); +} + + +static const char * +get_filename(const int iscapture, const char *devname) +{ + if (devname == NULL) { + devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE); + if (devname == NULL) { + devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE; + } + } + return devname; } static int -DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DISKAUDIO_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 = get_filename(iscapture, handle ? NULL : devname); + const char *envr = SDL_getenv(DISKENVR_IODELAY); 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)); + SDL_zerop(this->hidden); - this->hidden->mixlen = this->spec.size; - this->hidden->write_delay = - (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY; + if (envr != NULL) { + this->hidden->io_delay = SDL_atoi(envr); + } else { + this->hidden->io_delay = ((this->spec.samples * 1000) / this->spec.freq); + } /* Open the audio device */ - this->hidden->output = SDL_RWFromFile(fname, "wb"); - if (this->hidden->output == NULL) { - DISKAUD_CloseDevice(this); + this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb"); + if (this->hidden->io == NULL) { return -1; } /* Allocate mixing buffer */ - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - DISKAUD_CloseDevice(this); - return -1; + if (!iscapture) { + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); #if HAVE_STDIO_H fprintf(stderr, - "WARNING: You are using the SDL disk writer audio driver!\n" - " Writing to file [%s].\n", fname); + "WARNING: You are using the SDL disk i/o audio driver!\n" + " %s file [%s].\n", iscapture ? "Reading from" : "Writing to", + fname); #endif /* We're ready to rock and roll. :-) */ @@ -143,30 +172,34 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } static void -DISKAUD_DetectDevices(void) +DISKAUDIO_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); + SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1); + SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2); } static int -DISKAUD_Init(SDL_AudioDriverImpl * impl) +DISKAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ - impl->OpenDevice = DISKAUD_OpenDevice; - impl->WaitDevice = DISKAUD_WaitDevice; - impl->PlayDevice = DISKAUD_PlayDevice; - impl->GetDeviceBuf = DISKAUD_GetDeviceBuf; - impl->CloseDevice = DISKAUD_CloseDevice; - impl->DetectDevices = DISKAUD_DetectDevices; + impl->OpenDevice = DISKAUDIO_OpenDevice; + impl->WaitDevice = DISKAUDIO_WaitDevice; + impl->PlayDevice = DISKAUDIO_PlayDevice; + impl->GetDeviceBuf = DISKAUDIO_GetDeviceBuf; + impl->CaptureFromDevice = DISKAUDIO_CaptureFromDevice; + impl->FlushCapture = DISKAUDIO_FlushCapture; + + impl->CloseDevice = DISKAUDIO_CloseDevice; + impl->DetectDevices = DISKAUDIO_DetectDevices; impl->AllowsArbitraryDeviceNames = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } -AudioBootStrap DISKAUD_bootstrap = { - "disk", "direct-to-disk audio", DISKAUD_Init, 1 +AudioBootStrap DISKAUDIO_bootstrap = { + "disk", "direct-to-disk audio", DISKAUDIO_Init, 1 }; #endif /* SDL_AUDIO_DRIVER_DISK */ diff --git a/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.h b/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.h index b5666f7fc..ad152a9ce 100644 --- a/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.h +++ b/Engine/lib/sdl/src/audio/disk/SDL_diskaudio.h @@ -32,10 +32,9 @@ struct SDL_PrivateAudioData { /* The file descriptor for the audio device */ - SDL_RWops *output; + SDL_RWops *io; + Uint32 io_delay; Uint8 *mixbuf; - Uint32 mixlen; - Uint32 write_delay; }; #endif /* _SDL_diskaudio_h */ diff --git a/Engine/lib/sdl/src/audio/dsp/SDL_dspaudio.c b/Engine/lib/sdl/src/audio/dsp/SDL_dspaudio.c index 17e029e1d..a5a31b3aa 100644 --- a/Engine/lib/sdl/src/audio/dsp/SDL_dspaudio.c +++ b/Engine/lib/sdl/src/audio/dsp/SDL_dspaudio.c @@ -44,7 +44,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_dspaudio.h" @@ -60,16 +59,11 @@ DSP_DetectDevices(void) static void DSP_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } @@ -106,23 +100,20 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); if (this->hidden->audio_fd < 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno)); } - this->hidden->mixbuf = NULL; - /* Make the file descriptor use blocking writes with fcntl() */ + /* Make the file descriptor use blocking i/o with fcntl() */ { long ctlflags; ctlflags = fcntl(this->hidden->audio_fd, F_GETFL); ctlflags &= ~O_NONBLOCK; if (fcntl(this->hidden->audio_fd, F_SETFL, ctlflags) < 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio blocking mode"); } } @@ -130,7 +121,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Get a list of supported hardware formats */ if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_GETFMTS, &value) < 0) { perror("SNDCTL_DSP_GETFMTS"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't get audio format list"); } @@ -187,7 +177,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - DSP_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -197,7 +186,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if ((ioctl(this->hidden->audio_fd, SNDCTL_DSP_SETFMT, &value) < 0) || (value != format)) { perror("SNDCTL_DSP_SETFMT"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio format"); } @@ -205,7 +193,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) value = this->spec.channels; if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_CHANNELS, &value) < 0) { perror("SNDCTL_DSP_CHANNELS"); - DSP_CloseDevice(this); return SDL_SetError("Cannot set the number of channels"); } this->spec.channels = value; @@ -214,7 +201,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) value = this->spec.freq; if (ioctl(this->hidden->audio_fd, SNDCTL_DSP_SPEED, &value) < 0) { perror("SNDCTL_DSP_SPEED"); - DSP_CloseDevice(this); return SDL_SetError("Couldn't set audio frequency"); } this->spec.freq = value; @@ -225,7 +211,6 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Determine the power of two of the fragment size */ for (frag_spec = 0; (0x01U << frag_spec) < this->spec.size; ++frag_spec); if ((0x01U << frag_spec) != this->spec.size) { - DSP_CloseDevice(this); return SDL_SetError("Fragment size must be a power of two"); } frag_spec |= 0x00020000; /* two fragments, for low latency */ @@ -250,13 +235,14 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - DSP_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ return 0; @@ -266,14 +252,13 @@ DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) static void DSP_PlayDevice(_THIS) { - const Uint8 *mixbuf = this->hidden->mixbuf; - const int mixlen = this->hidden->mixlen; - if (write(this->hidden->audio_fd, mixbuf, mixlen) == -1) { + struct SDL_PrivateAudioData *h = this->hidden; + if (write(h->audio_fd, h->mixbuf, h->mixlen) == -1) { perror("Audio write"); SDL_OpenedAudioDeviceDisconnected(this); } #ifdef DEBUG_AUDIO - fprintf(stderr, "Wrote %d bytes of audio data\n", mixlen); + fprintf(stderr, "Wrote %d bytes of audio data\n", h->mixlen); #endif } @@ -283,6 +268,30 @@ DSP_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +DSP_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + return (int) read(this->hidden->audio_fd, buffer, buflen); +} + +static void +DSP_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + audio_buf_info info; + if (ioctl(h->audio_fd, SNDCTL_DSP_GETISPACE, &info) == 0) { + while (info.bytes > 0) { + char buf[512]; + const size_t len = SDL_min(sizeof (buf), info.bytes); + const ssize_t br = read(h->audio_fd, buf, len); + if (br <= 0) { + break; + } + info.bytes -= br; + } + } +} + static int DSP_Init(SDL_AudioDriverImpl * impl) { @@ -292,8 +301,11 @@ DSP_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = DSP_PlayDevice; impl->GetDeviceBuf = DSP_GetDeviceBuf; impl->CloseDevice = DSP_CloseDevice; + impl->CaptureFromDevice = DSP_CaptureFromDevice; + impl->FlushCapture = DSP_FlushCapture; impl->AllowsArbitraryDeviceNames = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/dummy/SDL_dummyaudio.c b/Engine/lib/sdl/src/audio/dummy/SDL_dummyaudio.c index 107f0b073..b39f8e327 100644 --- a/Engine/lib/sdl/src/audio/dummy/SDL_dummyaudio.c +++ b/Engine/lib/sdl/src/audio/dummy/SDL_dummyaudio.c @@ -22,27 +22,44 @@ /* Output audio to nowhere... */ +#include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" #include "SDL_dummyaudio.h" static int -DUMMYAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { return 0; /* always succeeds. */ } static int -DUMMYAUD_Init(SDL_AudioDriverImpl * impl) +DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + /* Delay to make this sort of simulate real audio input. */ + SDL_Delay((this->spec.samples * 1000) / this->spec.freq); + + /* always return a full buffer of silence. */ + SDL_memset(buffer, this->spec.silence, buflen); + return buflen; +} + +static int +DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ - impl->OpenDevice = DUMMYAUD_OpenDevice; + impl->OpenDevice = DUMMYAUDIO_OpenDevice; + impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice; + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } -AudioBootStrap DUMMYAUD_bootstrap = { - "dummy", "SDL dummy audio driver", DUMMYAUD_Init, 1 +AudioBootStrap DUMMYAUDIO_bootstrap = { + "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1 }; /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c b/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c index 8378233ca..839d445ee 100644 --- a/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/Engine/lib/sdl/src/audio/emscripten/SDL_emscriptenaudio.c @@ -61,16 +61,15 @@ 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) + /* Only do something if audio is enabled */ + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { return; + } if (this->convert.needed) { + const int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8; + if (this->hidden->conv_in_len != 0) { this->convert.len = this->hidden->conv_in_len * bytes_in * this->spec.channels; } @@ -128,7 +127,7 @@ HandleAudioProcess(_THIS) } for (var j = 0; j < $1; ++j) { - channelData[j] = getValue($0 + (j*numChannels + c)*4, 'float'); + channelData[j] = HEAPF32[$0 + ((j*numChannels + c) << 2) >> 2]; } } }, buf, byte_len / bytes / this->spec.channels); @@ -136,29 +135,147 @@ HandleAudioProcess(_THIS) } static void -Emscripten_CloseDevice(_THIS) +HandleCaptureProcess(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->mixbuf != NULL) { - /* Clean up the audio buffer */ - SDL_free(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - } + Uint8 *buf; + int buflen; - SDL_free(this->hidden); - this->hidden = NULL; + /* Only do something if audio is enabled */ + if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) { + return; } + + if (this->convert.needed) { + buf = this->convert.buf; + buflen = this->convert.len_cvt; + } else { + if (!this->hidden->mixbuf) { + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); + if (!this->hidden->mixbuf) { + return; /* oh well. */ + } + } + buf = this->hidden->mixbuf; + buflen = this->spec.size; + } + + EM_ASM_ARGS({ + var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels; + if (numChannels == 1) { /* fastpath this a little for the common (mono) case. */ + var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(0); + if (channelData.length != $1) { + throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; + } + for (var j = 0; j < $1; ++j) { + setValue($0 + (j * 4), channelData[j], 'float'); + } + } else { + for (var c = 0; c < numChannels; ++c) { + var channelData = SDL2.capture.currentCaptureBuffer.getChannelData(c); + if (channelData.length != $1) { + throw 'Web Audio capture buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + $1 + ' samples!'; + } + + for (var j = 0; j < $1; ++j) { + setValue($0 + (((j * numChannels) + c) * 4), channelData[j], 'float'); + } + } + } + }, buf, (this->spec.size / sizeof (float)) / this->spec.channels); + + /* okay, we've got an interleaved float32 array in C now. */ + + if (this->convert.needed) { + SDL_ConvertAudio(&this->convert); + } + + /* Send it to the app. */ + (*this->spec.callback) (this->spec.userdata, buf, buflen); +} + + + +static void +EMSCRIPTENAUDIO_CloseDevice(_THIS) +{ + EM_ASM_({ + if ($0) { + if (SDL2.capture.silenceTimer !== undefined) { + clearTimeout(SDL2.capture.silenceTimer); + } + if (SDL2.capture.stream !== undefined) { + var tracks = SDL2.capture.stream.getAudioTracks(); + for (var i = 0; i < tracks.length; i++) { + SDL2.capture.stream.removeTrack(tracks[i]); + } + SDL2.capture.stream = undefined; + } + if (SDL2.capture.scriptProcessorNode !== undefined) { + SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) {}; + SDL2.capture.scriptProcessorNode.disconnect(); + SDL2.capture.scriptProcessorNode = undefined; + } + if (SDL2.capture.mediaStreamNode !== undefined) { + SDL2.capture.mediaStreamNode.disconnect(); + SDL2.capture.mediaStreamNode = undefined; + } + if (SDL2.capture.silenceBuffer !== undefined) { + SDL2.capture.silenceBuffer = undefined + } + SDL2.capture = undefined; + } else { + if (SDL2.audio.scriptProcessorNode != undefined) { + SDL2.audio.scriptProcessorNode.disconnect(); + SDL2.audio.scriptProcessorNode = undefined; + } + SDL2.audio = undefined; + } + if ((SDL2.audioContext !== undefined) && (SDL2.audio === undefined) && (SDL2.capture === undefined)) { + SDL2.audioContext.close(); + SDL2.audioContext = undefined; + } + }, this->iscapture); + + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int -Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { SDL_bool valid_format = SDL_FALSE; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + SDL_AudioFormat test_format; int i; float f; int result; + /* based on parts of library_sdl.js */ + + /* create context (TODO: this puts stuff in the global namespace...)*/ + result = EM_ASM_INT({ + if(typeof(SDL2) === 'undefined') { + SDL2 = {}; + } + if (!$0) { + SDL2.audio = {}; + } else { + SDL2.capture = {}; + } + + if (!SDL2.audioContext) { + if (typeof(AudioContext) !== 'undefined') { + SDL2.audioContext = new AudioContext(); + } else if (typeof(webkitAudioContext) !== 'undefined') { + SDL2.audioContext = new webkitAudioContext(); + } + } + return SDL2.audioContext === undefined ? -1 : 0; + }, iscapture); + if (result < 0) { + return SDL_SetError("Web Audio API is not available!"); + } + + test_format = SDL_FirstAudioFormat(this->spec.format); while ((!valid_format) && (test_format)) { switch (test_format) { case AUDIO_F32: /* web audio only supports floats */ @@ -181,36 +298,11 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 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!"); - } + SDL_zerop(this->hidden); /* limit to native freq */ - int sampleRate = EM_ASM_INT_V({ - return SDL2.audioContext['sampleRate']; + const int sampleRate = EM_ASM_INT_V({ + return SDL2.audioContext.sampleRate; }); if(this->spec.freq != sampleRate) { @@ -227,26 +319,86 @@ Emscripten_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 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); + if (iscapture) { + /* The idea is to take the capture media stream, hook it up to an + audio graph where we can pass it through a ScriptProcessorNode + to access the raw PCM samples and push them to the SDL app's + callback. From there, we "process" the audio data into silence + and forget about it. */ + + /* This should, strictly speaking, use MediaRecorder for capture, but + this API is cleaner to use and better supported, and fires a + callback whenever there's enough data to fire down into the app. + The downside is that we are spending CPU time silencing a buffer + that the audiocontext uselessly mixes into any output. On the + upside, both of those things are not only run in native code in + the browser, they're probably SIMD code, too. MediaRecorder + feels like it's a pretty inefficient tapdance in similar ways, + to be honest. */ + + EM_ASM_({ + var have_microphone = function(stream) { + //console.log('SDL audio capture: we have a microphone! Replacing silence callback.'); + if (SDL2.capture.silenceTimer !== undefined) { + clearTimeout(SDL2.capture.silenceTimer); + SDL2.capture.silenceTimer = undefined; + } + SDL2.capture.mediaStreamNode = SDL2.audioContext.createMediaStreamSource(stream); + SDL2.capture.scriptProcessorNode = SDL2.audioContext.createScriptProcessor($1, $0, 1); + SDL2.capture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) { + if ((SDL2 === undefined) || (SDL2.capture === undefined)) { return; } + audioProcessingEvent.outputBuffer.getChannelData(0).fill(0.0); + SDL2.capture.currentCaptureBuffer = audioProcessingEvent.inputBuffer; + Runtime.dynCall('vi', $2, [$3]); + }; + SDL2.capture.mediaStreamNode.connect(SDL2.capture.scriptProcessorNode); + SDL2.capture.scriptProcessorNode.connect(SDL2.audioContext.destination); + SDL2.capture.stream = stream; + }; + + var no_microphone = function(error) { + //console.log('SDL audio capture: we DO NOT have a microphone! (' + error.name + ')...leaving silence callback running.'); + }; + + /* we write silence to the audio callback until the microphone is available (user approves use, etc). */ + SDL2.capture.silenceBuffer = SDL2.audioContext.createBuffer($0, $1, SDL2.audioContext.sampleRate); + SDL2.capture.silenceBuffer.getChannelData(0).fill(0.0); + var silence_callback = function() { + SDL2.capture.currentCaptureBuffer = SDL2.capture.silenceBuffer; + Runtime.dynCall('vi', $2, [$3]); + }; + + SDL2.capture.silenceTimer = setTimeout(silence_callback, ($1 / SDL2.audioContext.sampleRate) * 1000); + + if ((navigator.mediaDevices !== undefined) && (navigator.mediaDevices.getUserMedia !== undefined)) { + navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(have_microphone).catch(no_microphone); + } else if (navigator.webkitGetUserMedia !== undefined) { + navigator.webkitGetUserMedia({ audio: true, video: false }, have_microphone, no_microphone); + } + }, this->spec.channels, this->spec.samples, HandleCaptureProcess, this); + } else { + /* setup a ScriptProcessorNode */ + EM_ASM_ARGS({ + SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); + SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { + if ((SDL2 === undefined) || (SDL2.audio === undefined)) { return; } + 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) +EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ - impl->OpenDevice = Emscripten_OpenDevice; - impl->CloseDevice = Emscripten_CloseDevice; + impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice; + impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice; - /* only one output */ impl->OnlyHasDefaultOutputDevice = 1; /* no threads here */ @@ -254,7 +406,7 @@ Emscripten_Init(SDL_AudioDriverImpl * impl) impl->ProvidesOwnCallbackThread = 1; /* check availability */ - int available = EM_ASM_INT_V({ + const int available = EM_ASM_INT_V({ if (typeof(AudioContext) !== 'undefined') { return 1; } else if (typeof(webkitAudioContext) !== 'undefined') { @@ -267,11 +419,23 @@ Emscripten_Init(SDL_AudioDriverImpl * impl) SDL_SetError("No audio context available"); } + const int capture_available = available && EM_ASM_INT_V({ + if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) { + return 1; + } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') { + return 1; + } + return 0; + }); + + impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE; + impl->OnlyHasDefaultCaptureDevice = capture_available ? SDL_TRUE : SDL_FALSE; + return available; } -AudioBootStrap EmscriptenAudio_bootstrap = { - "emscripten", "SDL emscripten audio driver", Emscripten_Init, 0 +AudioBootStrap EMSCRIPTENAUDIO_bootstrap = { + "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0 }; #endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */ diff --git a/Engine/lib/sdl/src/audio/esd/SDL_esdaudio.c b/Engine/lib/sdl/src/audio/esd/SDL_esdaudio.c index 6a7882dcb..3eb719791 100644 --- a/Engine/lib/sdl/src/audio/esd/SDL_esdaudio.c +++ b/Engine/lib/sdl/src/audio/esd/SDL_esdaudio.c @@ -32,7 +32,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_esdaudio.h" @@ -174,17 +173,11 @@ ESD_GetDeviceBuf(_THIS) static void ESD_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - SDL_NAME(esd_close) (this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + SDL_NAME(esd_close) (this->hidden->audio_fd); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } /* Try to get the name of the program */ @@ -227,7 +220,7 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); this->hidden->audio_fd = -1; /* Convert audio spec to the ESD audio format */ @@ -252,7 +245,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!found) { - ESD_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } @@ -271,7 +263,6 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) get_progname()); if (this->hidden->audio_fd < 0) { - ESD_CloseDevice(this); return SDL_SetError("Couldn't open ESD connection"); } @@ -283,9 +274,8 @@ ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - ESD_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); diff --git a/Engine/lib/sdl/src/audio/fusionsound/SDL_fsaudio.c b/Engine/lib/sdl/src/audio/fusionsound/SDL_fsaudio.c index b22a3e9a3..daa0f9dd6 100644 --- a/Engine/lib/sdl/src/audio/fusionsound/SDL_fsaudio.c +++ b/Engine/lib/sdl/src/audio/fusionsound/SDL_fsaudio.c @@ -22,6 +22,8 @@ #if SDL_AUDIO_DRIVER_FUSIONSOUND +/* !!! FIXME: why is this is SDL_FS_* instead of FUSIONSOUND_*? */ + /* Allow access to a raw mixing buffer */ #ifdef HAVE_SIGNAL_H @@ -31,7 +33,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_fsaudio.h" @@ -150,13 +151,6 @@ SDL_FS_PlayDevice(_THIS) #endif } -static void -SDL_FS_WaitDone(_THIS) -{ - this->hidden->stream->Wait(this->hidden->stream, - this->hidden->mixsamples * FUSION_BUFFERS); -} - static Uint8 * SDL_FS_GetDeviceBuf(_THIS) @@ -168,20 +162,14 @@ SDL_FS_GetDeviceBuf(_THIS) static void SDL_FS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->stream) { - this->hidden->stream->Release(this->hidden->stream); - this->hidden->stream = NULL; - } - if (this->hidden->fs) { - this->hidden->fs->Release(this->hidden->fs); - this->hidden->fs = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->stream) { + this->hidden->stream->Release(this->hidden->stream); } + if (this->hidden->fs) { + this->hidden->fs->Release(this->hidden->fs); + } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } @@ -200,7 +188,7 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ for (test_format = SDL_FirstAudioFormat(this->spec.format); @@ -239,7 +227,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (format == 0) { - SDL_FS_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -247,7 +234,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Retrieve the main sound interface. */ ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs); if (ret) { - SDL_FS_CloseDevice(this); return SDL_SetError("Unable to initialize FusionSound: %d", ret); } @@ -266,7 +252,6 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->fs->CreateStream(this->hidden->fs, &desc, &this->hidden->stream); if (ret) { - SDL_FS_CloseDevice(this); return SDL_SetError("Unable to create FusionSoundStream: %d", ret); } @@ -285,9 +270,8 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - SDL_FS_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); @@ -328,7 +312,6 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = SDL_FS_WaitDevice; impl->GetDeviceBuf = SDL_FS_GetDeviceBuf; impl->CloseDevice = SDL_FS_CloseDevice; - impl->WaitDone = SDL_FS_WaitDone; impl->Deinitialize = SDL_FS_Deinitialize; impl->OnlyHasDefaultOutputDevice = 1; diff --git a/Engine/lib/sdl/src/audio/haiku/SDL_haikuaudio.cc b/Engine/lib/sdl/src/audio/haiku/SDL_haikuaudio.cc index 38f3b9621..25b1fa217 100644 --- a/Engine/lib/sdl/src/audio/haiku/SDL_haikuaudio.cc +++ b/Engine/lib/sdl/src/audio/haiku/SDL_haikuaudio.cc @@ -49,10 +49,11 @@ FillSound(void *device, void *stream, size_t len, SDL_AudioDevice *audio = (SDL_AudioDevice *) device; /* Only do soemthing if audio is enabled */ - if (!audio->enabled) + if (!SDL_AtomicGet(&audio->enabled)) { return; + } - if (!audio->paused) { + if (!SDL_AtomicGet(&audio->paused)) { if (audio->convert.needed) { SDL_LockMutex(audio->mixer_lock); (*audio->spec.callback) (audio->spec.userdata, @@ -73,16 +74,11 @@ FillSound(void *device, void *stream, size_t len, static void HAIKUAUDIO_CloseDevice(_THIS) { - if (_this->hidden != NULL) { - if (_this->hidden->audio_obj) { - _this->hidden->audio_obj->Stop(); - delete _this->hidden->audio_obj; - _this->hidden->audio_obj = NULL; - } - - delete _this->hidden; - _this->hidden = NULL; + if (_this->hidden->audio_obj) { + _this->hidden->audio_obj->Stop(); + delete _this->hidden->audio_obj; } + delete _this->hidden; } @@ -122,10 +118,10 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (_this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(_this->hidden, 0, (sizeof *_this->hidden)); + SDL_zerop(_this->hidden); /* Parse the audio format and fill the Be raw audio format */ - SDL_memset(&format, '\0', sizeof(media_raw_audio_format)); + SDL_zero(format); format.byte_order = B_MEDIA_LITTLE_ENDIAN; format.frame_rate = (float) _this->spec.freq; format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */ @@ -176,7 +172,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_datatype) { /* shouldn't happen, but just in case... */ - HAIKUAUDIO_CloseDevice(_this); return SDL_SetError("Unsupported audio format"); } @@ -195,7 +190,6 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (_this->hidden->audio_obj->Start() == B_NO_ERROR) { _this->hidden->audio_obj->SetHasData(true); } else { - HAIKUAUDIO_CloseDevice(_this); return SDL_SetError("Unable to start Be audio"); } diff --git a/Engine/lib/sdl/src/audio/nacl/SDL_naclaudio.c b/Engine/lib/sdl/src/audio/nacl/SDL_naclaudio.c index 2d1ee73e9..33cbe1c83 100644 --- a/Engine/lib/sdl/src/audio/nacl/SDL_naclaudio.c +++ b/Engine/lib/sdl/src/audio/nacl/SDL_naclaudio.c @@ -27,7 +27,6 @@ #include "SDL_audio.h" #include "SDL_mutex.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" @@ -38,22 +37,20 @@ #include "ppapi_simple/ps_event.h" /* The tag name used by NACL audio */ -#define NACLAUD_DRIVER_NAME "nacl" +#define NACLAUDIO_DRIVER_NAME "nacl" #define SAMPLE_FRAME_COUNT 4096 /* Audio driver functions */ -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); /* FIXME: Make use of latency if needed */ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data) { SDL_AudioDevice* _this = (SDL_AudioDevice*) data; - SDL_LockMutex(private->mutex); + SDL_LockMutex(private->mutex); /* !!! FIXME: is this mutex necessary? */ - if (_this->enabled && !_this->paused) { + if (SDL_AtomicGet(&_this->enabled) && !SDL_AtomicGet(&_this->paused)) { if (_this->convert.needed) { SDL_LockMutex(_this->mixer_lock); (*_this->spec.callback) (_this->spec.userdata, @@ -68,13 +65,13 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt SDL_UnlockMutex(_this->mixer_lock); } } else { - SDL_memset(samples, 0, buffer_size); + SDL_memset(samples, _this->spec.silence, buffer_size); } - return; + SDL_UnlockMutex(private->mutex); } -static void NACLAUD_CloseDevice(SDL_AudioDevice *device) { +static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) { const PPB_Core *core = PSInterfaceCore(); const PPB_Audio *ppb_audio = PSInterfaceAudio(); SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden; @@ -85,7 +82,7 @@ static void NACLAUD_CloseDevice(SDL_AudioDevice *device) { } static int -NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { +NACLAUDIO_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(); @@ -121,30 +118,30 @@ NACLAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { } static int -NACLAUD_Init(SDL_AudioDriverImpl * impl) +NACLAUDIO_Init(SDL_AudioDriverImpl * impl) { if (PSGetInstanceId() == 0) { return 0; } /* Set the function pointers */ - impl->OpenDevice = NACLAUD_OpenDevice; - impl->CloseDevice = NACLAUD_CloseDevice; + impl->OpenDevice = NACLAUDIO_OpenDevice; + impl->CloseDevice = NACLAUDIO_CloseDevice; impl->OnlyHasDefaultOutputDevice = 1; impl->ProvidesOwnCallbackThread = 1; /* - * impl->WaitDevice = NACLAUD_WaitDevice; - * impl->GetDeviceBuf = NACLAUD_GetDeviceBuf; - * impl->PlayDevice = NACLAUD_PlayDevice; - * impl->Deinitialize = NACLAUD_Deinitialize; + * impl->WaitDevice = NACLAUDIO_WaitDevice; + * impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf; + * impl->PlayDevice = NACLAUDIO_PlayDevice; + * impl->Deinitialize = NACLAUDIO_Deinitialize; */ return 1; } -AudioBootStrap NACLAUD_bootstrap = { - NACLAUD_DRIVER_NAME, "SDL NaCl Audio Driver", - NACLAUD_Init, 0 +AudioBootStrap NACLAUDIO_bootstrap = { + NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver", + NACLAUDIO_Init, 0 }; #endif /* SDL_AUDIO_DRIVER_NACL */ diff --git a/Engine/lib/sdl/src/audio/nas/SDL_nasaudio.c b/Engine/lib/sdl/src/audio/nas/SDL_nasaudio.c index 9de5ff8b4..fe15cd696 100644 --- a/Engine/lib/sdl/src/audio/nas/SDL_nasaudio.c +++ b/Engine/lib/sdl/src/audio/nas/SDL_nasaudio.c @@ -30,22 +30,21 @@ #include "SDL_timer.h" #include "SDL_audio.h" #include "SDL_loadso.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_nasaudio.h" -static struct SDL_PrivateAudioData *this2 = NULL; - - static void (*NAS_AuCloseServer) (AuServer *); static void (*NAS_AuNextEvent) (AuServer *, AuBool, AuEvent *); static AuBool(*NAS_AuDispatchEvent) (AuServer *, AuEvent *); +static void (*NAS_AuHandleEvents) (AuServer *); static AuFlowID(*NAS_AuCreateFlow) (AuServer *, AuStatus *); static void (*NAS_AuStartFlow) (AuServer *, AuFlowID, AuStatus *); static void (*NAS_AuSetElements) (AuServer *, AuFlowID, AuBool, int, AuElement *, AuStatus *); static void (*NAS_AuWriteElement) (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuBool, AuStatus *); +static AuUint32 (*NAS_AuReadElement) + (AuServer *, AuFlowID, int, AuUint32, AuPointer, AuStatus *); static AuServer *(*NAS_AuOpenServer) (_AuConst char *, int, _AuConst char *, int, _AuConst char *, char **); static AuEventHandlerRec *(*NAS_AuRegisterEventHandler) @@ -80,10 +79,12 @@ load_nas_syms(void) SDL_NAS_SYM(AuCloseServer); SDL_NAS_SYM(AuNextEvent); SDL_NAS_SYM(AuDispatchEvent); + SDL_NAS_SYM(AuHandleEvents); SDL_NAS_SYM(AuCreateFlow); SDL_NAS_SYM(AuStartFlow); SDL_NAS_SYM(AuSetElements); SDL_NAS_SYM(AuWriteElement); + SDL_NAS_SYM(AuReadElement); SDL_NAS_SYM(AuOpenServer); SDL_NAS_SYM(AuRegisterEventHandler); return 0; @@ -187,19 +188,53 @@ NAS_GetDeviceBuf(_THIS) return (this->hidden->mixbuf); } +static int +NAS_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + int retval; + + while (SDL_TRUE) { + /* just keep the event queue moving and the server chattering. */ + NAS_AuHandleEvents(h->aud); + + retval = (int) NAS_AuReadElement(h->aud, h->flow, 1, buflen, buffer, NULL); + /*printf("read %d capture bytes\n", (int) retval);*/ + if (retval == 0) { + SDL_Delay(10); /* don't burn the CPU if we're waiting for data. */ + } else { + break; + } + } + + return retval; +} + +static void +NAS_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + AuUint32 total = 0; + AuUint32 br; + Uint8 buf[512]; + + do { + /* just keep the event queue moving and the server chattering. */ + NAS_AuHandleEvents(h->aud); + br = NAS_AuReadElement(h->aud, h->flow, 1, sizeof (buf), buf, NULL); + /*printf("flushed %d capture bytes\n", (int) br);*/ + total += br; + } while ((br == sizeof (buf)) && (total < this->spec.size)); +} + static void NAS_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->aud) { - NAS_AuCloseServer(this->hidden->aud); - this->hidden->aud = 0; - } - SDL_free(this->hidden); - this2 = this->hidden = NULL; + if (this->hidden->aud) { + NAS_AuCloseServer(this->hidden->aud); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static unsigned char @@ -225,6 +260,12 @@ sdlformat_to_auformat(unsigned int fmt) static AuBool event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) { + SDL_AudioDevice *this = (SDL_AudioDevice *) hnd->data; + struct SDL_PrivateAudioData *h = this->hidden; + if (this->iscapture) { + return AuTrue; /* we don't (currently) care about any of this for capture devices */ + } + switch (ev->type) { case AuEventTypeElementNotify: { @@ -232,24 +273,24 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) switch (event->kind) { case AuElementNotifyKindLowWater: - if (this2->buf_free >= 0) { - this2->really += event->num_bytes; - gettimeofday(&this2->last_tv, 0); - this2->buf_free += event->num_bytes; + if (h->buf_free >= 0) { + h->really += event->num_bytes; + gettimeofday(&h->last_tv, 0); + h->buf_free += event->num_bytes; } else { - this2->buf_free = event->num_bytes; + h->buf_free = event->num_bytes; } break; case AuElementNotifyKindState: switch (event->cur_state) { case AuStatePause: if (event->reason != AuReasonUser) { - if (this2->buf_free >= 0) { - this2->really += event->num_bytes; - gettimeofday(&this2->last_tv, 0); - this2->buf_free += event->num_bytes; + if (h->buf_free >= 0) { + h->really += event->num_bytes; + gettimeofday(&h->last_tv, 0); + h->buf_free += event->num_bytes; } else { - this2->buf_free = event->num_bytes; + h->buf_free = event->num_bytes; } } break; @@ -261,15 +302,29 @@ event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) } static AuDeviceID -find_device(_THIS, int nch) +find_device(_THIS) { /* These "Au" things are all macros, not functions... */ + struct SDL_PrivateAudioData *h = this->hidden; + const unsigned int devicekind = this->iscapture ? AuComponentKindPhysicalInput : AuComponentKindPhysicalOutput; + const int numdevs = AuServerNumDevices(h->aud); + const int nch = this->spec.channels; int i; - for (i = 0; i < AuServerNumDevices(this->hidden->aud); i++) { - if ((AuDeviceKind(AuServerDevice(this->hidden->aud, i)) == - AuComponentKindPhysicalOutput) && - AuDeviceNumTracks(AuServerDevice(this->hidden->aud, i)) == nch) { - return AuDeviceIdentifier(AuServerDevice(this->hidden->aud, i)); + + /* Try to find exact match on channels first... */ + for (i = 0; i < numdevs; i++) { + const AuDeviceAttributes *dev = AuServerDevice(h->aud, i); + if ((AuDeviceKind(dev) == devicekind) && (AuDeviceNumTracks(dev) == nch)) { + return AuDeviceIdentifier(dev); + } + } + + /* Take anything, then... */ + for (i = 0; i < numdevs; i++) { + const AuDeviceAttributes *dev = AuServerDevice(h->aud, i); + if (AuDeviceKind(dev) == devicekind) { + this->spec.channels = AuDeviceNumTracks(dev); + return AuDeviceIdentifier(dev); } } return AuNone; @@ -288,7 +343,7 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Try for a closest match on audio format */ format = 0; @@ -300,21 +355,18 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (format == 0) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't find any hardware audio formats"); } this->spec.format = test_format; this->hidden->aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); if (this->hidden->aud == 0) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't open connection to NAS server"); } - this->hidden->dev = find_device(this, this->spec.channels); + this->hidden->dev = find_device(this); if ((this->hidden->dev == AuNone) || (!(this->hidden->flow = NAS_AuCreateFlow(this->hidden->aud, 0)))) { - NAS_CloseDevice(this); return SDL_SetError("NAS: Couldn't find a fitting device on NAS server"); } @@ -328,29 +380,38 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&this->spec); - this2 = this->hidden; + if (iscapture) { + AuMakeElementImportDevice(elms, this->spec.freq, this->hidden->dev, + AuUnlimitedSamples, 0, NULL); + AuMakeElementExportClient(elms + 1, 0, this->spec.freq, format, + this->spec.channels, AuTrue, buffer_size, + buffer_size, 0, NULL); + } else { + AuMakeElementImportClient(elms, this->spec.freq, format, + this->spec.channels, AuTrue, buffer_size, + buffer_size / 4, 0, NULL); + AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, + AuUnlimitedSamples, 0, NULL); + } + + NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, + 2, elms, NULL); - AuMakeElementImportClient(elms, this->spec.freq, format, - this->spec.channels, AuTrue, buffer_size, - buffer_size / 4, 0, NULL); - AuMakeElementExportDevice(elms + 1, 0, this->hidden->dev, this->spec.freq, - AuUnlimitedSamples, 0, NULL); - NAS_AuSetElements(this->hidden->aud, this->hidden->flow, AuTrue, 2, elms, - NULL); NAS_AuRegisterEventHandler(this->hidden->aud, AuEventHandlerIDMask, 0, this->hidden->flow, event_handler, - (AuPointer) NULL); + (AuPointer) this); NAS_AuStartFlow(this->hidden->aud, this->hidden->flow, NULL); /* Allocate mixing buffer */ - this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); - if (this->hidden->mixbuf == NULL) { - NAS_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* We're ready to rock and roll. :-) */ return 0; @@ -381,9 +442,14 @@ NAS_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = NAS_PlayDevice; impl->WaitDevice = NAS_WaitDevice; impl->GetDeviceBuf = NAS_GetDeviceBuf; + impl->CaptureFromDevice = NAS_CaptureFromDevice; + impl->FlushCapture = NAS_FlushCapture; impl->CloseDevice = NAS_CloseDevice; impl->Deinitialize = NAS_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: is this true? */ + + impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/paudio/SDL_paudio.c b/Engine/lib/sdl/src/audio/paudio/SDL_paudio.c index 14c9701f4..57202245f 100644 --- a/Engine/lib/sdl/src/audio/paudio/SDL_paudio.c +++ b/Engine/lib/sdl/src/audio/paudio/SDL_paudio.c @@ -35,7 +35,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" #include "SDL_stdinc.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_paudio.h" @@ -228,16 +227,11 @@ PAUDIO_GetDeviceBuf(_THIS) static void PAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -262,13 +256,12 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ fd = OpenAudioPath(audiodev, sizeof(audiodev), OPEN_FLAGS, 0); this->hidden->audio_fd = fd; if (fd < 0) { - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't open %s: %s", audiodev, strerror(errno)); } @@ -277,7 +270,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) * that we can have. */ if (ioctl(fd, AUDIO_BUFFER, &paud_bufinfo) < 0) { - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't get audio buffer information"); } @@ -391,7 +383,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #ifdef DEBUG_AUDIO fprintf(stderr, "Couldn't find any hardware audio formats\n"); #endif - PAUDIO_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -449,15 +440,13 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (err != NULL) { - PAUDIO_CloseDevice(this); return SDL_SetError("Paudio: %s", err); } /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - PAUDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); @@ -492,7 +481,6 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) paud_control.ioctl_request = AUDIO_START; paud_control.position = 0; if (ioctl(fd, AUDIO_CONTROL, &paud_control) < 0) { - PAUDIO_CloseDevice(this); #ifdef DEBUG_AUDIO fprintf(stderr, "Can't start audio play\n"); #endif diff --git a/Engine/lib/sdl/src/audio/psp/SDL_pspaudio.c b/Engine/lib/sdl/src/audio/psp/SDL_pspaudio.c index 18d2947e4..bd3456d3f 100644 --- a/Engine/lib/sdl/src/audio/psp/SDL_pspaudio.c +++ b/Engine/lib/sdl/src/audio/psp/SDL_pspaudio.c @@ -30,7 +30,6 @@ #include "SDL_audio.h" #include "SDL_error.h" #include "SDL_timer.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "../SDL_sysaudio.h" @@ -40,10 +39,10 @@ #include /* The tag name used by PSP audio */ -#define PSPAUD_DRIVER_NAME "psp" +#define PSPAUDIO_DRIVER_NAME "psp" static int -PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { int format, mixlen, i; this->hidden = (struct SDL_PrivateAudioData *) @@ -51,7 +50,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(*this->hidden)); + SDL_zerop(this->hidden); switch (this->spec.format & 0xff) { case 8: case 16: @@ -66,20 +65,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.freq = 44100; /* Update the fragment size as size in bytes. */ -/* SDL_CalculateAudioSpec(this->spec); MOD */ - switch (this->spec.format) { - case AUDIO_U8: - this->spec.silence = 0x80; - break; - default: - this->spec.silence = 0x00; - break; - } - this->spec.size = SDL_AUDIO_BITSIZE(this->spec.format) / 8; - this->spec.size *= this->spec.channels; - this->spec.size *= this->spec.samples; - -/* ========================================== */ + SDL_CalculateAudioSpec(&this->spec); /* Allocate the mixing buffer. Its size and starting address must be a multiple of 64 bytes. Our sample count is already a multiple of @@ -112,7 +98,7 @@ PSPAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; } -static void PSPAUD_PlayDevice(_THIS) +static void PSPAUDIO_PlayDevice(_THIS) { Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer]; @@ -126,28 +112,25 @@ static void PSPAUD_PlayDevice(_THIS) } /* This function waits until it is possible to write a full sound buffer */ -static void PSPAUD_WaitDevice(_THIS) +static void PSPAUDIO_WaitDevice(_THIS) { /* Because we block when sending audio, there's no need for this function to do anything. */ } -static Uint8 *PSPAUD_GetDeviceBuf(_THIS) +static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS) { return this->hidden->mixbufs[this->hidden->next_buffer]; } -static void PSPAUD_CloseDevice(_THIS) +static void PSPAUDIO_CloseDevice(_THIS) { if (this->hidden->channel >= 0) { sceAudioChRelease(this->hidden->channel); - this->hidden->channel = -1; - } - - if (this->hidden->rawbuf != NULL) { - free(this->hidden->rawbuf); - this->hidden->rawbuf = NULL; } + free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */ + SDL_free(this->hidden); } -static void PSPAUD_ThreadInit(_THIS) + +static void PSPAUDIO_ThreadInit(_THIS) { /* Increase the priority of this audio thread by 1 to put it ahead of other SDL threads. */ @@ -162,24 +145,22 @@ static void PSPAUD_ThreadInit(_THIS) static int -PSPAUD_Init(SDL_AudioDriverImpl * impl) +PSPAUDIO_Init(SDL_AudioDriverImpl * impl) { - /* Set the function pointers */ - impl->OpenDevice = PSPAUD_OpenDevice; - impl->PlayDevice = PSPAUD_PlayDevice; - impl->WaitDevice = PSPAUD_WaitDevice; - impl->GetDeviceBuf = PSPAUD_GetDeviceBuf; - impl->WaitDone = PSPAUD_WaitDevice; - impl->CloseDevice = PSPAUD_CloseDevice; - impl->ThreadInit = PSPAUD_ThreadInit; + impl->OpenDevice = PSPAUDIO_OpenDevice; + impl->PlayDevice = PSPAUDIO_PlayDevice; + impl->WaitDevice = PSPAUDIO_WaitDevice; + impl->GetDeviceBuf = PSPAUDIO_GetDeviceBuf; + impl->CloseDevice = PSPAUDIO_CloseDevice; + impl->ThreadInit = PSPAUDIO_ThreadInit; /* PSP audio device */ impl->OnlyHasDefaultOutputDevice = 1; /* impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultInputDevice = 1; + impl->OnlyHasDefaultCaptureDevice = 1; */ /* impl->DetectDevices = DSOUND_DetectDevices; @@ -188,8 +169,8 @@ PSPAUD_Init(SDL_AudioDriverImpl * impl) return 1; /* this audio target is available. */ } -AudioBootStrap PSPAUD_bootstrap = { - "psp", "PSP audio driver", PSPAUD_Init, 0 +AudioBootStrap PSPAUDIO_bootstrap = { + "psp", "PSP audio driver", PSPAUDIO_Init, 0 }; /* SDL_AUDI */ diff --git a/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.c b/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.c index 6b11e066f..9ced49d21 100644 --- a/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.c @@ -42,10 +42,10 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_pulseaudio.h" #include "SDL_loadso.h" +#include "../../thread/SDL_systhread.h" #if (PA_API_VERSION < 12) /** Return non-zero if the passed state is one of the connected states */ @@ -99,12 +99,19 @@ static pa_stream * (*PULSEAUDIO_pa_stream_new) (pa_context *, const char *, const pa_sample_spec *, const pa_channel_map *); static int (*PULSEAUDIO_pa_stream_connect_playback) (pa_stream *, const char *, const pa_buffer_attr *, pa_stream_flags_t, pa_cvolume *, pa_stream *); +static int (*PULSEAUDIO_pa_stream_connect_record) (pa_stream *, const char *, + const pa_buffer_attr *, pa_stream_flags_t); static pa_stream_state_t (*PULSEAUDIO_pa_stream_get_state) (pa_stream *); static size_t (*PULSEAUDIO_pa_stream_writable_size) (pa_stream *); +static size_t (*PULSEAUDIO_pa_stream_readable_size) (pa_stream *); static int (*PULSEAUDIO_pa_stream_write) (pa_stream *, const void *, size_t, pa_free_cb_t, int64_t, pa_seek_mode_t); static pa_operation * (*PULSEAUDIO_pa_stream_drain) (pa_stream *, pa_stream_success_cb_t, void *); +static int (*PULSEAUDIO_pa_stream_peek) (pa_stream *, const void **, size_t *); +static int (*PULSEAUDIO_pa_stream_drop) (pa_stream *); +static pa_operation * (*PULSEAUDIO_pa_stream_flush) (pa_stream *, + pa_stream_success_cb_t, void *); static int (*PULSEAUDIO_pa_stream_disconnect) (pa_stream *); static void (*PULSEAUDIO_pa_stream_unref) (pa_stream *); @@ -205,11 +212,16 @@ load_pulseaudio_syms(void) SDL_PULSEAUDIO_SYM(pa_context_unref); SDL_PULSEAUDIO_SYM(pa_stream_new); SDL_PULSEAUDIO_SYM(pa_stream_connect_playback); + SDL_PULSEAUDIO_SYM(pa_stream_connect_record); SDL_PULSEAUDIO_SYM(pa_stream_get_state); SDL_PULSEAUDIO_SYM(pa_stream_writable_size); + SDL_PULSEAUDIO_SYM(pa_stream_readable_size); SDL_PULSEAUDIO_SYM(pa_stream_write); SDL_PULSEAUDIO_SYM(pa_stream_drain); SDL_PULSEAUDIO_SYM(pa_stream_disconnect); + SDL_PULSEAUDIO_SYM(pa_stream_peek); + SDL_PULSEAUDIO_SYM(pa_stream_drop); + SDL_PULSEAUDIO_SYM(pa_stream_flush); SDL_PULSEAUDIO_SYM(pa_stream_unref); SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto); SDL_PULSEAUDIO_SYM(pa_strerror); @@ -238,6 +250,12 @@ getAppName(void) return "SDL Application"; /* oh well. */ } +static void +stream_operation_complete_no_op(pa_stream *s, int success, void *userdata) +{ + /* no-op for pa_stream_drain(), etc, to use for callback. */ +} + static void WaitForPulseOperation(pa_mainloop *mainloop, pa_operation *o) { @@ -325,7 +343,7 @@ PULSEAUDIO_WaitDevice(_THIS) { struct SDL_PrivateAudioData *h = this->hidden; - while (this->enabled) { + while (SDL_AtomicGet(&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) { @@ -343,41 +361,13 @@ PULSEAUDIO_PlayDevice(_THIS) { /* Write the audio data */ struct SDL_PrivateAudioData *h = this->hidden; - if (this->enabled) { + if (SDL_AtomicGet(&this->enabled)) { if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { SDL_OpenedAudioDeviceDisconnected(this); } } } -static void -stream_drain_complete(pa_stream *s, int success, void *userdata) -{ - /* no-op for pa_stream_drain() to use for callback. */ -} - -static void -PULSEAUDIO_WaitDone(_THIS) -{ - if (this->enabled) { - struct SDL_PrivateAudioData *h = this->hidden; - pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL); - if (o) { - while (PULSEAUDIO_pa_operation_get_state(o) != PA_OPERATION_DONE) { - if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || - PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || - PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_pa_operation_cancel(o); - break; - } - } - PULSEAUDIO_pa_operation_unref(o); - } - } -} - - - static Uint8 * PULSEAUDIO_GetDeviceBuf(_THIS) { @@ -385,24 +375,96 @@ PULSEAUDIO_GetDeviceBuf(_THIS) } +static int +PULSEAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + struct SDL_PrivateAudioData *h = this->hidden; + const void *data = NULL; + size_t nbytes = 0; + + while (SDL_AtomicGet(&this->enabled)) { + if (h->capturebuf != NULL) { + const int cpy = SDL_min(buflen, h->capturelen); + SDL_memcpy(buffer, h->capturebuf, cpy); + /*printf("PULSEAUDIO: fed %d captured bytes\n", cpy);*/ + h->capturebuf += cpy; + h->capturelen -= cpy; + if (h->capturelen == 0) { + h->capturebuf = NULL; + PULSEAUDIO_pa_stream_drop(h->stream); /* done with this fragment. */ + } + return cpy; /* new data, return it. */ + } + + if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY || + PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY || + PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + SDL_OpenedAudioDeviceDisconnected(this); + return -1; /* uhoh, pulse failed! */ + } + + if (PULSEAUDIO_pa_stream_readable_size(h->stream) == 0) { + continue; /* no data available yet. */ + } + + /* a new fragment is available! */ + PULSEAUDIO_pa_stream_peek(h->stream, &data, &nbytes); + SDL_assert(nbytes > 0); + if (data == NULL) { /* NULL==buffer had a hole. Ignore that. */ + PULSEAUDIO_pa_stream_drop(h->stream); /* drop this fragment. */ + } else { + /* store this fragment's data, start feeding it to SDL. */ + /*printf("PULSEAUDIO: captured %d new bytes\n", (int) nbytes);*/ + h->capturebuf = (const Uint8 *) data; + h->capturelen = nbytes; + } + } + + return -1; /* not enabled? */ +} + +static void +PULSEAUDIO_FlushCapture(_THIS) +{ + struct SDL_PrivateAudioData *h = this->hidden; + + if (h->capturebuf != NULL) { + PULSEAUDIO_pa_stream_drop(h->stream); + h->capturebuf = NULL; + h->capturelen = 0; + } + + WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_stream_flush(h->stream, stream_operation_complete_no_op, NULL)); +} + static void PULSEAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - SDL_free(this->hidden->device_name); - if (this->hidden->stream) { - PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); - PULSEAUDIO_pa_stream_unref(this->hidden->stream); + if (this->hidden->stream) { + if (this->hidden->capturebuf != NULL) { + PULSEAUDIO_pa_stream_drop(this->hidden->stream); } - DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); - SDL_free(this->hidden); - this->hidden = NULL; + PULSEAUDIO_pa_stream_disconnect(this->hidden->stream); + PULSEAUDIO_pa_stream_unref(this->hidden->stream); + } + + DisconnectFromPulseServer(this->hidden->mainloop, this->hidden->context); + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden->device_name); + SDL_free(this->hidden); +} + +static void +SinkDeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +{ + if (i) { + char **devname = (char **) data; + *devname = SDL_strdup(i->name); } } static void -DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data) +SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, void *data) { if (i) { char **devname = (char **) data; @@ -411,7 +473,7 @@ DeviceNameCallback(pa_context *c, const pa_sink_info *i, int is_last, void *data } static SDL_bool -FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) +FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle) { const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; @@ -419,7 +481,16 @@ FindDeviceName(struct SDL_PrivateAudioData *h, void *handle) return SDL_TRUE; } - WaitForPulseOperation(h->mainloop, PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, DeviceNameCallback, &h->device_name)); + if (iscapture) { + WaitForPulseOperation(h->mainloop, + PULSEAUDIO_pa_context_get_source_info_by_index(h->context, idx, + SourceDeviceNameCallback, &h->device_name)); + } else { + WaitForPulseOperation(h->mainloop, + PULSEAUDIO_pa_context_get_sink_info_by_index(h->context, idx, + SinkDeviceNameCallback, &h->device_name)); + } + return (h->device_name != NULL); } @@ -433,15 +504,15 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) pa_channel_map pacmap; pa_stream_flags_t flags = 0; int state = 0; + int rc = 0; /* Initialize all variables that we clean on shutdown */ - this->hidden = (struct SDL_PrivateAudioData *) + h = 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)); - h = this->hidden; + SDL_zerop(this->hidden); paspec.format = PA_SAMPLE_INVALID; @@ -482,7 +553,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } if (paspec.format == PA_SAMPLE_INVALID) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Couldn't find any hardware audio formats"); } this->spec.format = test_format; @@ -494,13 +564,14 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - h->mixlen = this->spec.size; - h->mixbuf = (Uint8 *) SDL_AllocAudioMem(h->mixlen); - if (h->mixbuf == NULL) { - PULSEAUDIO_CloseDevice(this); - return SDL_OutOfMemory(); + if (!iscapture) { + h->mixlen = this->spec.size; + h->mixbuf = (Uint8 *) SDL_malloc(h->mixlen); + if (h->mixbuf == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(h->mixbuf, this->spec.silence, this->spec.size); } - SDL_memset(h->mixbuf, this->spec.silence, this->spec.size); paspec.channels = this->spec.channels; paspec.rate = this->spec.freq; @@ -522,13 +593,11 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif if (ConnectToPulseServer(&h->mainloop, &h->context) < 0) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect to PulseAudio server"); } - if (!FindDeviceName(h, handle)) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Requested PulseAudio sink missing?"); + if (!FindDeviceName(h, iscapture, handle)) { + return SDL_SetError("Requested PulseAudio sink/source missing?"); } /* The SDL ALSA output hints us that we use Windows' channel mapping */ @@ -544,7 +613,6 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) ); if (h->stream == NULL) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not set up PulseAudio stream"); } @@ -554,20 +622,22 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) flags |= PA_STREAM_DONT_MOVE; } - if (PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, - NULL, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); + if (iscapture) { + rc = PULSEAUDIO_pa_stream_connect_record(h->stream, h->device_name, &paattr, flags); + } else { + rc = PULSEAUDIO_pa_stream_connect_playback(h->stream, h->device_name, &paattr, flags, NULL, NULL); + } + + if (rc < 0) { return SDL_SetError("Could not connect PulseAudio stream"); } do { if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("pa_mainloop_iterate() failed"); } state = PULSEAUDIO_pa_stream_get_state(h->stream); if (!PA_STREAM_IS_GOOD(state)) { - PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); } } while (state != PA_STREAM_READY); @@ -646,7 +716,7 @@ PULSEAUDIO_DetectDevices() 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); + hotplug_thread = SDL_CreateThreadInternal(HotplugThread, "PulseHotplug", 256 * 1024, NULL); } static void @@ -684,8 +754,11 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = PULSEAUDIO_WaitDevice; impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf; impl->CloseDevice = PULSEAUDIO_CloseDevice; - impl->WaitDone = PULSEAUDIO_WaitDone; impl->Deinitialize = PULSEAUDIO_Deinitialize; + impl->CaptureFromDevice = PULSEAUDIO_CaptureFromDevice; + impl->FlushCapture = PULSEAUDIO_FlushCapture; + + impl->HasCaptureSupport = SDL_TRUE; return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.h b/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.h index c57ab7132..e12000f2a 100644 --- a/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.h +++ b/Engine/lib/sdl/src/audio/pulseaudio/SDL_pulseaudio.h @@ -42,6 +42,9 @@ struct SDL_PrivateAudioData /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; + + const Uint8 *capturebuf; + int capturelen; }; #endif /* _SDL_pulseaudio_h */ diff --git a/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c b/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c index 1899ca6d9..149cad90a 100644 --- a/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c +++ b/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.c @@ -45,7 +45,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_qsa_audio.h" @@ -138,8 +137,7 @@ QSA_ThreadInit(_THIS) static void QSA_InitAudioParams(snd_pcm_channel_params_t * cpars) { - SDL_memset(cpars, 0, sizeof(snd_pcm_channel_params_t)); - + SDL_zerop(cpars); cpars->channel = SND_PCM_CHANNEL_PLAYBACK; cpars->mode = SND_PCM_MODE_BLOCK; cpars->start_mode = SND_PCM_START_DATA; @@ -229,7 +227,7 @@ QSA_PlayDevice(_THIS) int towrite; void *pcmbuffer; - if ((!this->enabled) || (!this->hidden)) { + if (!SDL_AtomicGet(&this->enabled) || !this->hidden) { return; } @@ -262,7 +260,7 @@ QSA_PlayDevice(_THIS) continue; } else { if ((errno == EINVAL) || (errno == EIO)) { - SDL_memset(&cstatus, 0, sizeof(cstatus)); + SDL_zero(cstatus); if (!this->hidden->iscapture) { cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; } else { @@ -305,7 +303,7 @@ QSA_PlayDevice(_THIS) towrite -= written; pcmbuffer += written * this->spec.channels; } - } while ((towrite > 0) && (this->enabled)); + } while ((towrite > 0) && SDL_AtomicGet(&this->enabled)); /* If we couldn't write, assume fatal error for now */ if (towrite != 0) { @@ -322,27 +320,21 @@ QSA_GetDeviceBuf(_THIS) static void QSA_CloseDevice(_THIS) { - if (this->hidden != NULL) { - if (this->hidden->audio_handle != NULL) { - if (!this->hidden->iscapture) { - /* Finish playing available samples */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_PLAYBACK); - } else { - /* Cancel unread samples during capture */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_CAPTURE); - } - snd_pcm_close(this->hidden->audio_handle); - this->hidden->audio_handle = NULL; + if (this->hidden->audio_handle != NULL) { + if (!this->hidden->iscapture) { + /* Finish playing available samples */ + snd_pcm_plugin_flush(this->hidden->audio_handle, + SND_PCM_CHANNEL_PLAYBACK); + } else { + /* Cancel unread samples during capture */ + snd_pcm_plugin_flush(this->hidden->audio_handle, + SND_PCM_CHANNEL_CAPTURE); } - - SDL_FreeAudioMem(this->hidden->pcm_buf); - this->hidden->pcm_buf = NULL; - - SDL_free(this->hidden); - this->hidden = NULL; + snd_pcm_close(this->hidden->audio_handle); } + + SDL_free(this->hidden->pcm_buf); + SDL_free(this->hidden); } static int @@ -365,13 +357,13 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(struct SDL_PrivateAudioData)); + SDL_zerop(this->hidden); /* Initialize channel transfer parameters to default */ QSA_InitAudioParams(&cparams); /* Initialize channel direction: capture or playback */ - this->hidden->iscapture = iscapture; + this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; if (device != NULL) { /* Open requested audio device */ @@ -391,7 +383,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Check if requested device is opened */ if (status < 0) { this->hidden->audio_handle = NULL; - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_open", status); } @@ -401,7 +392,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) snd_pcm_plugin_set_disable(this->hidden->audio_handle, PLUGIN_DISABLE_MMAP); if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_plugin_set_disable", status); } } @@ -487,7 +477,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* assumes test_format not 0 on success */ if (test_format == 0) { - QSA_CloseDevice(this); return SDL_SetError("QSA: Couldn't find any hardware audio formats"); } @@ -505,12 +494,11 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Setup the transfer parameters according to cparams */ status = snd_pcm_plugin_params(this->hidden->audio_handle, &cparams); if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_channel_params", status); } /* Make sure channel is setup right one last time */ - SDL_memset(&csetup, 0, sizeof(csetup)); + SDL_zero(csetup); if (!this->hidden->iscapture) { csetup.channel = SND_PCM_CHANNEL_PLAYBACK; } else { @@ -519,7 +507,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Setup an audio channel */ if (snd_pcm_plugin_setup(this->hidden->audio_handle, &csetup) < 0) { - QSA_CloseDevice(this); return SDL_SetError("QSA: Unable to setup channel"); } @@ -540,9 +527,8 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) * closest multiple) */ this->hidden->pcm_buf = - (Uint8 *) SDL_AllocAudioMem(this->hidden->pcm_len); + (Uint8 *) SDL_malloc(this->hidden->pcm_len); if (this->hidden->pcm_buf == NULL) { - QSA_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->pcm_buf, this->spec.silence, @@ -560,7 +546,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (this->hidden->audio_fd < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_file_descriptor", status); } @@ -578,7 +563,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (status < 0) { - QSA_CloseDevice(this); return QSA_SetError("snd_pcm_plugin_prepare", status); } @@ -724,32 +708,13 @@ QSA_DetectDevices(void) } } -static void -QSA_WaitDone(_THIS) -{ - if (!this->hidden->iscapture) { - if (this->hidden->audio_handle != NULL) { - /* Wait till last fragment is played and stop channel */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_PLAYBACK); - } - } else { - if (this->hidden->audio_handle != NULL) { - /* Discard all unread data and stop channel */ - snd_pcm_plugin_flush(this->hidden->audio_handle, - SND_PCM_CHANNEL_CAPTURE); - } - } -} - static void QSA_Deinitialize(void) { /* Clear devices array on shutdown */ - SDL_memset(qsa_playback_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); - SDL_memset(qsa_capture_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); + /* !!! FIXME: we zero these on init...any reason to do it here? */ + SDL_zero(qsa_playback_device); + SDL_zero(qsa_capture_device); qsa_playback_devices = 0; qsa_capture_devices = 0; } @@ -761,10 +726,8 @@ QSA_Init(SDL_AudioDriverImpl * impl) int32_t status = 0; /* Clear devices array */ - SDL_memset(qsa_playback_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); - SDL_memset(qsa_capture_device, 0x00, - sizeof(QSA_Device) * QSA_MAX_DEVICES); + SDL_zero(qsa_playback_device); + SDL_zero(qsa_capture_device); qsa_playback_devices = 0; qsa_capture_devices = 0; @@ -778,7 +741,6 @@ QSA_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = QSA_PlayDevice; impl->GetDeviceBuf = QSA_GetDeviceBuf; impl->CloseDevice = QSA_CloseDevice; - impl->WaitDone = QSA_WaitDone; impl->Deinitialize = QSA_Deinitialize; impl->LockDevice = NULL; impl->UnlockDevice = NULL; @@ -788,7 +750,7 @@ QSA_Init(SDL_AudioDriverImpl * impl) impl->SkipMixerLock = 0; impl->HasCaptureSupport = 1; impl->OnlyHasDefaultOutputDevice = 0; - impl->OnlyHasDefaultInputDevice = 0; + impl->OnlyHasDefaultCaptureDevice = 0; /* Check if io-audio manager is running or not */ status = snd_cards(); diff --git a/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.h b/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.h index 53d37e96f..19a2215aa 100644 --- a/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.h +++ b/Engine/lib/sdl/src/audio/qsa/SDL_qsa_audio.h @@ -34,7 +34,7 @@ struct SDL_PrivateAudioData { /* SDL capture state */ - int iscapture; + SDL_bool iscapture; /* The audio device handle */ int cardno; diff --git a/Engine/lib/sdl/src/audio/sndio/SDL_sndioaudio.c b/Engine/lib/sdl/src/audio/sndio/SDL_sndioaudio.c index 64565ae88..fb7d78ff1 100644 --- a/Engine/lib/sdl/src/audio/sndio/SDL_sndioaudio.c +++ b/Engine/lib/sdl/src/audio/sndio/SDL_sndioaudio.c @@ -36,7 +36,6 @@ #include #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "SDL_sndioaudio.h" @@ -171,25 +170,15 @@ SNDIO_GetDeviceBuf(_THIS) return this->hidden->mixbuf; } -static void -SNDIO_WaitDone(_THIS) -{ - SNDIO_sio_stop(this->hidden->dev); -} - static void SNDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - if ( this->hidden->dev != NULL ) { - SNDIO_sio_close(this->hidden->dev); - this->hidden->dev = NULL; - } - SDL_free(this->hidden); - this->hidden = NULL; + if ( this->hidden->dev != NULL ) { + SNDIO_sio_stop(this->hidden->dev); + SNDIO_sio_close(this->hidden->dev); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -204,13 +193,12 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, sizeof(*this->hidden)); + SDL_zerop(this->hidden); this->hidden->mixlen = this->spec.size; /* !!! FIXME: SIO_DEVANY can be a specific device... */ if ((this->hidden->dev = SNDIO_sio_open(SIO_DEVANY, SIO_PLAY, 0)) == NULL) { - SNDIO_CloseDevice(this); return SDL_SetError("sio_open() failed"); } @@ -233,7 +221,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) continue; } if (SNDIO_sio_getpar(this->hidden->dev, &par) == 0) { - SNDIO_CloseDevice(this); return SDL_SetError("sio_getpar() failed"); } if (par.bps != SIO_BPS(par.bits)) { @@ -248,7 +235,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (status < 0) { - SNDIO_CloseDevice(this); return SDL_SetError("sndio: Couldn't find any hardware audio formats"); } @@ -269,7 +255,6 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) else if ((par.bps == 1) && (!par.sig)) this->spec.format = AUDIO_U8; else { - SNDIO_CloseDevice(this); return SDL_SetError("sndio: Got unsupported hardware audio format."); } @@ -282,9 +267,8 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Allocate mixing buffer */ this->hidden->mixlen = this->spec.size; - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - SNDIO_CloseDevice(this); return SDL_OutOfMemory(); } SDL_memset(this->hidden->mixbuf, this->spec.silence, this->hidden->mixlen); @@ -315,7 +299,6 @@ SNDIO_Init(SDL_AudioDriverImpl * impl) impl->WaitDevice = SNDIO_WaitDevice; impl->PlayDevice = SNDIO_PlayDevice; impl->GetDeviceBuf = SNDIO_GetDeviceBuf; - impl->WaitDone = SNDIO_WaitDone; impl->CloseDevice = SNDIO_CloseDevice; impl->Deinitialize = SNDIO_Deinitialize; impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: sndio can handle multiple devices. */ diff --git a/Engine/lib/sdl/src/audio/sun/SDL_sunaudio.c b/Engine/lib/sdl/src/audio/sun/SDL_sunaudio.c index 71029d21f..b994c12c3 100644 --- a/Engine/lib/sdl/src/audio/sun/SDL_sunaudio.c +++ b/Engine/lib/sdl/src/audio/sun/SDL_sunaudio.c @@ -40,7 +40,6 @@ #include "SDL_timer.h" #include "SDL_audio.h" -#include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_sunaudio.h" @@ -183,18 +182,12 @@ SUNAUDIO_GetDeviceBuf(_THIS) static void SUNAUDIO_CloseDevice(_THIS) { - if (this->hidden != NULL) { - SDL_FreeAudioMem(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - SDL_free(this->hidden->ulaw_buf); - this->hidden->ulaw_buf = NULL; - if (this->hidden->audio_fd >= 0) { - close(this->hidden->audio_fd); - this->hidden->audio_fd = -1; - } - SDL_free(this->hidden); - this->hidden = NULL; + SDL_free(this->hidden->ulaw_buf); + if (this->hidden->audio_fd >= 0) { + close(this->hidden->audio_fd); } + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -219,7 +212,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Open the audio device */ this->hidden->audio_fd = open(devname, flags, 0); @@ -340,7 +333,7 @@ SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_CalculateAudioSpec(&this->spec); /* Allocate mixing buffer */ - this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->spec.size); + this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size); if (this->hidden->mixbuf == NULL) { return SDL_OutOfMemory(); } diff --git a/Engine/lib/sdl/src/audio/winmm/SDL_winmm.c b/Engine/lib/sdl/src/audio/winmm/SDL_winmm.c index 6d05a65ef..34f543ddb 100644 --- a/Engine/lib/sdl/src/audio/winmm/SDL_winmm.c +++ b/Engine/lib/sdl/src/audio/winmm/SDL_winmm.c @@ -27,6 +27,7 @@ #include "../../core/windows/SDL_windows.h" #include +#include "SDL_assert.h" #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audio_c.h" @@ -40,11 +41,11 @@ static void DetectWave##typ##Devs(void) { \ const UINT iscapture = iscap ? 1 : 0; \ const UINT devcount = wave##typ##GetNumDevs(); \ - capstyp caps; \ + capstyp##2W caps; \ UINT i; \ for (i = 0; i < devcount; i++) { \ - if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ - char *name = WIN_StringToUTF8(caps.szPname); \ + if (wave##typ##GetDevCaps(i,(LP##capstyp##W)&caps,sizeof(caps))==MMSYSERR_NOERROR) { \ + char *name = WIN_LookupAudioDeviceName(caps.szPname,&caps.NameGuid); \ if (name != NULL) { \ SDL_AddAudioDevice((int) iscapture, name, (void *) ((size_t) i+1)); \ SDL_free(name); \ @@ -134,63 +135,87 @@ WINMM_PlayDevice(_THIS) this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; } -static void -WINMM_WaitDone(_THIS) +static int +WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen) { - int i, left; + const int nextbuf = this->hidden->next_buffer; + MMRESULT result; - do { - left = NUM_BUFFERS; - for (i = 0; i < NUM_BUFFERS; ++i) { - if (this->hidden->wavebuf[i].dwFlags & WHDR_DONE) { - --left; - } - } - if (left > 0) { - SDL_Delay(100); - } - } while (left > 0); + SDL_assert(buflen == this->spec.size); + + /* Wait for an audio chunk to finish */ + WaitForSingleObject(this->hidden->audio_sem, INFINITE); + + /* Copy it to caller's buffer... */ + SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size); + + /* requeue the buffer that just finished. */ + result = waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[nextbuf], + sizeof (this->hidden->wavebuf[nextbuf])); + if (result != MMSYSERR_NOERROR) { + return -1; /* uhoh! Disable the device. */ + } + + /* queue the next buffer in sequence, next time. */ + this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS; + return this->spec.size; +} + +static void +WINMM_FlushCapture(_THIS) +{ + /* Wait for an audio chunk to finish */ + if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) { + const int nextbuf = this->hidden->next_buffer; + /* requeue the buffer that just finished without reading from it. */ + waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[nextbuf], + sizeof (this->hidden->wavebuf[nextbuf])); + this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS; + } } static void WINMM_CloseDevice(_THIS) { - /* Close up audio */ - if (this->hidden != NULL) { - int i; + int i; - if (this->hidden->audio_sem) { - CloseHandle(this->hidden->audio_sem); - this->hidden->audio_sem = 0; - } + if (this->hidden->hout) { + waveOutReset(this->hidden->hout); /* Clean up mixing buffers */ for (i = 0; i < NUM_BUFFERS; ++i) { if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { waveOutUnprepareHeader(this->hidden->hout, &this->hidden->wavebuf[i], - sizeof(this->hidden->wavebuf[i])); - this->hidden->wavebuf[i].dwUser = 0xFFFF; + sizeof (this->hidden->wavebuf[i])); } } - /* Free raw mixing buffer */ - SDL_free(this->hidden->mixbuf); - this->hidden->mixbuf = NULL; - - if (this->hidden->hin) { - waveInClose(this->hidden->hin); - this->hidden->hin = 0; - } - - if (this->hidden->hout) { - waveOutClose(this->hidden->hout); - this->hidden->hout = 0; - } - - SDL_free(this->hidden); - this->hidden = NULL; + waveOutClose(this->hidden->hout); } + + if (this->hidden->hin) { + waveInReset(this->hidden->hin); + + /* Clean up mixing buffers */ + for (i = 0; i < NUM_BUFFERS; ++i) { + if (this->hidden->wavebuf[i].dwUser != 0xFFFF) { + waveInUnprepareHeader(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof (this->hidden->wavebuf[i])); + } + } + waveInClose(this->hidden->hin); + } + + if (this->hidden->audio_sem) { + CloseHandle(this->hidden->audio_sem); + } + + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static SDL_bool @@ -239,7 +264,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); /* Initialize the wavebuf structures for closing */ for (i = 0; i < NUM_BUFFERS; ++i) @@ -269,7 +294,6 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_datatype) { - WINMM_CloseDevice(this); return SDL_SetError("Unsupported audio format"); } @@ -281,36 +305,45 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) result = waveInOpen(&this->hidden->hin, devId, &waveformat, (DWORD_PTR) CaptureSound, (DWORD_PTR) this, CALLBACK_FUNCTION); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInOpen()", result); + } } else { result = waveOutOpen(&this->hidden->hout, devId, &waveformat, (DWORD_PTR) FillSound, (DWORD_PTR) this, CALLBACK_FUNCTION); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutOpen()", result); + } } - if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); - return SetMMerror("waveOutOpen()", result); - } #ifdef SOUND_DEBUG /* Check the sound device we retrieved */ { - WAVEOUTCAPS caps; - - result = waveOutGetDevCaps((UINT) this->hidden->hout, - &caps, sizeof(caps)); - if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); - return SetMMerror("waveOutGetDevCaps()", result); + if (iscapture) { + WAVEINCAPS caps; + result = waveInGetDevCaps((UINT) this->hidden->hout, + &caps, sizeof (caps)); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInGetDevCaps()", result); + } + printf("Audio device: %s\n", caps.szPname); + } else { + WAVEOUTCAPS caps; + result = waveOutGetDevCaps((UINT) this->hidden->hout, + &caps, sizeof(caps)); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutGetDevCaps()", result); + } + printf("Audio device: %s\n", caps.szPname); } - printf("Audio device: %s\n", caps.szPname); } #endif /* Create the audio buffer semaphore */ this->hidden->audio_sem = - CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL); + CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL); if (this->hidden->audio_sem == NULL) { - WINMM_CloseDevice(this); return SDL_SetError("Couldn't create semaphore"); } @@ -318,22 +351,44 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixbuf = (Uint8 *) SDL_malloc(NUM_BUFFERS * this->spec.size); if (this->hidden->mixbuf == NULL) { - WINMM_CloseDevice(this); return SDL_OutOfMemory(); } + + SDL_zero(this->hidden->wavebuf); for (i = 0; i < NUM_BUFFERS; ++i) { - SDL_memset(&this->hidden->wavebuf[i], 0, - sizeof(this->hidden->wavebuf[i])); this->hidden->wavebuf[i].dwBufferLength = this->spec.size; this->hidden->wavebuf[i].dwFlags = WHDR_DONE; this->hidden->wavebuf[i].lpData = (LPSTR) & this->hidden->mixbuf[i * this->spec.size]; - result = waveOutPrepareHeader(this->hidden->hout, - &this->hidden->wavebuf[i], - sizeof(this->hidden->wavebuf[i])); + + if (iscapture) { + result = waveInPrepareHeader(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInPrepareHeader()", result); + } + + result = waveInAddBuffer(this->hidden->hin, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveInAddBuffer()", result); + } + } else { + result = waveOutPrepareHeader(this->hidden->hout, + &this->hidden->wavebuf[i], + sizeof(this->hidden->wavebuf[i])); + if (result != MMSYSERR_NOERROR) { + return SetMMerror("waveOutPrepareHeader()", result); + } + } + } + + if (iscapture) { + result = waveInStart(this->hidden->hin); if (result != MMSYSERR_NOERROR) { - WINMM_CloseDevice(this); - return SetMMerror("waveOutPrepareHeader()", result); + return SetMMerror("waveInStart()", result); } } @@ -349,10 +404,13 @@ WINMM_Init(SDL_AudioDriverImpl * impl) impl->OpenDevice = WINMM_OpenDevice; impl->PlayDevice = WINMM_PlayDevice; impl->WaitDevice = WINMM_WaitDevice; - impl->WaitDone = WINMM_WaitDone; impl->GetDeviceBuf = WINMM_GetDeviceBuf; + impl->CaptureFromDevice = WINMM_CaptureFromDevice; + impl->FlushCapture = WINMM_FlushCapture; impl->CloseDevice = WINMM_CloseDevice; + impl->HasCaptureSupport = SDL_TRUE; + return 1; /* this audio target is available. */ } diff --git a/Engine/lib/sdl/src/audio/xaudio2/SDL_xaudio2.c b/Engine/lib/sdl/src/audio/xaudio2/SDL_xaudio2.c index dff234b40..a18e5d24e 100644 --- a/Engine/lib/sdl/src/audio/xaudio2/SDL_xaudio2.c +++ b/Engine/lib/sdl/src/audio/xaudio2/SDL_xaudio2.c @@ -195,7 +195,7 @@ XAUDIO2_PlayDevice(_THIS) IXAudio2SourceVoice *source = this->hidden->source; HRESULT result = S_OK; - if (!this->enabled) { /* shutting down? */ + if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */ return; } @@ -226,64 +226,47 @@ XAUDIO2_PlayDevice(_THIS) static void XAUDIO2_WaitDevice(_THIS) { - if (this->enabled) { + if (SDL_AtomicGet(&this->enabled)) { SDL_SemWait(this->hidden->semaphore); } } static void -XAUDIO2_WaitDone(_THIS) +XAUDIO2_PrepareToClose(_THIS) { IXAudio2SourceVoice *source = this->hidden->source; - XAUDIO2_VOICE_STATE state; - SDL_assert(!this->enabled); /* flag that stops playing. */ - IXAudio2SourceVoice_Discontinuity(source); -#if SDL_XAUDIO2_WIN8 - IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); -#else - IXAudio2SourceVoice_GetState(source, &state); -#endif - while (state.BuffersQueued > 0) { - SDL_SemWait(this->hidden->semaphore); -#if SDL_XAUDIO2_WIN8 - IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED); -#else - IXAudio2SourceVoice_GetState(source, &state); -#endif + if (source) { + IXAudio2SourceVoice_Discontinuity(source); } } - static void XAUDIO2_CloseDevice(_THIS) { - if (this->hidden != NULL) { - IXAudio2 *ixa2 = this->hidden->ixa2; - IXAudio2SourceVoice *source = this->hidden->source; - IXAudio2MasteringVoice *mastering = this->hidden->mastering; + IXAudio2 *ixa2 = this->hidden->ixa2; + IXAudio2SourceVoice *source = this->hidden->source; + IXAudio2MasteringVoice *mastering = this->hidden->mastering; - if (source != NULL) { - IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); - IXAudio2SourceVoice_FlushSourceBuffers(source); - IXAudio2SourceVoice_DestroyVoice(source); - } - if (ixa2 != NULL) { - IXAudio2_StopEngine(ixa2); - } - if (mastering != NULL) { - IXAudio2MasteringVoice_DestroyVoice(mastering); - } - if (ixa2 != NULL) { - IXAudio2_Release(ixa2); - } - SDL_free(this->hidden->mixbuf); - if (this->hidden->semaphore != NULL) { - SDL_DestroySemaphore(this->hidden->semaphore); - } - - SDL_free(this->hidden); - this->hidden = NULL; + if (source != NULL) { + IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW); + IXAudio2SourceVoice_FlushSourceBuffers(source); + IXAudio2SourceVoice_DestroyVoice(source); } + if (ixa2 != NULL) { + IXAudio2_StopEngine(ixa2); + } + if (mastering != NULL) { + IXAudio2MasteringVoice_DestroyVoice(mastering); + } + if (ixa2 != NULL) { + IXAudio2_Release(ixa2); + } + if (this->hidden->semaphore != NULL) { + SDL_DestroySemaphore(this->hidden->semaphore); + } + + SDL_free(this->hidden->mixbuf); + SDL_free(this->hidden); } static int @@ -345,12 +328,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) IXAudio2_Release(ixa2); return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + SDL_zerop(this->hidden); this->hidden->ixa2 = ixa2; this->hidden->semaphore = SDL_CreateSemaphore(1); if (this->hidden->semaphore == NULL) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: CreateSemaphore() failed!"); } @@ -368,7 +350,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } if (!valid_format) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Unsupported audio format"); } @@ -379,11 +360,10 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->mixlen = this->spec.size; this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen); if (this->hidden->mixbuf == NULL) { - XAUDIO2_CloseDevice(this); return SDL_OutOfMemory(); } this->hidden->nextbuf = this->hidden->mixbuf; - SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen); + SDL_memset(this->hidden->mixbuf, this->spec.silence, 2 * this->hidden->mixlen); /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On Xbox360, this means 5.1 output, but on Windows, it means "figure out @@ -401,7 +381,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->spec.freq, 0, devId, NULL); #endif if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't create mastering voice"); } @@ -436,7 +415,6 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) #endif if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't create source voice"); } this->hidden->source = source; @@ -444,13 +422,11 @@ XAUDIO2_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Start everything playing! */ result = IXAudio2_StartEngine(ixa2); if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't start engine"); } result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW); if (result != S_OK) { - XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't start source voice"); } @@ -499,7 +475,7 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl) impl->OpenDevice = XAUDIO2_OpenDevice; impl->PlayDevice = XAUDIO2_PlayDevice; impl->WaitDevice = XAUDIO2_WaitDevice; - impl->WaitDone = XAUDIO2_WaitDone; + impl->PrepareToClose = XAUDIO2_PrepareToClose; impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf; impl->CloseDevice = XAUDIO2_CloseDevice; impl->Deinitialize = XAUDIO2_Deinitialize; diff --git a/Engine/lib/sdl/src/core/android/SDL_android.c b/Engine/lib/sdl/src/core/android/SDL_android.c index f6e0a833c..b93b16255 100644 --- a/Engine/lib/sdl/src/core/android/SDL_android.c +++ b/Engine/lib/sdl/src/core/android/SDL_android.c @@ -71,10 +71,14 @@ static jclass mActivityClass; /* method signatures */ static jmethodID midGetNativeSurface; -static jmethodID midAudioInit; +static jmethodID midAudioOpen; static jmethodID midAudioWriteShortBuffer; static jmethodID midAudioWriteByteBuffer; -static jmethodID midAudioQuit; +static jmethodID midAudioClose; +static jmethodID midCaptureOpen; +static jmethodID midCaptureReadShortBuffer; +static jmethodID midCaptureReadByteBuffer; +static jmethodID midCaptureClose; static jmethodID midPollInputDevices; /* Accelerometer data storage */ @@ -118,34 +122,45 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "getNativeSurface","()Landroid/view/Surface;"); - midAudioInit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, - "audioInit", "(IZZI)I"); + midAudioOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "audioOpen", "(IZZI)I"); midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "audioWriteShortBuffer", "([S)V"); midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "audioWriteByteBuffer", "([B)V"); - midAudioQuit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, - "audioQuit", "()V"); + midAudioClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "audioClose", "()V"); + midCaptureOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "captureOpen", "(IZZI)I"); + midCaptureReadShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "captureReadShortBuffer", "([SZ)I"); + midCaptureReadByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "captureReadByteBuffer", "([BZ)I"); + midCaptureClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "captureClose", "()V"); midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "pollInputDevices", "()V"); bHasNewData = SDL_FALSE; - if (!midGetNativeSurface || !midAudioInit || - !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) { + if (!midGetNativeSurface || + !midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose || + !midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose || + !midPollInputDevices) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); } __android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init() finished!"); } /* Drop file */ -void Java_org_libsdl_app_SDLActivity_onNativeDropFile( +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeDropFile( JNIEnv* env, jclass jcls, jstring filename) { const char *path = (*env)->GetStringUTFChars(env, filename, NULL); - SDL_SendDropFile(path); + SDL_SendDropFile(NULL, path); (*env)->ReleaseStringUTFChars(env, filename, path); + SDL_SendDropComplete(NULL); } /* Resize */ @@ -555,11 +570,15 @@ int Android_JNI_SetupThread(void) static jboolean audioBuffer16Bit = JNI_FALSE; static jobject audioBuffer = NULL; static void* audioBufferPinned = NULL; +static jboolean captureBuffer16Bit = JNI_FALSE; +static jobject captureBuffer = NULL; -int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) +int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames) { jboolean audioBufferStereo; int audioBufferFrames; + jobject jbufobj = NULL; + jboolean isCopy; JNIEnv *env = Android_JNI_GetEnv(); @@ -568,14 +587,24 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i } Android_JNI_SetupThread(); - __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); - audioBuffer16Bit = is16Bit; audioBufferStereo = channelCount > 1; - if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioInit, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) { - /* Error during audio initialization */ - __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!"); - return 0; + if (iscapture) { + __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture"); + captureBuffer16Bit = is16Bit; + if ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) { + /* Error during audio initialization */ + __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioRecord initialization!"); + return 0; + } + } else { + __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output"); + audioBuffer16Bit = is16Bit; + if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) { + /* Error during audio initialization */ + __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!"); + return 0; + } } /* Allocating the audio buffer from the Java side and passing it as the return value for audioInit no longer works on @@ -584,31 +613,43 @@ int Android_JNI_OpenAudioDevice(int sampleRate, int is16Bit, int channelCount, i if (is16Bit) { jshortArray audioBufferLocal = (*env)->NewShortArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1)); if (audioBufferLocal) { - audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal); + jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal); (*env)->DeleteLocalRef(env, audioBufferLocal); } } else { jbyteArray audioBufferLocal = (*env)->NewByteArray(env, desiredBufferFrames * (audioBufferStereo ? 2 : 1)); if (audioBufferLocal) { - audioBuffer = (*env)->NewGlobalRef(env, audioBufferLocal); + jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal); (*env)->DeleteLocalRef(env, audioBufferLocal); } } - if (audioBuffer == NULL) { + if (jbufobj == NULL) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: could not allocate an audio buffer!"); return 0; } - jboolean isCopy = JNI_FALSE; - if (audioBuffer16Bit) { - audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy); + if (iscapture) { + captureBuffer = jbufobj; + } else { + audioBuffer = jbufobj; + } + + isCopy = JNI_FALSE; + + if (is16Bit) { + if (!iscapture) { + audioBufferPinned = (*env)->GetShortArrayElements(env, (jshortArray)audioBuffer, &isCopy); + } audioBufferFrames = (*env)->GetArrayLength(env, (jshortArray)audioBuffer); } else { - audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy); + if (!iscapture) { + audioBufferPinned = (*env)->GetByteArrayElements(env, (jbyteArray)audioBuffer, &isCopy); + } audioBufferFrames = (*env)->GetArrayLength(env, (jbyteArray)audioBuffer); } + if (audioBufferStereo) { audioBufferFrames /= 2; } @@ -636,16 +677,71 @@ void Android_JNI_WriteAudioBuffer(void) /* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */ } -void Android_JNI_CloseAudioDevice(void) +int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen) +{ + JNIEnv *env = Android_JNI_GetEnv(); + jboolean isCopy = JNI_FALSE; + jint br; + + if (captureBuffer16Bit) { + SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen / 2)); + br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE); + if (br > 0) { + jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy); + br *= 2; + SDL_memcpy(buffer, ptr, br); + (*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, (jshort *)ptr, JNI_ABORT); + } + } else { + SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen); + br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE); + if (br > 0) { + jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy); + SDL_memcpy(buffer, ptr, br); + (*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, (jbyte *)ptr, JNI_ABORT); + } + } + + return (int) br; +} + +void Android_JNI_FlushCapturedAudio(void) +{ + JNIEnv *env = Android_JNI_GetEnv(); + #if 0 /* !!! FIXME: this needs API 23, or it'll do blocking reads and never end. */ + if (captureBuffer16Bit) { + const jint len = (*env)->GetArrayLength(env, (jshortArray)captureBuffer); + while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE) == len) { /* spin */ } + } else { + const jint len = (*env)->GetArrayLength(env, (jbyteArray)captureBuffer); + while ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE) == len) { /* spin */ } + } + #else + if (captureBuffer16Bit) { + (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE); + } else { + (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE); + } + #endif +} + +void Android_JNI_CloseAudioDevice(const int iscapture) { JNIEnv *env = Android_JNI_GetEnv(); - (*env)->CallStaticVoidMethod(env, mActivityClass, midAudioQuit); - - if (audioBuffer) { - (*env)->DeleteGlobalRef(env, audioBuffer); - audioBuffer = NULL; - audioBufferPinned = NULL; + if (iscapture) { + (*env)->CallStaticVoidMethod(env, mActivityClass, midCaptureClose); + if (captureBuffer) { + (*env)->DeleteGlobalRef(env, captureBuffer); + captureBuffer = NULL; + } + } else { + (*env)->CallStaticVoidMethod(env, mActivityClass, midAudioClose); + if (audioBuffer) { + (*env)->DeleteGlobalRef(env, audioBuffer); + audioBuffer = NULL; + audioBufferPinned = NULL; + } } } @@ -653,10 +749,12 @@ void Android_JNI_CloseAudioDevice(void) /* If the parameter silent is truthy then SDL_SetError() will not be called. */ static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent) { - SDL_assert(LocalReferenceHolder_IsActive()); JNIEnv *mEnv = Android_JNI_GetEnv(); + jthrowable exception; - jthrowable exception = (*mEnv)->ExceptionOccurred(mEnv); + SDL_assert(LocalReferenceHolder_IsActive()); + + exception = (*mEnv)->ExceptionOccurred(mEnv); if (exception != NULL) { jmethodID mid; @@ -666,13 +764,16 @@ static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent) if (!silent) { jclass exceptionClass = (*mEnv)->GetObjectClass(mEnv, exception); jclass classClass = (*mEnv)->FindClass(mEnv, "java/lang/Class"); + jstring exceptionName; + const char* exceptionNameUTF8; + jstring exceptionMessage; mid = (*mEnv)->GetMethodID(mEnv, classClass, "getName", "()Ljava/lang/String;"); - jstring exceptionName = (jstring)(*mEnv)->CallObjectMethod(mEnv, exceptionClass, mid); - const char* exceptionNameUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionName, 0); + exceptionName = (jstring)(*mEnv)->CallObjectMethod(mEnv, exceptionClass, mid); + exceptionNameUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionName, 0); mid = (*mEnv)->GetMethodID(mEnv, exceptionClass, "getMessage", "()Ljava/lang/String;"); - jstring exceptionMessage = (jstring)(*mEnv)->CallObjectMethod(mEnv, exception, mid); + exceptionMessage = (jstring)(*mEnv)->CallObjectMethod(mEnv, exception, mid); if (exceptionMessage != NULL) { const char* exceptionMessageUTF8 = (*mEnv)->GetStringUTFChars(mEnv, exceptionMessage, 0); @@ -855,6 +956,7 @@ int Android_JNI_FileOpen(SDL_RWops* ctx, struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); JNIEnv *mEnv = Android_JNI_GetEnv(); int retval; + jstring fileNameJString; if (!LocalReferenceHolder_Init(&refs, mEnv)) { LocalReferenceHolder_Cleanup(&refs); @@ -866,7 +968,7 @@ int Android_JNI_FileOpen(SDL_RWops* ctx, return -1; } - jstring fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName); + fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName); ctx->hidden.androidio.fileNameRef = (*mEnv)->NewGlobalRef(mEnv, fileNameJString); ctx->hidden.androidio.inputStreamRef = NULL; ctx->hidden.androidio.readableByteChannelRef = NULL; @@ -885,10 +987,11 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, if (ctx->hidden.androidio.assetFileDescriptorRef) { size_t bytesMax = size * maxnum; + size_t result; if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) { bytesMax = ctx->hidden.androidio.size - ctx->hidden.androidio.position; } - size_t result = read(ctx->hidden.androidio.fd, buffer, bytesMax ); + result = read(ctx->hidden.androidio.fd, buffer, bytesMax ); if (result > 0) { ctx->hidden.androidio.position += result; LocalReferenceHolder_Cleanup(&refs); @@ -900,19 +1003,23 @@ size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, jlong bytesRemaining = (jlong) (size * maxnum); jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position); int bytesRead = 0; + JNIEnv *mEnv; + jobject readableByteChannel; + jmethodID readMethod; + jobject byteBuffer; /* Don't read more bytes than those that remain in the file, otherwise we get an exception */ if (bytesRemaining > bytesMax) bytesRemaining = bytesMax; - JNIEnv *mEnv = Android_JNI_GetEnv(); + mEnv = Android_JNI_GetEnv(); if (!LocalReferenceHolder_Init(&refs, mEnv)) { LocalReferenceHolder_Cleanup(&refs); return 0; } - jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef; - jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; - jobject byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining); + readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef; + readMethod = (jmethodID)ctx->hidden.androidio.readMethod; + byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining); while (bytesRemaining > 0) { /* result = readableByteChannel.read(...); */ @@ -1002,6 +1109,7 @@ Sint64 Android_JNI_FileSize(SDL_RWops* ctx) Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) { if (ctx->hidden.androidio.assetFileDescriptorRef) { + off_t ret; switch (whence) { case RW_SEEK_SET: if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size; @@ -1020,11 +1128,12 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) } whence = SEEK_SET; - off_t ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET); + ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET); if (ret == -1) return -1; ctx->hidden.androidio.position = ret - ctx->hidden.androidio.offset; } else { Sint64 newPosition; + Sint64 movement; switch (whence) { case RW_SEEK_SET: @@ -1048,17 +1157,18 @@ Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence) newPosition = ctx->hidden.androidio.size; } - Sint64 movement = newPosition - ctx->hidden.androidio.position; + movement = newPosition - ctx->hidden.androidio.position; if (movement > 0) { unsigned char buffer[4096]; /* The easy case where we're seeking forwards */ while (movement > 0) { Sint64 amount = sizeof (buffer); + size_t result; if (amount > movement) { amount = movement; } - size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount); + result = Android_JNI_FileRead(ctx, buffer, 1, amount); if (result <= 0) { /* Failed to read/skip the required amount, so fail */ return -1; @@ -1091,21 +1201,23 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name) struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); JNIEnv* env = Android_JNI_GetEnv(); jobject retval = NULL; + jstring service; + jmethodID mid; + jobject context; + jobject manager; if (!LocalReferenceHolder_Init(&refs, env)) { LocalReferenceHolder_Cleanup(&refs); return NULL; } - jstring service = (*env)->NewStringUTF(env, name); - - jmethodID mid; + service = (*env)->NewStringUTF(env, name); mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;"); - jobject context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid); + context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid); mid = (*env)->GetMethodID(env, mActivityClass, "getSystemServiceFromUiThread", "(Ljava/lang/String;)Ljava/lang/Object;"); - jobject manager = (*env)->CallObjectMethod(env, context, mid, service); + manager = (*env)->CallObjectMethod(env, context, mid, service); (*env)->DeleteLocalRef(env, service); @@ -1117,11 +1229,12 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name) #define SETUP_CLIPBOARD(error) \ struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); \ JNIEnv* env = Android_JNI_GetEnv(); \ + jobject clipboard; \ if (!LocalReferenceHolder_Init(&refs, env)) { \ LocalReferenceHolder_Cleanup(&refs); \ return error; \ } \ - jobject clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \ + clipboard = Android_JNI_GetSystemServiceObject("clipboard"); \ if (!clipboard) { \ LocalReferenceHolder_Cleanup(&refs); \ return error; \ @@ -1132,14 +1245,17 @@ static jobject Android_JNI_GetSystemServiceObject(const char* name) int Android_JNI_SetClipboardText(const char* text) { + /* Watch out for C89 scoping rules because of the macro */ SETUP_CLIPBOARD(-1) - jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "setText", "(Ljava/lang/CharSequence;)V"); - jstring string = (*env)->NewStringUTF(env, text); - (*env)->CallVoidMethod(env, clipboard, mid, string); - (*env)->DeleteGlobalRef(env, clipboard); - (*env)->DeleteLocalRef(env, string); - + /* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */ + { + jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "setText", "(Ljava/lang/CharSequence;)V"); + jstring string = (*env)->NewStringUTF(env, text); + (*env)->CallVoidMethod(env, clipboard, mid, string); + (*env)->DeleteGlobalRef(env, clipboard); + (*env)->DeleteLocalRef(env, string); + } CLEANUP_CLIPBOARD(); return 0; @@ -1147,25 +1263,30 @@ int Android_JNI_SetClipboardText(const char* text) char* Android_JNI_GetClipboardText(void) { + /* Watch out for C89 scoping rules because of the macro */ SETUP_CLIPBOARD(SDL_strdup("")) - jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "getText", "()Ljava/lang/CharSequence;"); - jobject sequence = (*env)->CallObjectMethod(env, clipboard, mid); - (*env)->DeleteGlobalRef(env, clipboard); - if (sequence) { - mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, sequence), "toString", "()Ljava/lang/String;"); - jstring string = (jstring)((*env)->CallObjectMethod(env, sequence, mid)); - const char* utf = (*env)->GetStringUTFChars(env, string, 0); - if (utf) { - char* text = SDL_strdup(utf); - (*env)->ReleaseStringUTFChars(env, string, utf); + /* Nest the following in a scope to avoid C89 declaration rules triggered by the macro */ + { + jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "getText", "()Ljava/lang/CharSequence;"); + jobject sequence = (*env)->CallObjectMethod(env, clipboard, mid); + (*env)->DeleteGlobalRef(env, clipboard); + if (sequence) { + jstring string; + const char* utf; + mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, sequence), "toString", "()Ljava/lang/String;"); + string = (jstring)((*env)->CallObjectMethod(env, sequence, mid)); + utf = (*env)->GetStringUTFChars(env, string, 0); + if (utf) { + char* text = SDL_strdup(utf); + (*env)->ReleaseStringUTFChars(env, string, utf); - CLEANUP_CLIPBOARD(); + CLEANUP_CLIPBOARD(); - return text; + return text; + } } } - CLEANUP_CLIPBOARD(); return SDL_strdup(""); @@ -1173,10 +1294,13 @@ char* Android_JNI_GetClipboardText(void) SDL_bool Android_JNI_HasClipboardText(void) { + jmethodID mid; + jboolean has; + /* Watch out for C89 scoping rules because of the macro */ SETUP_CLIPBOARD(SDL_FALSE) - jmethodID mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "hasText", "()Z"); - jboolean has = (*env)->CallBooleanMethod(env, clipboard, mid); + mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, clipboard), "hasText", "()Z"); + has = (*env)->CallBooleanMethod(env, clipboard, mid); (*env)->DeleteGlobalRef(env, clipboard); CLEANUP_CLIPBOARD(); @@ -1193,49 +1317,61 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco { struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__); JNIEnv* env = Android_JNI_GetEnv(); + jmethodID mid; + jobject context; + jstring action; + jclass cls; + jobject filter; + jobject intent; + jstring iname; + jmethodID imid; + jstring bname; + jmethodID bmid; if (!LocalReferenceHolder_Init(&refs, env)) { LocalReferenceHolder_Cleanup(&refs); return -1; } - jmethodID mid; mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;"); - jobject context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid); + context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid); - jstring action = (*env)->NewStringUTF(env, "android.intent.action.BATTERY_CHANGED"); + action = (*env)->NewStringUTF(env, "android.intent.action.BATTERY_CHANGED"); - jclass cls = (*env)->FindClass(env, "android/content/IntentFilter"); + cls = (*env)->FindClass(env, "android/content/IntentFilter"); mid = (*env)->GetMethodID(env, cls, "", "(Ljava/lang/String;)V"); - jobject filter = (*env)->NewObject(env, cls, mid, action); + filter = (*env)->NewObject(env, cls, mid, action); (*env)->DeleteLocalRef(env, action); mid = (*env)->GetMethodID(env, mActivityClass, "registerReceiver", "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;"); - jobject intent = (*env)->CallObjectMethod(env, context, mid, NULL, filter); + intent = (*env)->CallObjectMethod(env, context, mid, NULL, filter); (*env)->DeleteLocalRef(env, filter); cls = (*env)->GetObjectClass(env, intent); - jstring iname; - jmethodID imid = (*env)->GetMethodID(env, cls, "getIntExtra", "(Ljava/lang/String;I)I"); + imid = (*env)->GetMethodID(env, cls, "getIntExtra", "(Ljava/lang/String;I)I"); + /* Watch out for C89 scoping rules because of the macro */ #define GET_INT_EXTRA(var, key) \ + int var; \ iname = (*env)->NewStringUTF(env, key); \ - int var = (*env)->CallIntMethod(env, intent, imid, iname, -1); \ + var = (*env)->CallIntMethod(env, intent, imid, iname, -1); \ (*env)->DeleteLocalRef(env, iname); - jstring bname; - jmethodID bmid = (*env)->GetMethodID(env, cls, "getBooleanExtra", "(Ljava/lang/String;Z)Z"); + bmid = (*env)->GetMethodID(env, cls, "getBooleanExtra", "(Ljava/lang/String;Z)Z"); + /* Watch out for C89 scoping rules because of the macro */ #define GET_BOOL_EXTRA(var, key) \ + int var; \ bname = (*env)->NewStringUTF(env, key); \ - int var = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \ + var = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \ (*env)->DeleteLocalRef(env, bname); if (plugged) { + /* Watch out for C89 scoping rules because of the macro */ GET_INT_EXTRA(plug, "plugged") /* == BatteryManager.EXTRA_PLUGGED (API 5) */ if (plug == -1) { LocalReferenceHolder_Cleanup(&refs); @@ -1247,6 +1383,7 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco } if (charged) { + /* Watch out for C89 scoping rules because of the macro */ GET_INT_EXTRA(status, "status") /* == BatteryManager.EXTRA_STATUS (API 5) */ if (status == -1) { LocalReferenceHolder_Cleanup(&refs); @@ -1266,8 +1403,20 @@ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seco } if (percent) { - GET_INT_EXTRA(level, "level") /* == BatteryManager.EXTRA_LEVEL (API 5) */ - GET_INT_EXTRA(scale, "scale") /* == BatteryManager.EXTRA_SCALE (API 5) */ + int level; + int scale; + + /* Watch out for C89 scoping rules because of the macro */ + { + GET_INT_EXTRA(level_temp, "level") /* == BatteryManager.EXTRA_LEVEL (API 5) */ + level = level_temp; + } + /* Watch out for C89 scoping rules because of the macro */ + { + GET_INT_EXTRA(scale_temp, "scale") /* == BatteryManager.EXTRA_SCALE (API 5) */ + scale = scale_temp; + } + if ((level == -1) || (scale == -1)) { LocalReferenceHolder_Cleanup(&refs); return -1; @@ -1320,14 +1469,16 @@ void Android_JNI_PollInputDevices(void) int Android_JNI_SendMessage(int command, int param) { JNIEnv *env = Android_JNI_GetEnv(); + jmethodID mid; + jboolean success; if (!env) { return -1; } - jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z"); + mid = (*env)->GetStaticMethodID(env, mActivityClass, "sendMessage", "(II)Z"); if (!mid) { return -1; } - jboolean success = (*env)->CallStaticBooleanMethod(env, mActivityClass, mid, command, param); + success = (*env)->CallStaticBooleanMethod(env, mActivityClass, mid, command, param); return success ? 0 : -1; } @@ -1339,11 +1490,12 @@ void Android_JNI_SuspendScreenSaver(SDL_bool suspend) void Android_JNI_ShowTextInput(SDL_Rect *inputRect) { JNIEnv *env = Android_JNI_GetEnv(); + jmethodID mid; if (!env) { return; } - jmethodID mid = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z"); + mid = (*env)->GetStaticMethodID(env, mActivityClass, "showTextInput", "(IIII)Z"); if (!mid) { return; } diff --git a/Engine/lib/sdl/src/core/android/SDL_android.h b/Engine/lib/sdl/src/core/android/SDL_android.h index 8e2ab93c3..cb7ff0736 100644 --- a/Engine/lib/sdl/src/core/android/SDL_android.h +++ b/Engine/lib/sdl/src/core/android/SDL_android.h @@ -40,10 +40,12 @@ 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 int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int channelCount, int desiredBufferFrames); extern void* Android_JNI_GetAudioBuffer(void); extern void Android_JNI_WriteAudioBuffer(void); -extern void Android_JNI_CloseAudioDevice(void); +extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen); +extern void Android_JNI_FlushCapturedAudio(void); +extern void Android_JNI_CloseAudioDevice(const int iscapture); #include "SDL_rwops.h" diff --git a/Engine/lib/sdl/src/core/linux/SDL_dbus.c b/Engine/lib/sdl/src/core/linux/SDL_dbus.c index 5d0df050c..ab73ca17c 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_dbus.c +++ b/Engine/lib/sdl/src/core/linux/SDL_dbus.c @@ -27,7 +27,7 @@ static const char *dbus_library = "libdbus-1.so.3"; static void *dbus_handle = NULL; static unsigned int screensaver_cookie = 0; -static SDL_DBusContext dbus = {0}; +static SDL_DBusContext dbus; static int LoadDBUSSyms(void) diff --git a/Engine/lib/sdl/src/core/linux/SDL_evdev.c b/Engine/lib/sdl/src/core/linux/SDL_evdev.c index a8f2b138e..4761f3e46 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_evdev.c +++ b/Engine/lib/sdl/src/core/linux/SDL_evdev.c @@ -29,10 +29,7 @@ * The evtest application is also useful to debug the protocol */ - #include "SDL_evdev.h" -#define _THIS SDL_EVDEV_PrivateData *_this -static _THIS = NULL; #include #include @@ -43,18 +40,8 @@ static _THIS = NULL; #ifdef SDL_INPUT_LINUXKD #include #include -#endif - - -/* We need this to prevent keystrokes from appear in the console */ -#ifndef KDSKBMUTE -#define KDSKBMUTE 0x4B51 -#endif -#ifndef KDSKBMODE -#define KDSKBMODE 0x4B45 -#endif -#ifndef K_OFF -#define K_OFF 0x04 +#include +#include /* for TIOCL_GETSHIFTSTATE */ #endif #include "SDL.h" @@ -63,273 +50,71 @@ static _THIS = NULL; #include "../../core/linux/SDL_udev.h" #include "SDL_scancode.h" #include "../../events/SDL_events_c.h" +#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */ /* This isn't defined in older Linux kernel headers */ #ifndef SYN_DROPPED #define SYN_DROPPED 3 #endif +typedef struct SDL_evdevlist_item +{ + char *path; + int fd; + + /* TODO: use this for every device, not just touchscreen */ + int out_of_sync; + + /* TODO: expand on this to have data for every possible class (mouse, + keyboard, touchpad, etc.). Also there's probably some things in here we + can pull out to the SDL_evdevlist_item i.e. name */ + int is_touchscreen; + struct { + char* name; + + int min_x, max_x, range_x; + int min_y, max_y, range_y; + + int max_slots; + int current_slot; + struct { + enum { + EVDEV_TOUCH_SLOTDELTA_NONE = 0, + EVDEV_TOUCH_SLOTDELTA_DOWN, + EVDEV_TOUCH_SLOTDELTA_UP, + EVDEV_TOUCH_SLOTDELTA_MOVE + } delta; + int tracking_id; + int x, y; + } * slots; + } * touchscreen_data; + + struct SDL_evdevlist_item *next; +} SDL_evdevlist_item; + +typedef struct SDL_EVDEV_PrivateData +{ + SDL_evdevlist_item *first; + SDL_evdevlist_item *last; + int num_devices; + int ref_count; + int console_fd; + int kb_mode; +} SDL_EVDEV_PrivateData; + +#define _THIS SDL_EVDEV_PrivateData *_this +static _THIS = NULL; + static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode); static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item); -static int SDL_EVDEV_device_removed(const char *devpath); +static int SDL_EVDEV_device_removed(const char *dev_path); #if SDL_USE_LIBUDEV -static int SDL_EVDEV_device_added(const char *devpath); -void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); +static int SDL_EVDEV_device_added(const char *dev_path, int udev_class); +void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, + const char *dev_path); #endif /* SDL_USE_LIBUDEV */ -static SDL_Scancode EVDEV_Keycodes[] = { - SDL_SCANCODE_UNKNOWN, /* KEY_RESERVED 0 */ - SDL_SCANCODE_ESCAPE, /* KEY_ESC 1 */ - SDL_SCANCODE_1, /* KEY_1 2 */ - SDL_SCANCODE_2, /* KEY_2 3 */ - SDL_SCANCODE_3, /* KEY_3 4 */ - SDL_SCANCODE_4, /* KEY_4 5 */ - SDL_SCANCODE_5, /* KEY_5 6 */ - SDL_SCANCODE_6, /* KEY_6 7 */ - SDL_SCANCODE_7, /* KEY_7 8 */ - SDL_SCANCODE_8, /* KEY_8 9 */ - SDL_SCANCODE_9, /* KEY_9 10 */ - SDL_SCANCODE_0, /* KEY_0 11 */ - SDL_SCANCODE_MINUS, /* KEY_MINUS 12 */ - SDL_SCANCODE_EQUALS, /* KEY_EQUAL 13 */ - SDL_SCANCODE_BACKSPACE, /* KEY_BACKSPACE 14 */ - SDL_SCANCODE_TAB, /* KEY_TAB 15 */ - SDL_SCANCODE_Q, /* KEY_Q 16 */ - SDL_SCANCODE_W, /* KEY_W 17 */ - SDL_SCANCODE_E, /* KEY_E 18 */ - SDL_SCANCODE_R, /* KEY_R 19 */ - SDL_SCANCODE_T, /* KEY_T 20 */ - SDL_SCANCODE_Y, /* KEY_Y 21 */ - SDL_SCANCODE_U, /* KEY_U 22 */ - SDL_SCANCODE_I, /* KEY_I 23 */ - SDL_SCANCODE_O, /* KEY_O 24 */ - SDL_SCANCODE_P, /* KEY_P 25 */ - SDL_SCANCODE_LEFTBRACKET, /* KEY_LEFTBRACE 26 */ - SDL_SCANCODE_RIGHTBRACKET, /* KEY_RIGHTBRACE 27 */ - SDL_SCANCODE_RETURN, /* KEY_ENTER 28 */ - SDL_SCANCODE_LCTRL, /* KEY_LEFTCTRL 29 */ - SDL_SCANCODE_A, /* KEY_A 30 */ - SDL_SCANCODE_S, /* KEY_S 31 */ - SDL_SCANCODE_D, /* KEY_D 32 */ - SDL_SCANCODE_F, /* KEY_F 33 */ - SDL_SCANCODE_G, /* KEY_G 34 */ - SDL_SCANCODE_H, /* KEY_H 35 */ - SDL_SCANCODE_J, /* KEY_J 36 */ - SDL_SCANCODE_K, /* KEY_K 37 */ - SDL_SCANCODE_L, /* KEY_L 38 */ - SDL_SCANCODE_SEMICOLON, /* KEY_SEMICOLON 39 */ - SDL_SCANCODE_APOSTROPHE, /* KEY_APOSTROPHE 40 */ - SDL_SCANCODE_GRAVE, /* KEY_GRAVE 41 */ - SDL_SCANCODE_LSHIFT, /* KEY_LEFTSHIFT 42 */ - SDL_SCANCODE_BACKSLASH, /* KEY_BACKSLASH 43 */ - SDL_SCANCODE_Z, /* KEY_Z 44 */ - SDL_SCANCODE_X, /* KEY_X 45 */ - SDL_SCANCODE_C, /* KEY_C 46 */ - SDL_SCANCODE_V, /* KEY_V 47 */ - SDL_SCANCODE_B, /* KEY_B 48 */ - SDL_SCANCODE_N, /* KEY_N 49 */ - SDL_SCANCODE_M, /* KEY_M 50 */ - SDL_SCANCODE_COMMA, /* KEY_COMMA 51 */ - SDL_SCANCODE_PERIOD, /* KEY_DOT 52 */ - SDL_SCANCODE_SLASH, /* KEY_SLASH 53 */ - SDL_SCANCODE_RSHIFT, /* KEY_RIGHTSHIFT 54 */ - SDL_SCANCODE_KP_MULTIPLY, /* KEY_KPASTERISK 55 */ - SDL_SCANCODE_LALT, /* KEY_LEFTALT 56 */ - SDL_SCANCODE_SPACE, /* KEY_SPACE 57 */ - SDL_SCANCODE_CAPSLOCK, /* KEY_CAPSLOCK 58 */ - SDL_SCANCODE_F1, /* KEY_F1 59 */ - SDL_SCANCODE_F2, /* KEY_F2 60 */ - SDL_SCANCODE_F3, /* KEY_F3 61 */ - SDL_SCANCODE_F4, /* KEY_F4 62 */ - SDL_SCANCODE_F5, /* KEY_F5 63 */ - SDL_SCANCODE_F6, /* KEY_F6 64 */ - SDL_SCANCODE_F7, /* KEY_F7 65 */ - SDL_SCANCODE_F8, /* KEY_F8 66 */ - SDL_SCANCODE_F9, /* KEY_F9 67 */ - SDL_SCANCODE_F10, /* KEY_F10 68 */ - SDL_SCANCODE_NUMLOCKCLEAR, /* KEY_NUMLOCK 69 */ - SDL_SCANCODE_SCROLLLOCK, /* KEY_SCROLLLOCK 70 */ - SDL_SCANCODE_KP_7, /* KEY_KP7 71 */ - SDL_SCANCODE_KP_8, /* KEY_KP8 72 */ - SDL_SCANCODE_KP_9, /* KEY_KP9 73 */ - SDL_SCANCODE_KP_MINUS, /* KEY_KPMINUS 74 */ - SDL_SCANCODE_KP_4, /* KEY_KP4 75 */ - SDL_SCANCODE_KP_5, /* KEY_KP5 76 */ - SDL_SCANCODE_KP_6, /* KEY_KP6 77 */ - SDL_SCANCODE_KP_PLUS, /* KEY_KPPLUS 78 */ - SDL_SCANCODE_KP_1, /* KEY_KP1 79 */ - SDL_SCANCODE_KP_2, /* KEY_KP2 80 */ - SDL_SCANCODE_KP_3, /* KEY_KP3 81 */ - SDL_SCANCODE_KP_0, /* KEY_KP0 82 */ - SDL_SCANCODE_KP_PERIOD, /* KEY_KPDOT 83 */ - SDL_SCANCODE_UNKNOWN, /* 84 */ - SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU 85 */ - SDL_SCANCODE_UNKNOWN, /* KEY_102ND 86 */ - SDL_SCANCODE_F11, /* KEY_F11 87 */ - SDL_SCANCODE_F12, /* KEY_F12 88 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RO 89 */ - SDL_SCANCODE_LANG3, /* KEY_KATAKANA 90 */ - SDL_SCANCODE_LANG4, /* KEY_HIRAGANA 91 */ - SDL_SCANCODE_UNKNOWN, /* KEY_HENKAN 92 */ - SDL_SCANCODE_LANG3, /* KEY_KATAKANAHIRAGANA 93 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MUHENKAN 94 */ - SDL_SCANCODE_KP_COMMA, /* KEY_KPJPCOMMA 95 */ - SDL_SCANCODE_KP_ENTER, /* KEY_KPENTER 96 */ - SDL_SCANCODE_RCTRL, /* KEY_RIGHTCTRL 97 */ - SDL_SCANCODE_KP_DIVIDE, /* KEY_KPSLASH 98 */ - SDL_SCANCODE_SYSREQ, /* KEY_SYSRQ 99 */ - SDL_SCANCODE_RALT, /* KEY_RIGHTALT 100 */ - SDL_SCANCODE_UNKNOWN, /* KEY_LINEFEED 101 */ - SDL_SCANCODE_HOME, /* KEY_HOME 102 */ - SDL_SCANCODE_UP, /* KEY_UP 103 */ - SDL_SCANCODE_PAGEUP, /* KEY_PAGEUP 104 */ - SDL_SCANCODE_LEFT, /* KEY_LEFT 105 */ - SDL_SCANCODE_RIGHT, /* KEY_RIGHT 106 */ - SDL_SCANCODE_END, /* KEY_END 107 */ - SDL_SCANCODE_DOWN, /* KEY_DOWN 108 */ - SDL_SCANCODE_PAGEDOWN, /* KEY_PAGEDOWN 109 */ - SDL_SCANCODE_INSERT, /* KEY_INSERT 110 */ - SDL_SCANCODE_DELETE, /* KEY_DELETE 111 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MACRO 112 */ - SDL_SCANCODE_MUTE, /* KEY_MUTE 113 */ - SDL_SCANCODE_VOLUMEDOWN, /* KEY_VOLUMEDOWN 114 */ - SDL_SCANCODE_VOLUMEUP, /* KEY_VOLUMEUP 115 */ - SDL_SCANCODE_POWER, /* KEY_POWER 116 SC System Power Down */ - SDL_SCANCODE_KP_EQUALS, /* KEY_KPEQUAL 117 */ - SDL_SCANCODE_KP_MINUS, /* KEY_KPPLUSMINUS 118 */ - SDL_SCANCODE_PAUSE, /* KEY_PAUSE 119 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCALE 120 AL Compiz Scale (Expose) */ - SDL_SCANCODE_KP_COMMA, /* KEY_KPCOMMA 121 */ - SDL_SCANCODE_LANG1, /* KEY_HANGEUL,KEY_HANGUEL 122 */ - SDL_SCANCODE_LANG2, /* KEY_HANJA 123 */ - SDL_SCANCODE_INTERNATIONAL3,/* KEY_YEN 124 */ - SDL_SCANCODE_LGUI, /* KEY_LEFTMETA 125 */ - SDL_SCANCODE_RGUI, /* KEY_RIGHTMETA 126 */ - SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE 127 */ - SDL_SCANCODE_STOP, /* KEY_STOP 128 AC Stop */ - SDL_SCANCODE_AGAIN, /* KEY_AGAIN 129 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROPS 130 AC Properties */ - SDL_SCANCODE_UNDO, /* KEY_UNDO 131 AC Undo */ - SDL_SCANCODE_UNKNOWN, /* KEY_FRONT 132 */ - SDL_SCANCODE_COPY, /* KEY_COPY 133 AC Copy */ - SDL_SCANCODE_UNKNOWN, /* KEY_OPEN 134 AC Open */ - SDL_SCANCODE_PASTE, /* KEY_PASTE 135 AC Paste */ - SDL_SCANCODE_FIND, /* KEY_FIND 136 AC Search */ - SDL_SCANCODE_CUT, /* KEY_CUT 137 AC Cut */ - SDL_SCANCODE_HELP, /* KEY_HELP 138 AL Integrated Help Center */ - SDL_SCANCODE_MENU, /* KEY_MENU 139 Menu (show menu) */ - SDL_SCANCODE_CALCULATOR, /* KEY_CALC 140 AL Calculator */ - SDL_SCANCODE_UNKNOWN, /* KEY_SETUP 141 */ - SDL_SCANCODE_SLEEP, /* KEY_SLEEP 142 SC System Sleep */ - SDL_SCANCODE_UNKNOWN, /* KEY_WAKEUP 143 System Wake Up */ - SDL_SCANCODE_UNKNOWN, /* KEY_FILE 144 AL Local Machine Browser */ - SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE 145 */ - SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE 146 */ - SDL_SCANCODE_UNKNOWN, /* KEY_XFER 147 */ - SDL_SCANCODE_APP1, /* KEY_PROG1 148 */ - SDL_SCANCODE_APP1, /* KEY_PROG2 149 */ - SDL_SCANCODE_WWW, /* KEY_WWW 150 AL Internet Browser */ - SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS 151 */ - SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE,KEY_SCREENLOCK 152 AL Terminal Lock/Screensaver */ - SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION 153 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CYCLEWINDOWS 154 */ - SDL_SCANCODE_MAIL, /* KEY_MAIL 155 */ - SDL_SCANCODE_AC_BOOKMARKS, /* KEY_BOOKMARKS 156 AC Bookmarks */ - SDL_SCANCODE_COMPUTER, /* KEY_COMPUTER 157 */ - SDL_SCANCODE_AC_BACK, /* KEY_BACK 158 AC Back */ - SDL_SCANCODE_AC_FORWARD, /* KEY_FORWARD 159 AC Forward */ - SDL_SCANCODE_UNKNOWN, /* KEY_CLOSECD 160 */ - SDL_SCANCODE_EJECT, /* KEY_EJECTCD 161 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EJECTCLOSECD 162 */ - SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG 163 */ - SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE 164 */ - SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG 165 */ - SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD 166 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RECORD 167 */ - SDL_SCANCODE_UNKNOWN, /* KEY_REWIND 168 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PHONE 169 Media Select Telephone */ - SDL_SCANCODE_UNKNOWN, /* KEY_ISO 170 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CONFIG 171 AL Consumer Control Configuration */ - SDL_SCANCODE_AC_HOME, /* KEY_HOMEPAGE 172 AC Home */ - SDL_SCANCODE_AC_REFRESH, /* KEY_REFRESH 173 AC Refresh */ - SDL_SCANCODE_UNKNOWN, /* KEY_EXIT 174 AC Exit */ - SDL_SCANCODE_UNKNOWN, /* KEY_MOVE 175 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EDIT 176 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLUP 177 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SCROLLDOWN 178 */ - SDL_SCANCODE_KP_LEFTPAREN, /* KEY_KPLEFTPAREN 179 */ - SDL_SCANCODE_KP_RIGHTPAREN, /* KEY_KPRIGHTPAREN 180 */ - SDL_SCANCODE_UNKNOWN, /* KEY_NEW 181 AC New */ - SDL_SCANCODE_AGAIN, /* KEY_REDO 182 AC Redo/Repeat */ - SDL_SCANCODE_F13, /* KEY_F13 183 */ - SDL_SCANCODE_F14, /* KEY_F14 184 */ - SDL_SCANCODE_F15, /* KEY_F15 185 */ - SDL_SCANCODE_F16, /* KEY_F16 186 */ - SDL_SCANCODE_F17, /* KEY_F17 187 */ - SDL_SCANCODE_F18, /* KEY_F18 188 */ - SDL_SCANCODE_F19, /* KEY_F19 189 */ - SDL_SCANCODE_F20, /* KEY_F20 190 */ - SDL_SCANCODE_F21, /* KEY_F21 191 */ - SDL_SCANCODE_F22, /* KEY_F22 192 */ - SDL_SCANCODE_F23, /* KEY_F23 193 */ - SDL_SCANCODE_F24, /* KEY_F24 194 */ - SDL_SCANCODE_UNKNOWN, /* 195 */ - SDL_SCANCODE_UNKNOWN, /* 196 */ - SDL_SCANCODE_UNKNOWN, /* 197 */ - SDL_SCANCODE_UNKNOWN, /* 198 */ - SDL_SCANCODE_UNKNOWN, /* 199 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD 200 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD 201 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 202 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PROG4 203 */ - SDL_SCANCODE_UNKNOWN, /* KEY_DASHBOARD 204 AL Dashboard */ - SDL_SCANCODE_UNKNOWN, /* KEY_SUSPEND 205 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CLOSE 206 AC Close */ - SDL_SCANCODE_UNKNOWN, /* KEY_PLAY 207 */ - SDL_SCANCODE_UNKNOWN, /* KEY_FASTFORWARD 208 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BASSBOOST 209 */ - SDL_SCANCODE_UNKNOWN, /* KEY_PRINT 210 AC Print */ - SDL_SCANCODE_UNKNOWN, /* KEY_HP 211 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CAMERA 212 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SOUND 213 */ - SDL_SCANCODE_UNKNOWN, /* KEY_QUESTION 214 */ - SDL_SCANCODE_UNKNOWN, /* KEY_EMAIL 215 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CHAT 216 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SEARCH 217 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CONNECT 218 */ - SDL_SCANCODE_UNKNOWN, /* KEY_FINANCE 219 AL Checkbook/Finance */ - SDL_SCANCODE_UNKNOWN, /* KEY_SPORT 220 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SHOP 221 */ - SDL_SCANCODE_UNKNOWN, /* KEY_ALTERASE 222 */ - SDL_SCANCODE_UNKNOWN, /* KEY_CANCEL 223 AC Cancel */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSDOWN 224 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESSUP 225 */ - SDL_SCANCODE_UNKNOWN, /* KEY_MEDIA 226 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SWITCHVIDEOMODE 227 Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMTOGGLE 228 */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMDOWN 229 */ - SDL_SCANCODE_UNKNOWN, /* KEY_KBDILLUMUP 230 */ - SDL_SCANCODE_UNKNOWN, /* KEY_SEND 231 AC Send */ - SDL_SCANCODE_UNKNOWN, /* KEY_REPLY 232 AC Reply */ - SDL_SCANCODE_UNKNOWN, /* KEY_FORWARDMAIL 233 AC Forward Msg */ - SDL_SCANCODE_UNKNOWN, /* KEY_SAVE 234 AC Save */ - SDL_SCANCODE_UNKNOWN, /* KEY_DOCUMENTS 235 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BATTERY 236 */ - SDL_SCANCODE_UNKNOWN, /* KEY_BLUETOOTH 237 */ - SDL_SCANCODE_UNKNOWN, /* KEY_WLAN 238 */ - SDL_SCANCODE_UNKNOWN, /* KEY_UWB 239 */ - SDL_SCANCODE_UNKNOWN, /* KEY_UNKNOWN 240 */ - SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_NEXT 241 drive next video source */ - SDL_SCANCODE_UNKNOWN, /* KEY_VIDEO_PREV 242 drive previous video source */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_CYCLE 243 brightness up, after max is min */ - SDL_SCANCODE_UNKNOWN, /* KEY_BRIGHTNESS_ZERO 244 brightness off, use ambient */ - SDL_SCANCODE_UNKNOWN, /* KEY_DISPLAY_OFF 245 display device to off state */ - SDL_SCANCODE_UNKNOWN, /* KEY_WIMAX 246 */ - SDL_SCANCODE_UNKNOWN, /* KEY_RFKILL 247 Key that controls all radios */ - SDL_SCANCODE_UNKNOWN, /* KEY_MICMUTE 248 Mute / unmute the microphone */ -}; - static Uint8 EVDEV_MouseButtons[] = { SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */ SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */ @@ -342,121 +127,98 @@ static Uint8 EVDEV_MouseButtons[] = { }; static const char* EVDEV_consoles[] = { - "/proc/self/fd/0", + /* "/proc/self/fd/0", "/dev/tty", - "/dev/tty0", + "/dev/tty0", */ /* the tty ioctl's prohibit these */ "/dev/tty1", "/dev/tty2", "/dev/tty3", "/dev/tty4", "/dev/tty5", "/dev/tty6", + "/dev/tty7", /* usually X is spawned in tty7 */ "/dev/vc/0", "/dev/console" }; -#define IS_CONSOLE(fd) isatty (fd) && ioctl(fd, KDGKBTYPE, &arg) == 0 && ((arg == KB_101) || (arg == KB_84)) - -static int SDL_EVDEV_get_console_fd(void) -{ - int fd, i; - char arg = 0; +static int SDL_EVDEV_is_console(int fd) { + int type; - /* Try a few consoles to see which one we have read access to */ - - 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; - close(fd); - } - } - - /* Try stdin, stdout, stderr */ - - for(fd = 0; fd < 3; fd++) { - if (IS_CONSOLE(fd)) return fd; - } - - /* We won't be able to send SDL_TEXTINPUT events */ - return -1; + return isatty(fd) && ioctl(fd, KDGKBTYPE, &type) == 0 && + (type == KB_101 || type == KB_84); } /* Prevent keystrokes from reaching the tty */ -static int SDL_EVDEV_mute_keyboard(int tty, int *kb_mode) +static int SDL_EVDEV_mute_keyboard(int tty_fd, int* old_kb_mode) { - char arg; - - *kb_mode = 0; /* FIXME: Is this a sane default in case KDGKBMODE fails? */ - if (!IS_CONSOLE(tty)) { + if (!SDL_EVDEV_is_console(tty_fd)) { return SDL_SetError("Tried to mute an invalid tty"); } - ioctl(tty, KDGKBMODE, kb_mode); /* It's not fatal if this fails */ - if (ioctl(tty, KDSKBMUTE, 1) && ioctl(tty, KDSKBMODE, K_OFF)) { - return SDL_SetError("EVDEV: Failed muting keyboard"); + + if (ioctl(tty_fd, KDGKBMODE, old_kb_mode) < 0) { + return SDL_SetError("Failed to get keyboard mode during muting"); } + /* FIXME: atm this absolutely ruins the vt, and KDSKBMUTE isn't implemented + in the kernel */ + /* + if (ioctl(tty_fd, KDSKBMODE, K_OFF) < 0) { + return SDL_SetError("Failed to set keyboard mode during muting"); + } + */ + return 0; } /* Restore the keyboard mode for given tty */ -static void SDL_EVDEV_unmute_keyboard(int tty, int kb_mode) +static void SDL_EVDEV_unmute_keyboard(int tty_fd, int kb_mode) { - if (ioctl(tty, KDSKBMUTE, 0) && ioctl(tty, KDSKBMODE, kb_mode)) { - SDL_Log("EVDEV: Failed restoring keyboard mode"); + /* read above */ + /* + if (ioctl(tty_fd, KDSKBMODE, kb_mode) < 0) { + SDL_Log("Failed to unmute keyboard"); } + */ } -/* Read /sys/class/tty/tty0/active and open the tty */ static int SDL_EVDEV_get_active_tty() -{ - int fd, len; - char ttyname[NAME_MAX + 1]; - char ttypath[PATH_MAX+1] = "/dev/"; - char arg; +{ + int i, fd, ret, tty = 0; + char tiocl; + struct vt_stat vt_state; + char path[PATH_MAX + 1]; - fd = open("/sys/class/tty/tty0/active", O_RDONLY); - if (fd < 0) { - return SDL_SetError("Could not determine which tty is active"); - } - - len = read(fd, ttyname, NAME_MAX); - close(fd); - - if (len <= 0) { - return SDL_SetError("Could not read which tty is active"); - } - - if (ttyname[len-1] == '\n') { - ttyname[len-1] = '\0'; - } - else { - ttyname[len] = '\0'; - } - - SDL_strlcat(ttypath, ttyname, PATH_MAX); - fd = open(ttypath, O_RDWR | O_NOCTTY); - if (fd < 0) { - return SDL_SetError("Could not open tty: %s", ttypath); - } - - if (!IS_CONSOLE(fd)) { + for(i = 0; i < SDL_arraysize(EVDEV_consoles); i++) { + fd = open(EVDEV_consoles[i], O_RDONLY); + + if (fd < 0 && !SDL_EVDEV_is_console(fd)) + break; + + tiocl = TIOCL_GETFGCONSOLE; + if ((ret = ioctl(fd, TIOCLINUX, &tiocl)) >= 0) + tty = ret + 1; + else if (ioctl(fd, VT_GETSTATE, &vt_state) == 0) + tty = vt_state.v_active; + close(fd); - return SDL_SetError("Invalid tty obtained: %s", ttypath); + + if (tty) { + sprintf(path, "/dev/tty%u", tty); + fd = open(path, O_RDONLY); + if (fd >= 0 && SDL_EVDEV_is_console(fd)) + return fd; + } } - - return fd; + + return SDL_SetError("Failed to determine active tty"); } int SDL_EVDEV_Init(void) { - int retval = 0; - if (_this == NULL) { - - _this = (SDL_EVDEV_PrivateData *) SDL_calloc(1, sizeof(*_this)); - if(_this == NULL) { + _this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this)); + if (_this == NULL) { return SDL_OutOfMemory(); } @@ -469,7 +231,9 @@ SDL_EVDEV_Init(void) /* Set up the udev callback */ if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) { - SDL_EVDEV_Quit(); + SDL_UDEV_Quit(); + SDL_free(_this); + _this = NULL; return -1; } @@ -479,26 +243,18 @@ SDL_EVDEV_Init(void) /* TODO: Scan the devices manually, like a caveman */ #endif /* SDL_USE_LIBUDEV */ - /* We need a physical terminal (not PTS) to be able to translate key code to symbols via the kernel tables */ - _this->console_fd = SDL_EVDEV_get_console_fd(); + /* We need a physical terminal (not PTS) to be able to translate key + code to symbols via the kernel tables */ + _this->console_fd = SDL_EVDEV_get_active_tty(); - /* Mute the keyboard so keystrokes only generate evdev events and do not leak through to the console */ - _this->tty = STDIN_FILENO; - if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) { - /* stdin is not a tty, probably we were launched remotely, so we try to disable the active tty */ - _this->tty = SDL_EVDEV_get_active_tty(); - if (_this->tty >= 0) { - if (SDL_EVDEV_mute_keyboard(_this->tty, &_this->kb_mode) < 0) { - close(_this->tty); - _this->tty = -1; - } - } - } + /* Mute the keyboard so keystrokes only generate evdev events and do not + leak through to the console */ + SDL_EVDEV_mute_keyboard(_this->console_fd, &_this->kb_mode); } _this->ref_count += 1; - return retval; + return 0; } void @@ -511,21 +267,16 @@ SDL_EVDEV_Quit(void) _this->ref_count -= 1; if (_this->ref_count < 1) { - #if SDL_USE_LIBUDEV SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback); SDL_UDEV_Quit(); #endif /* SDL_USE_LIBUDEV */ if (_this->console_fd >= 0) { + SDL_EVDEV_unmute_keyboard(_this->console_fd, _this->kb_mode); close(_this->console_fd); } - if (_this->tty >= 0) { - SDL_EVDEV_unmute_keyboard(_this->tty, _this->kb_mode); - close(_this->tty); - } - /* Remove existing devices */ while(_this->first != NULL) { SDL_EVDEV_device_removed(_this->first->path); @@ -533,7 +284,7 @@ SDL_EVDEV_Quit(void) SDL_assert(_this->first == NULL); SDL_assert(_this->last == NULL); - SDL_assert(_this->numdevices == 0); + SDL_assert(_this->num_devices == 0); SDL_free(_this); _this = NULL; @@ -541,47 +292,116 @@ SDL_EVDEV_Quit(void) } #if SDL_USE_LIBUDEV -void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) +void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class, + const char* dev_path) { - if (devpath == NULL) { + if (dev_path == NULL) { return; } - switch(udev_type) { + switch(udev_event) { case SDL_UDEV_DEVICEADDED: - if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE|SDL_UDEV_DEVICE_KEYBOARD))) { + if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD | + SDL_UDEV_DEVICE_TOUCHSCREEN))) return; - } - SDL_EVDEV_device_added(devpath); - break; - + + SDL_EVDEV_device_added(dev_path, udev_class); + break; case SDL_UDEV_DEVICEREMOVED: - SDL_EVDEV_device_removed(devpath); + SDL_EVDEV_device_removed(dev_path); break; - default: break; } } - #endif /* SDL_USE_LIBUDEV */ +#ifdef SDL_INPUT_LINUXKD +/* this logic is pulled from kbd_keycode() in drivers/tty/vt/keyboard.c in the + Linux kernel source */ +static void SDL_EVDEV_do_text_input(unsigned short keycode) { + char shift_state; + int locks_state; + struct kbentry kbe; + unsigned char type; + char text[2] = { 0 }; + + if (_this->console_fd < 0) + return; + + shift_state = TIOCL_GETSHIFTSTATE; + if (ioctl(_this->console_fd, TIOCLINUX, &shift_state) < 0) { + /* TODO: error */ + return; + } + + kbe.kb_table = shift_state; + kbe.kb_index = keycode; + + if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) { + /* TODO: error */ + return; + } + + type = KTYP(kbe.kb_value); + + if (type < 0xf0) { + /* + * FIXME: keysyms with a type below 0xf0 represent a unicode character + * which requires special handling due to dead characters, diacritics, + * etc. For perfect input a proper way to deal with such characters + * should be implemented. + * + * For reference, the only place I was able to find out about this + * special 0xf0 value was in an unused? couple of patches listed below. + * + * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-keyboard.diff + * http://ftp.tc.edu.tw/pub/docs/Unicode/utf8/linux-2.3.12-console.diff + */ + + return; + } + + type -= 0xf0; + + /* if type is KT_LETTER then it can be affected by Caps Lock */ + if (type == KT_LETTER) { + type = KT_LATIN; + + if (ioctl(_this->console_fd, KDGKBLED, &locks_state) < 0) { + /* TODO: error */ + return; + } + + if (locks_state & K_CAPSLOCK) { + kbe.kb_table = shift_state ^ (1 << KG_SHIFT); + + if (ioctl(_this->console_fd, KDGKBENT, &kbe) < 0) { + /* TODO: error */ + return; + } + } + } + + /* TODO: convert values >= 0x80 from ISO-8859-1? to UTF-8 */ + if (type != KT_LATIN || KVAL(kbe.kb_value) >= 0x80) + return; + + *text = KVAL(kbe.kb_value); + SDL_SendKeyboardText(text); +} +#endif /* SDL_INPUT_LINUXKD */ + void SDL_EVDEV_Poll(void) { struct input_event events[32]; - int i, len; + int i, j, len; SDL_evdevlist_item *item; SDL_Scancode scan_code; int mouse_button; SDL_Mouse *mouse; -#ifdef SDL_INPUT_LINUXKD - Uint16 modstate; - struct kbentry kbe; - static char keysym[8]; - char *end; - Uint32 kval; -#endif + float norm_x, norm_y; if (!_this) { return; @@ -597,6 +417,13 @@ SDL_EVDEV_Poll(void) while ((len = read(item->fd, events, (sizeof events))) > 0) { len /= sizeof(events[0]); for (i = 0; i < len; ++i) { + /* special handling for touchscreen, that should eventually be + used for all devices */ + if (item->out_of_sync && item->is_touchscreen && + events[i].type == EV_SYN && events[i].code != SYN_REPORT) { + break; + } + switch (events[i].type) { case EV_KEY: if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) { @@ -614,57 +441,55 @@ 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) { - kbe.kb_index = events[i].code; - /* Convert the key to an UTF-8 char */ - /* Ref: http://www.linuxjournal.com/article/2783 */ - modstate = SDL_GetModState(); - 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); - - 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))) - { - kval = KVAL(kbe.kb_value); - - /* While there's a KG_CAPSSHIFT symbol, it's not useful to build the table index with it - * 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)) { - kval = tolower(kval); - } else { - kval = toupper(kval); - } - } - - /* Convert to UTF-8 and send */ - end = SDL_UCS4ToUTF8(kval, keysym); - *end = '\0'; - SDL_SendKeyboardText(keysym); - } - } + SDL_EVDEV_do_text_input(events[i].code); #endif /* SDL_INPUT_LINUXKD */ } } break; case EV_ABS: switch(events[i].code) { + case ABS_MT_SLOT: + if (!item->is_touchscreen) /* FIXME: temp hack */ + break; + item->touchscreen_data->current_slot = events[i].value; + break; + case ABS_MT_TRACKING_ID: + if (!item->is_touchscreen) /* FIXME: temp hack */ + break; + if (events[i].value >= 0) { + item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value; + item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN; + } else { + item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP; + } + break; + case ABS_MT_POSITION_X: + if (!item->is_touchscreen) /* FIXME: temp hack */ + break; + item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value; + if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { + item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; + } + break; + case ABS_MT_POSITION_Y: + if (!item->is_touchscreen) /* FIXME: temp hack */ + break; + item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value; + if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) { + item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE; + } + break; case ABS_X: + if (item->is_touchscreen) /* FIXME: temp hack */ + break; SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y); break; case ABS_Y: + if (item->is_touchscreen) /* FIXME: temp hack */ + break; SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value); break; default: @@ -691,7 +516,41 @@ SDL_EVDEV_Poll(void) break; case EV_SYN: switch (events[i].code) { + case SYN_REPORT: + if (!item->is_touchscreen) /* FIXME: temp hack */ + break; + + for(j = 0; j < item->touchscreen_data->max_slots; j++) { + norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) / + (float)item->touchscreen_data->range_x; + norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) / + (float)item->touchscreen_data->range_y; + + switch(item->touchscreen_data->slots[j].delta) { + case EVDEV_TOUCH_SLOTDELTA_DOWN: + SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, 1.0f); + item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; + break; + case EVDEV_TOUCH_SLOTDELTA_UP: + SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, 1.0f); + item->touchscreen_data->slots[j].tracking_id = -1; + item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; + break; + case EVDEV_TOUCH_SLOTDELTA_MOVE: + SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, 1.0f); + item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE; + break; + default: + break; + } + } + + if (item->out_of_sync) + item->out_of_sync = 0; + break; case SYN_DROPPED: + if (item->is_touchscreen) + item->out_of_sync = 1; SDL_EVDEV_sync_device(item); break; default: @@ -709,30 +568,227 @@ SDL_EVDEV_translate_keycode(int keycode) { SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; - if (keycode < SDL_arraysize(EVDEV_Keycodes)) { - scancode = EVDEV_Keycodes[keycode]; - } + if (keycode < SDL_arraysize(linux_scancode_table)) + scancode = linux_scancode_table[keycode]; + if (scancode == SDL_SCANCODE_UNKNOWN) { - SDL_Log("The key you just pressed is not recognized by SDL. To help get this fixed, please report this to the SDL mailing list EVDEV KeyCode %d \n", keycode); + SDL_Log("The key you just pressed is not recognized by SDL. To help " + "get this fixed, please report this to the SDL mailing list " + " EVDEV KeyCode %d\n", keycode); } + return scancode; } +#ifdef SDL_USE_LIBUDEV +static int +SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item) +{ + int ret, i; + char name[64]; + struct input_absinfo abs_info; + + if (!item->is_touchscreen) + return 0; + + item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data)); + if (item->touchscreen_data == NULL) + return SDL_OutOfMemory(); + + ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name); + if (ret < 0) { + SDL_free(item->touchscreen_data); + return SDL_SetError("Failed to get evdev touchscreen name"); + } + + item->touchscreen_data->name = SDL_strdup(name); + if (item->touchscreen_data->name == NULL) { + SDL_free(item->touchscreen_data); + return SDL_OutOfMemory(); + } + + ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info); + if (ret < 0) { + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); + return SDL_SetError("Failed to get evdev touchscreen limits"); + } + item->touchscreen_data->min_x = abs_info.minimum; + item->touchscreen_data->max_x = abs_info.maximum; + item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum; + + ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info); + if (ret < 0) { + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); + return SDL_SetError("Failed to get evdev touchscreen limits"); + } + item->touchscreen_data->min_y = abs_info.minimum; + item->touchscreen_data->max_y = abs_info.maximum; + item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum; + + ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); + if (ret < 0) { + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); + return SDL_SetError("Failed to get evdev touchscreen limits"); + } + item->touchscreen_data->max_slots = abs_info.maximum + 1; + + item->touchscreen_data->slots = SDL_calloc( + item->touchscreen_data->max_slots, + sizeof(*item->touchscreen_data->slots)); + if (item->touchscreen_data->slots == NULL) { + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); + return SDL_OutOfMemory(); + } + + for(i = 0; i < item->touchscreen_data->max_slots; i++) { + item->touchscreen_data->slots[i].tracking_id = -1; + } + + ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */ + item->touchscreen_data->name); + if (ret < 0) { + SDL_free(item->touchscreen_data->slots); + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); + return ret; + } + + return 0; +} +#endif /* SDL_USE_LIBUDEV */ + +static void +SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) { + if (!item->is_touchscreen) + return; + + SDL_DelTouch(item->fd); + SDL_free(item->touchscreen_data->slots); + SDL_free(item->touchscreen_data->name); + SDL_free(item->touchscreen_data); +} + static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item) { - /* TODO: get full state of device and report whatever is required */ +#ifdef EVIOCGMTSLOTS + int i, ret; + struct input_absinfo abs_info; + /* + * struct input_mt_request_layout { + * __u32 code; + * __s32 values[num_slots]; + * }; + * + * this is the structure we're trying to emulate + */ + __u32* mt_req_code; + __s32* mt_req_values; + size_t mt_req_size; + + /* TODO: sync devices other than touchscreen */ + if (!item->is_touchscreen) + return; + + mt_req_size = sizeof(*mt_req_code) + + sizeof(*mt_req_values) * item->touchscreen_data->max_slots; + + mt_req_code = SDL_calloc(1, mt_req_size); + if (mt_req_code == NULL) { + return; + } + + mt_req_values = (__s32*)mt_req_code + 1; + + *mt_req_code = ABS_MT_TRACKING_ID; + ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); + if (ret < 0) { + SDL_free(mt_req_code); + return; + } + for(i = 0; i < item->touchscreen_data->max_slots; i++) { + /* + * This doesn't account for the very edge case of the user removing their + * finger and replacing it on the screen during the time we're out of sync, + * which'll mean that we're not going from down -> up or up -> down, we're + * going from down -> down but with a different tracking id, meaning we'd + * have to tell SDL of the two events, but since we wait till SYN_REPORT in + * SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't + * allow it. Lets just pray to God it doesn't happen. + */ + if (item->touchscreen_data->slots[i].tracking_id < 0 && + mt_req_values[i] >= 0) { + item->touchscreen_data->slots[i].tracking_id = mt_req_values[i]; + item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN; + } else if (item->touchscreen_data->slots[i].tracking_id >= 0 && + mt_req_values[i] < 0) { + item->touchscreen_data->slots[i].tracking_id = -1; + item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP; + } + } + + *mt_req_code = ABS_MT_POSITION_X; + ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); + if (ret < 0) { + SDL_free(mt_req_code); + return; + } + for(i = 0; i < item->touchscreen_data->max_slots; i++) { + if (item->touchscreen_data->slots[i].tracking_id >= 0 && + item->touchscreen_data->slots[i].x != mt_req_values[i]) { + item->touchscreen_data->slots[i].x = mt_req_values[i]; + if (item->touchscreen_data->slots[i].delta == + EVDEV_TOUCH_SLOTDELTA_NONE) { + item->touchscreen_data->slots[i].delta = + EVDEV_TOUCH_SLOTDELTA_MOVE; + } + } + } + + *mt_req_code = ABS_MT_POSITION_Y; + ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code); + if (ret < 0) { + SDL_free(mt_req_code); + return; + } + for(i = 0; i < item->touchscreen_data->max_slots; i++) { + if (item->touchscreen_data->slots[i].tracking_id >= 0 && + item->touchscreen_data->slots[i].y != mt_req_values[i]) { + item->touchscreen_data->slots[i].y = mt_req_values[i]; + if (item->touchscreen_data->slots[i].delta == + EVDEV_TOUCH_SLOTDELTA_NONE) { + item->touchscreen_data->slots[i].delta = + EVDEV_TOUCH_SLOTDELTA_MOVE; + } + } + } + + ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info); + if (ret < 0) { + SDL_free(mt_req_code); + return; + } + item->touchscreen_data->current_slot = abs_info.value; + + SDL_free(mt_req_code); + +#endif /* EVIOCGMTSLOTS */ } #if SDL_USE_LIBUDEV static int -SDL_EVDEV_device_added(const char *devpath) +SDL_EVDEV_device_added(const char *dev_path, int udev_class) { + int ret; SDL_evdevlist_item *item; /* Check to make sure it's not already in list. */ for (item = _this->first; item != NULL; item = item->next) { - if (SDL_strcmp(devpath, item->path) == 0) { + if (SDL_strcmp(dev_path, item->path) == 0) { return -1; /* already have this one */ } } @@ -742,21 +798,28 @@ SDL_EVDEV_device_added(const char *devpath) return SDL_OutOfMemory(); } - item->fd = open(devpath, O_RDONLY, 0); + item->fd = open(dev_path, O_RDONLY | O_NONBLOCK); if (item->fd < 0) { SDL_free(item); - return SDL_SetError("Unable to open %s", devpath); + return SDL_SetError("Unable to open %s", dev_path); } - item->path = SDL_strdup(devpath); + item->path = SDL_strdup(dev_path); if (item->path == NULL) { close(item->fd); SDL_free(item); return SDL_OutOfMemory(); } - /* Non blocking read mode */ - fcntl(item->fd, F_SETFL, O_NONBLOCK); + if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) { + item->is_touchscreen = 1; + + if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) { + close(item->fd); + SDL_free(item); + return ret; + } + } if (_this->last == NULL) { _this->first = _this->last = item; @@ -767,19 +830,19 @@ SDL_EVDEV_device_added(const char *devpath) SDL_EVDEV_sync_device(item); - return _this->numdevices++; + return _this->num_devices++; } #endif /* SDL_USE_LIBUDEV */ static int -SDL_EVDEV_device_removed(const char *devpath) +SDL_EVDEV_device_removed(const char *dev_path) { SDL_evdevlist_item *item; SDL_evdevlist_item *prev = NULL; for (item = _this->first; item != NULL; item = item->next) { /* found it, remove it. */ - if (SDL_strcmp(devpath, item->path) == 0) { + if (SDL_strcmp(dev_path, item->path) == 0) { if (prev != NULL) { prev->next = item->next; } else { @@ -789,10 +852,13 @@ SDL_EVDEV_device_removed(const char *devpath) if (item == _this->last) { _this->last = prev; } + if (item->is_touchscreen) { + SDL_EVDEV_destroy_touchscreen(item); + } close(item->fd); SDL_free(item->path); SDL_free(item); - _this->numdevices--; + _this->num_devices--; return 0; } prev = item; @@ -805,4 +871,3 @@ SDL_EVDEV_device_removed(const char *devpath) #endif /* SDL_INPUT_LINUXEV */ /* vi: set ts=4 sw=4 expandtab: */ - diff --git a/Engine/lib/sdl/src/core/linux/SDL_evdev.h b/Engine/lib/sdl/src/core/linux/SDL_evdev.h index 989ced858..85b193864 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_evdev.h +++ b/Engine/lib/sdl/src/core/linux/SDL_evdev.h @@ -27,31 +27,11 @@ #ifdef SDL_INPUT_LINUXEV #include "SDL_events.h" -#include - -typedef struct SDL_evdevlist_item -{ - char *path; - int fd; - struct SDL_evdevlist_item *next; -} SDL_evdevlist_item; - -typedef struct SDL_EVDEV_PrivateData -{ - SDL_evdevlist_item *first; - SDL_evdevlist_item *last; - int numdevices; - int ref_count; - int console_fd; - int kb_mode; - int tty; -} SDL_EVDEV_PrivateData; extern int SDL_EVDEV_Init(void); extern void SDL_EVDEV_Quit(void); extern void SDL_EVDEV_Poll(void); - #endif /* SDL_INPUT_LINUXEV */ #endif /* _SDL_evdev_h */ diff --git a/Engine/lib/sdl/src/core/linux/SDL_fcitx.c b/Engine/lib/sdl/src/core/linux/SDL_fcitx.c new file mode 100644 index 000000000..83d19e690 --- /dev/null +++ b/Engine/lib/sdl/src/core/linux/SDL_fcitx.c @@ -0,0 +1,553 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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 HAVE_FCITX_FRONTEND_H + +#include +#include + +#include "SDL_fcitx.h" +#include "SDL_keycode.h" +#include "SDL_keyboard.h" +#include "../../events/SDL_keyboard_c.h" +#include "SDL_dbus.h" +#include "SDL_syswm.h" +#if SDL_VIDEO_DRIVER_X11 +# include "../../video/x11/SDL_x11video.h" +#endif +#include "SDL_hints.h" + +#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx" + +#define FCITX_IM_DBUS_PATH "/inputmethod" +#define FCITX_IC_DBUS_PATH "/inputcontext_%d" + +#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod" +#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext" + +#define IC_NAME_MAX 64 +#define DBUS_TIMEOUT 500 + +typedef struct _FcitxClient +{ + SDL_DBusContext *dbus; + + char servicename[IC_NAME_MAX]; + char icname[IC_NAME_MAX]; + + int id; + + SDL_Rect cursor_rect; +} FcitxClient; + +static FcitxClient fcitx_client; + +static int +GetDisplayNumber() +{ + const char *display = SDL_getenv("DISPLAY"); + const char *p = NULL; + int number = 0; + + if (display == NULL) + return 0; + + display = SDL_strchr(display, ':'); + if (display == NULL) + return 0; + + display++; + p = SDL_strchr(display, '.'); + if (p == NULL && display != NULL) { + number = SDL_strtod(display, NULL); + } else { + char *buffer = SDL_strdup(display); + buffer[p - display] = '\0'; + number = SDL_strtod(buffer, NULL); + SDL_free(buffer); + } + + return number; +} + +static char* +GetAppName() +{ +#if defined(__LINUX__) || defined(__FREEBSD__) + char *spot; + char procfile[1024]; + char linkfile[1024]; + int linksize; + +#if defined(__LINUX__) + SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid()); +#elif defined(__FREEBSD__) + SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid()); +#endif + linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); + if (linksize > 0) { + linkfile[linksize] = '\0'; + spot = SDL_strrchr(linkfile, '/'); + if (spot) { + return SDL_strdup(spot + 1); + } else { + return SDL_strdup(linkfile); + } + } +#endif /* __LINUX__ || __FREEBSD__ */ + + return SDL_strdup("SDL_App"); +} + +/* + * Copied from fcitx source + */ +#define CONT(i) ISUTF8_CB(in[i]) +#define VAL(i, s) ((in[i]&0x3f) << s) + +static char * +_fcitx_utf8_get_char(const char *i, uint32_t *chr) +{ + const unsigned char* in = (const unsigned char *)i; + if (!(in[0] & 0x80)) { + *(chr) = *(in); + return (char *)in + 1; + } + + /* 2-byte, 0x80-0x7ff */ + if ((in[0] & 0xe0) == 0xc0 && CONT(1)) { + *chr = ((in[0] & 0x1f) << 6) | VAL(1, 0); + return (char *)in + 2; + } + + /* 3-byte, 0x800-0xffff */ + if ((in[0] & 0xf0) == 0xe0 && CONT(1) && CONT(2)) { + *chr = ((in[0] & 0xf) << 12) | VAL(1, 6) | VAL(2, 0); + return (char *)in + 3; + } + + /* 4-byte, 0x10000-0x1FFFFF */ + if ((in[0] & 0xf8) == 0xf0 && CONT(1) && CONT(2) && CONT(3)) { + *chr = ((in[0] & 0x7) << 18) | VAL(1, 12) | VAL(2, 6) | VAL(3, 0); + return (char *)in + 4; + } + + /* 5-byte, 0x200000-0x3FFFFFF */ + if ((in[0] & 0xfc) == 0xf8 && CONT(1) && CONT(2) && CONT(3) && CONT(4)) { + *chr = ((in[0] & 0x3) << 24) | VAL(1, 18) | VAL(2, 12) | VAL(3, 6) | VAL(4, 0); + return (char *)in + 5; + } + + /* 6-byte, 0x400000-0x7FFFFFF */ + if ((in[0] & 0xfe) == 0xfc && CONT(1) && CONT(2) && CONT(3) && CONT(4) && CONT(5)) { + *chr = ((in[0] & 0x1) << 30) | VAL(1, 24) | VAL(2, 18) | VAL(3, 12) | VAL(4, 6) | VAL(5, 0); + return (char *)in + 6; + } + + *chr = *in; + + return (char *)in + 1; +} + +static size_t +_fcitx_utf8_strlen(const char *s) +{ + unsigned int l = 0; + + while (*s) { + uint32_t chr; + + s = _fcitx_utf8_get_char(s, &chr); + l++; + } + + return l; +} + +static DBusHandlerResult +DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data) +{ + SDL_DBusContext *dbus = (SDL_DBusContext *)data; + + if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) { + DBusMessageIter iter; + const char *text = NULL; + + dbus->message_iter_init(msg, &iter); + dbus->message_iter_get_basic(&iter, &text); + + if (text) + SDL_SendKeyboardText(text); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) { + DBusMessageIter iter; + const char *text; + + dbus->message_iter_init(msg, &iter); + dbus->message_iter_get_basic(&iter, &text); + + if (text && *text) { + char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + size_t text_bytes = SDL_strlen(text), i = 0; + size_t cursor = 0; + + while (i < text_bytes) { + size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf)); + size_t chars = _fcitx_utf8_strlen(buf); + + SDL_SendEditingText(buf, cursor, chars); + + i += sz; + cursor += chars; + } + } + + SDL_Fcitx_UpdateTextRect(NULL); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusMessage* +FcitxClientICNewMethod(FcitxClient *client, + const char *method) +{ + SDL_DBusContext *dbus = client->dbus; + return dbus->message_new_method_call( + client->servicename, + client->icname, + FCITX_IC_DBUS_INTERFACE, + method); +} + +static void +FcitxClientICCallMethod(FcitxClient *client, + const char *method) +{ + SDL_DBusContext *dbus = client->dbus; + DBusMessage *msg = FcitxClientICNewMethod(client, method); + + if (msg == NULL) + return ; + + if (dbus->connection_send(dbus->session_conn, msg, NULL)) { + dbus->connection_flush(dbus->session_conn); + } + + dbus->message_unref(msg); +} + +static void +Fcitx_SetCapabilities(void *data, + const char *name, + const char *old_val, + const char *internal_editing) +{ + FcitxClient *client = (FcitxClient *)data; + SDL_DBusContext *dbus = client->dbus; + Uint32 caps = CAPACITY_NONE; + + DBusMessage *msg = FcitxClientICNewMethod(client, "SetCapacity"); + if (msg == NULL) + return ; + + if (!(internal_editing && *internal_editing == '1')) { + caps |= CAPACITY_PREEDIT; + } + + dbus->message_append_args(msg, + DBUS_TYPE_UINT32, &caps, + DBUS_TYPE_INVALID); + if (dbus->connection_send(dbus->session_conn, msg, NULL)) { + dbus->connection_flush(dbus->session_conn); + } + + dbus->message_unref(msg); +} + +static void +FcitxClientCreateIC(FcitxClient *client) +{ + char *appname = NULL; + pid_t pid = 0; + int id = 0; + SDL_bool enable; + Uint32 arg1, arg2, arg3, arg4; + + SDL_DBusContext *dbus = client->dbus; + DBusMessage *reply = NULL; + DBusMessage *msg = dbus->message_new_method_call( + client->servicename, + FCITX_IM_DBUS_PATH, + FCITX_IM_DBUS_INTERFACE, + "CreateICv3" + ); + + if (msg == NULL) + return ; + + appname = GetAppName(); + pid = getpid(); + dbus->message_append_args(msg, + DBUS_TYPE_STRING, &appname, + DBUS_TYPE_INT32, &pid, + DBUS_TYPE_INVALID); + + do { + reply = dbus->connection_send_with_reply_and_block( + dbus->session_conn, + msg, + DBUS_TIMEOUT, + NULL); + + if (!reply) + break; + if (!dbus->message_get_args(reply, NULL, + DBUS_TYPE_INT32, &id, + DBUS_TYPE_BOOLEAN, &enable, + DBUS_TYPE_UINT32, &arg1, + DBUS_TYPE_UINT32, &arg2, + DBUS_TYPE_UINT32, &arg3, + DBUS_TYPE_UINT32, &arg4, + DBUS_TYPE_INVALID)) + break; + + if (id < 0) + break; + client->id = id; + + SDL_snprintf(client->icname, IC_NAME_MAX, + FCITX_IC_DBUS_PATH, client->id); + + dbus->bus_add_match(dbus->session_conn, + "type='signal', interface='org.fcitx.Fcitx.InputContext'", + NULL); + dbus->connection_add_filter(dbus->session_conn, + &DBus_MessageFilter, dbus, + NULL); + dbus->connection_flush(dbus->session_conn); + + SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, &Fcitx_SetCapabilities, client); + } + while (0); + + if (reply) + dbus->message_unref(reply); + dbus->message_unref(msg); + SDL_free(appname); +} + +static Uint32 +Fcitx_ModState(void) +{ + Uint32 fcitx_mods = 0; + SDL_Keymod sdl_mods = SDL_GetModState(); + + if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift; + if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock; + if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl; + if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt; + if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock; + if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super; + if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta; + + return fcitx_mods; +} + +SDL_bool +SDL_Fcitx_Init() +{ + fcitx_client.dbus = SDL_DBus_GetContext(); + + fcitx_client.cursor_rect.x = -1; + fcitx_client.cursor_rect.y = -1; + fcitx_client.cursor_rect.w = 0; + fcitx_client.cursor_rect.h = 0; + + SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX, + "%s-%d", + FCITX_DBUS_SERVICE, GetDisplayNumber()); + + FcitxClientCreateIC(&fcitx_client); + + return SDL_TRUE; +} + +void +SDL_Fcitx_Quit() +{ + FcitxClientICCallMethod(&fcitx_client, "DestroyIC"); +} + +void +SDL_Fcitx_SetFocus(SDL_bool focused) +{ + if (focused) { + FcitxClientICCallMethod(&fcitx_client, "FocusIn"); + } else { + FcitxClientICCallMethod(&fcitx_client, "FocusOut"); + } +} + +void +SDL_Fcitx_Reset(void) +{ + FcitxClientICCallMethod(&fcitx_client, "Reset"); + FcitxClientICCallMethod(&fcitx_client, "CloseIC"); +} + +SDL_bool +SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +{ + DBusMessage *msg = NULL; + DBusMessage *reply = NULL; + SDL_DBusContext *dbus = fcitx_client.dbus; + + Uint32 state = 0; + SDL_bool handled = SDL_FALSE; + int type = FCITX_PRESS_KEY; + Uint32 event_time = 0; + + msg = FcitxClientICNewMethod(&fcitx_client, "ProcessKeyEvent"); + if (msg == NULL) + return SDL_FALSE; + + state = Fcitx_ModState(); + dbus->message_append_args(msg, + DBUS_TYPE_UINT32, &keysym, + DBUS_TYPE_UINT32, &keycode, + DBUS_TYPE_UINT32, &state, + DBUS_TYPE_INT32, &type, + DBUS_TYPE_UINT32, &event_time, + DBUS_TYPE_INVALID); + + reply = dbus->connection_send_with_reply_and_block(dbus->session_conn, + msg, + -1, + NULL); + + if (reply) { + dbus->message_get_args(reply, + NULL, + DBUS_TYPE_INT32, &handled, + DBUS_TYPE_INVALID); + + dbus->message_unref(reply); + } + + if (handled) { + SDL_Fcitx_UpdateTextRect(NULL); + } + + return handled; +} + +void +SDL_Fcitx_UpdateTextRect(SDL_Rect *rect) +{ + SDL_Window *focused_win = NULL; + SDL_SysWMinfo info; + int x = 0, y = 0; + SDL_Rect *cursor = &fcitx_client.cursor_rect; + + SDL_DBusContext *dbus = fcitx_client.dbus; + DBusMessage *msg = NULL; + DBusConnection *conn; + + if (rect) { + SDL_memcpy(cursor, rect, sizeof(SDL_Rect)); + } + + focused_win = SDL_GetKeyboardFocus(); + if (!focused_win) { + return ; + } + + SDL_VERSION(&info.version); + if (!SDL_GetWindowWMInfo(focused_win, &info)) { + return; + } + + SDL_GetWindowPosition(focused_win, &x, &y); + +#if SDL_VIDEO_DRIVER_X11 + if (info.subsystem == SDL_SYSWM_X11) { + SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata; + + Display *x_disp = info.info.x11.display; + Window x_win = info.info.x11.window; + int x_screen = displaydata->screen; + Window unused; + X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused); + } +#endif + + if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) { + // move to bottom left + int w = 0, h = 0; + SDL_GetWindowSize(focused_win, &w, &h); + cursor->x = 0; + cursor->y = h; + } + + x += cursor->x; + y += cursor->y; + + msg = FcitxClientICNewMethod(&fcitx_client, "SetCursorRect"); + if (msg == NULL) + return ; + + dbus->message_append_args(msg, + DBUS_TYPE_INT32, &x, + DBUS_TYPE_INT32, &y, + DBUS_TYPE_INT32, &cursor->w, + DBUS_TYPE_INT32, &cursor->h, + DBUS_TYPE_INVALID); + + conn = dbus->session_conn; + if (dbus->connection_send(conn, msg, NULL)) + dbus->connection_flush(conn); + + dbus->message_unref(msg); +} + +void +SDL_Fcitx_PumpEvents() +{ + SDL_DBusContext *dbus = fcitx_client.dbus; + DBusConnection *conn = dbus->session_conn; + + dbus->connection_read_write(conn, 0); + + while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) { + /* Do nothing, actual work happens in DBus_MessageFilter */ + usleep(10); + } +} + +#endif /* HAVE_FCITX_FRONTEND_H */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/core/linux/SDL_fcitx.h b/Engine/lib/sdl/src/core/linux/SDL_fcitx.h new file mode 100644 index 000000000..64020475c --- /dev/null +++ b/Engine/lib/sdl/src/core/linux/SDL_fcitx.h @@ -0,0 +1,40 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_fcitx_h +#define _SDL_fcitx_h + +#include "../../SDL_internal.h" + +#include "SDL_stdinc.h" +#include "SDL_rect.h" + +extern SDL_bool SDL_Fcitx_Init(void); +extern void SDL_Fcitx_Quit(void); +extern void SDL_Fcitx_SetFocus(SDL_bool focused); +extern void SDL_Fcitx_Reset(void); +extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect); +extern void SDL_Fcitx_PumpEvents(); + +#endif /* _SDL_fcitx_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/core/linux/SDL_ibus.c b/Engine/lib/sdl/src/core/linux/SDL_ibus.c index c9804c90a..3d63b8b30 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_ibus.c +++ b/Engine/lib/sdl/src/core/linux/SDL_ibus.c @@ -42,7 +42,7 @@ static const char IBUS_INTERFACE[] = "org.freedesktop.IBus"; static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext"; static char *input_ctx_path = NULL; -static SDL_Rect ibus_cursor_rect = {0}; +static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 }; static DBusConnection *ibus_conn = NULL; static char *ibus_addr_file = NULL; int inotify_fd = -1, inotify_wd = -1; @@ -341,7 +341,9 @@ IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr) const char *path = NULL; SDL_bool result = SDL_FALSE; DBusMessage *msg; - DBusObjectPathVTable ibus_vtable = {0}; + DBusObjectPathVTable ibus_vtable; + + SDL_zero(ibus_vtable); ibus_vtable.message_function = &IBus_MessageHandler; ibus_conn = dbus->connection_open_private(addr, NULL); diff --git a/Engine/lib/sdl/src/core/linux/SDL_ime.c b/Engine/lib/sdl/src/core/linux/SDL_ime.c new file mode 100644 index 000000000..049bd6e02 --- /dev/null +++ b/Engine/lib/sdl/src/core/linux/SDL_ime.c @@ -0,0 +1,138 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_ime.h" +#include "SDL_ibus.h" +#include "SDL_fcitx.h" + +typedef SDL_bool (*_SDL_IME_Init)(); +typedef void (*_SDL_IME_Quit)(); +typedef void (*_SDL_IME_SetFocus)(SDL_bool); +typedef void (*_SDL_IME_Reset)(); +typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32); +typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *); +typedef void (*_SDL_IME_PumpEvents)(); + +static _SDL_IME_Init SDL_IME_Init_Real = NULL; +static _SDL_IME_Quit SDL_IME_Quit_Real = NULL; +static _SDL_IME_SetFocus SDL_IME_SetFocus_Real = NULL; +static _SDL_IME_Reset SDL_IME_Reset_Real = NULL; +static _SDL_IME_ProcessKeyEvent SDL_IME_ProcessKeyEvent_Real = NULL; +static _SDL_IME_UpdateTextRect SDL_IME_UpdateTextRect_Real = NULL; +static _SDL_IME_PumpEvents SDL_IME_PumpEvents_Real = NULL; + +static void +InitIME() +{ + static SDL_bool inited = SDL_FALSE; +#ifdef HAVE_FCITX_FRONTEND_H + const char *im_module = SDL_getenv("SDL_IM_MODULE"); + const char *xmodifiers = SDL_getenv("XMODIFIERS"); +#endif + + if (inited == SDL_TRUE) + return; + + inited = SDL_TRUE; + + /* See if fcitx IME support is being requested */ +#ifdef HAVE_FCITX_FRONTEND_H + if (!SDL_IME_Init_Real && + ((im_module && SDL_strcmp(im_module, "fcitx") == 0) || + (!im_module && xmodifiers && SDL_strstr(xmodifiers, "@im=fcitx") != NULL))) { + SDL_IME_Init_Real = SDL_Fcitx_Init; + SDL_IME_Quit_Real = SDL_Fcitx_Quit; + SDL_IME_SetFocus_Real = SDL_Fcitx_SetFocus; + SDL_IME_Reset_Real = SDL_Fcitx_Reset; + SDL_IME_ProcessKeyEvent_Real = SDL_Fcitx_ProcessKeyEvent; + SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect; + SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents; + } +#endif /* HAVE_FCITX_FRONTEND_H */ + + /* default to IBus */ +#ifdef HAVE_IBUS_IBUS_H + if (!SDL_IME_Init_Real) { + SDL_IME_Init_Real = SDL_IBus_Init; + SDL_IME_Quit_Real = SDL_IBus_Quit; + SDL_IME_SetFocus_Real = SDL_IBus_SetFocus; + SDL_IME_Reset_Real = SDL_IBus_Reset; + SDL_IME_ProcessKeyEvent_Real = SDL_IBus_ProcessKeyEvent; + SDL_IME_UpdateTextRect_Real = SDL_IBus_UpdateTextRect; + SDL_IME_PumpEvents_Real = SDL_IBus_PumpEvents; + } +#endif /* HAVE_IBUS_IBUS_H */ +} + +SDL_bool +SDL_IME_Init(void) +{ + InitIME(); + + if (SDL_IME_Init_Real) + return SDL_IME_Init_Real(); + + return SDL_FALSE; +} + +void +SDL_IME_Quit(void) +{ + if (SDL_IME_Quit_Real) + SDL_IME_Quit_Real(); +} + +void +SDL_IME_SetFocus(SDL_bool focused) +{ + if (SDL_IME_SetFocus_Real) + SDL_IME_SetFocus_Real(focused); +} + +void +SDL_IME_Reset(void) +{ + if (SDL_IME_Reset_Real) + SDL_IME_Reset_Real(); +} + +SDL_bool +SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +{ + if (SDL_IME_ProcessKeyEvent_Real) + return SDL_IME_ProcessKeyEvent_Real(keysym, keycode); + + return SDL_FALSE; +} + +void +SDL_IME_UpdateTextRect(SDL_Rect *rect) +{ + if (SDL_IME_UpdateTextRect_Real) + SDL_IME_UpdateTextRect_Real(rect); +} + +void +SDL_IME_PumpEvents() +{ + if (SDL_IME_PumpEvents_Real) + SDL_IME_PumpEvents_Real(); +} diff --git a/Engine/lib/sdl/src/core/linux/SDL_ime.h b/Engine/lib/sdl/src/core/linux/SDL_ime.h new file mode 100644 index 000000000..22b31de39 --- /dev/null +++ b/Engine/lib/sdl/src/core/linux/SDL_ime.h @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_ime_h +#define _SDL_ime_h + +#include "../../SDL_internal.h" + +#include "SDL_stdinc.h" +#include "SDL_rect.h" + +extern SDL_bool SDL_IME_Init(); +extern void SDL_IME_Quit(); +extern void SDL_IME_SetFocus(SDL_bool focused); +extern void SDL_IME_Reset(); +extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern void SDL_IME_UpdateTextRect(SDL_Rect *rect); +extern void SDL_IME_PumpEvents(); + +#endif /* _SDL_ime_h */ diff --git a/Engine/lib/sdl/src/core/linux/SDL_udev.c b/Engine/lib/sdl/src/core/linux/SDL_udev.c index 099cc435e..ae78ddd68 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_udev.c +++ b/Engine/lib/sdl/src/core/linux/SDL_udev.c @@ -349,7 +349,9 @@ guess_device_class(struct udev_device *dev) } else if (test_bit(BTN_MOUSE, bitmask_key)) { devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ } else if (test_bit(BTN_TOUCH, bitmask_key)) { - ; /* ID_INPUT_TOUCHSCREEN */ + /* TODO: better determining between touchscreen and multitouch touchpad, + see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */ + devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */ } if (test_bit(BTN_TRIGGER, bitmask_key) || @@ -411,6 +413,11 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) if (val != NULL && SDL_strcmp(val, "1") == 0 ) { devclass |= SDL_UDEV_DEVICE_MOUSE; } + + val = _this->udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN"); + if (val != NULL && SDL_strcmp(val, "1") == 0 ) { + devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; + } /* The undocumented rule is: - All devices with keys get ID_INPUT_KEY diff --git a/Engine/lib/sdl/src/core/linux/SDL_udev.h b/Engine/lib/sdl/src/core/linux/SDL_udev.h index 2e4434e62..9ffbb3252 100644 --- a/Engine/lib/sdl/src/core/linux/SDL_udev.h +++ b/Engine/lib/sdl/src/core/linux/SDL_udev.h @@ -42,17 +42,19 @@ typedef enum { - SDL_UDEV_DEVICEADDED = 0x0001, + SDL_UDEV_DEVICEADDED = 1, SDL_UDEV_DEVICEREMOVED } SDL_UDEV_deviceevent; /* A device can be any combination of these classes */ typedef enum { + SDL_UDEV_DEVICE_UNKNOWN = 0x0000, SDL_UDEV_DEVICE_MOUSE = 0x0001, SDL_UDEV_DEVICE_KEYBOARD = 0x0002, SDL_UDEV_DEVICE_JOYSTICK = 0x0004, - SDL_UDEV_DEVICE_SOUND = 0x0008 + SDL_UDEV_DEVICE_SOUND = 0x0008, + SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010 } SDL_UDEV_deviceclass; typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); diff --git a/Engine/lib/sdl/src/core/windows/SDL_windows.c b/Engine/lib/sdl/src/core/windows/SDL_windows.c index bc4afe0aa..6433fe26f 100644 --- a/Engine/lib/sdl/src/core/windows/SDL_windows.c +++ b/Engine/lib/sdl/src/core/windows/SDL_windows.c @@ -124,6 +124,84 @@ BOOL WIN_IsWindowsVistaOrGreater() #endif } +/* +WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's +longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which +will give you a name GUID. The full name is in the Windows Registry under +that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories + +Note that drivers can report GUID_NULL for the name GUID, in which case, +Windows makes a best effort to fill in those 31 bytes in the usual place. +This info summarized from MSDN: + +http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx + +Always look this up in the registry if possible, because the strings are +different! At least on Win10, I see "Yeti Stereo Microphone" in the +Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh. + +(Also, DirectSound shouldn't be limited to 32 chars, but its device enum +has the same problem.) +*/ +char * +WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid) +{ +#if __WINRT__ + return WIN_StringToUTF8(name); /* No registry access on WinRT/UWP, go with what we've got. */ +#else + static const GUID nullguid = { 0 }; + const unsigned char *ptr; + char keystr[128]; + WCHAR *strw = NULL; + SDL_bool rc; + HKEY hkey; + DWORD len = 0; + char *retval = NULL; + + if (SDL_memcmp(guid, &nullguid, sizeof (*guid)) == 0) { + return WIN_StringToUTF8(name); /* No GUID, go with what we've got. */ + } + + ptr = (const unsigned char *) guid; + SDL_snprintf(keystr, sizeof (keystr), + "System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6], + ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]); + + strw = WIN_UTF8ToString(keystr); + rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS); + SDL_free(strw); + if (!rc) { + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS); + if (!rc) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw = (WCHAR *) SDL_malloc(len + sizeof (WCHAR)); + if (!strw) { + RegCloseKey(hkey); + return WIN_StringToUTF8(name); /* oh well. */ + } + + rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE) strw, &len) == ERROR_SUCCESS); + RegCloseKey(hkey); + if (!rc) { + SDL_free(strw); + return WIN_StringToUTF8(name); /* oh well. */ + } + + strw[len / 2] = 0; /* make sure it's null-terminated. */ + + retval = WIN_StringToUTF8(strw); + SDL_free(strw); + return retval ? retval : WIN_StringToUTF8(name); +#endif /* if __WINRT__ / else */ +} + #endif /* __WIN32__ || __WINRT__ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/core/windows/SDL_windows.h b/Engine/lib/sdl/src/core/windows/SDL_windows.h index 0c99b03d4..0f67e4be5 100644 --- a/Engine/lib/sdl/src/core/windows/SDL_windows.h +++ b/Engine/lib/sdl/src/core/windows/SDL_windows.h @@ -59,6 +59,9 @@ extern void WIN_CoUninitialize(void); /* Returns SDL_TRUE if we're running on Windows Vista and newer */ extern BOOL WIN_IsWindowsVistaOrGreater(); +/* You need to SDL_free() the result of this call. */ +extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid); + #endif /* _INCLUDED_WINDOWS_H */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.cpp b/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.cpp index 5ab2ef9a2..e4ffadaad 100644 --- a/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -254,6 +254,18 @@ void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) CoreApplication::Exiting += ref new EventHandler(this, &SDL_WinRTApp::OnExiting); + +#if NTDDI_VERSION >= NTDDI_WIN10 + /* HACK ALERT! Xbox One doesn't seem to detect gamepads unless something + gets registered to receive Win10's Windows.Gaming.Input.Gamepad.GamepadAdded + events. We'll register an event handler for these events here, to make + sure that gamepad detection works later on, if requested. + */ + Windows::Gaming::Input::Gamepad::GamepadAdded += + ref new Windows::Foundation::EventHandler( + this, &SDL_WinRTApp::OnGamepadAdded + ); +#endif } #if NTDDI_VERSION > NTDDI_WIN8 @@ -810,11 +822,8 @@ static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args) SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK); SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK); - const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON); - if (hint) { - if (*hint == '1') { - args->Handled = true; - } + if (SDL_GetHintBoolean(SDL_HINT_WINRT_HANDLE_BACK_BUTTON, SDL_FALSE)) { + args->Handled = true; } } @@ -832,3 +841,15 @@ void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone: } #endif +#if NTDDI_VERSION >= NTDDI_WIN10 +void SDL_WinRTApp::OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad) +{ + /* HACK ALERT: Nothing needs to be done here, as this method currently + only exists to allow something to be registered with Win10's + GamepadAdded event, an operation that seems to be necessary to get + Xinput-based detection to work on Xbox One. + */ +} +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.h b/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.h index 0b69c2bb9..4b48115f0 100644 --- a/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.h +++ b/Engine/lib/sdl/src/core/winrt/SDL_winrtapp_direct3d.h @@ -80,6 +80,10 @@ protected: void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args); #endif +#if NTDDI_VERSION >= NTDDI_WIN10 + void OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad); +#endif + private: bool m_windowClosed; bool m_windowVisible; diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi.c b/Engine/lib/sdl/src/dynapi/SDL_dynapi.c index 1411f8c93..c26baf379 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi.c +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi.c @@ -293,7 +293,7 @@ SDL_InitDynamicAPI(void) * SDL_CreateThread() would also call this function before building the * new thread). */ - static volatile SDL_bool already_initialized = SDL_FALSE; + static SDL_bool already_initialized = SDL_FALSE; /* SDL_AtomicLock calls SDL mutex functions to emulate if SDL_ATOMIC_DISABLED, which we can't do here, so in such a diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi.h b/Engine/lib/sdl/src/dynapi/SDL_dynapi.h index 5faac2194..5e78338f2 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi.h +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi.h @@ -43,9 +43,15 @@ #include "TargetConditionals.h" #endif -#if TARGET_OS_IPHONE || __native_client__ || __EMSCRIPTEN__ /* probably not useful on iOS, NACL or Emscripten. */ +#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE /* probably not useful on iOS. */ #define SDL_DYNAMIC_API 0 -#elif SDL_BUILDING_WINRT /* probaly not useful on WinRT, given current .dll loading restrictions */ +#elif defined(__native_client__) && __native_client__ /* probably not useful on NACL. */ +#define SDL_DYNAMIC_API 0 +#elif defined(__EMSCRIPTEN__) && __EMSCRIPTEN__ /* probably not useful on Emscripten. */ +#define SDL_DYNAMIC_API 0 +#elif defined(SDL_BUILDING_WINRT) && SDL_BUILDING_WINRT /* probably not useful on WinRT, given current .dll loading restrictions */ +#define SDL_DYNAMIC_API 0 +#elif defined(__PSP__) && __PSP__ #define SDL_DYNAMIC_API 0 #elif defined(__clang_analyzer__) #define SDL_DYNAMIC_API 0 /* Turn off for static analysis, so reports are more clear. */ diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h b/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h index c9ebfffe2..9541611ce 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi_overrides.h @@ -445,6 +445,8 @@ #define SDL_iconv_close SDL_iconv_close_REAL #define SDL_iconv SDL_iconv_REAL #define SDL_iconv_string SDL_iconv_string_REAL +#define SDL_CreateRGBSurfaceWithFormat SDL_CreateRGBSurfaceWithFormat_REAL +#define SDL_CreateRGBSurfaceWithFormatFrom SDL_CreateRGBSurfaceWithFormatFrom_REAL #define SDL_CreateRGBSurface SDL_CreateRGBSurface_REAL #define SDL_CreateRGBSurfaceFrom SDL_CreateRGBSurfaceFrom_REAL #define SDL_FreeSurface SDL_FreeSurface_REAL @@ -597,3 +599,16 @@ #define SDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel_REAL #define SDL_GameControllerFromInstanceID SDL_GameControllerFromInstanceID_REAL #define SDL_JoystickFromInstanceID SDL_JoystickFromInstanceID_REAL +#define SDL_GetDisplayUsableBounds SDL_GetDisplayUsableBounds_REAL +#define SDL_GetWindowBordersSize SDL_GetWindowBordersSize_REAL +#define SDL_SetWindowOpacity SDL_SetWindowOpacity_REAL +#define SDL_GetWindowOpacity SDL_GetWindowOpacity_REAL +#define SDL_SetWindowInputFocus SDL_SetWindowInputFocus_REAL +#define SDL_SetWindowModalFor SDL_SetWindowModalFor_REAL +#define SDL_RenderSetIntegerScale SDL_RenderSetIntegerScale_REAL +#define SDL_RenderGetIntegerScale SDL_RenderGetIntegerScale_REAL +#define SDL_DequeueAudio SDL_DequeueAudio_REAL +#define SDL_SetWindowResizable SDL_SetWindowResizable_REAL +#define SDL_CreateRGBSurfaceWithFormat SDL_CreateRGBSurfaceWithFormat_REAL +#define SDL_CreateRGBSurfaceWithFormatFrom SDL_CreateRGBSurfaceWithFormatFrom_REAL +#define SDL_GetHintBoolean SDL_GetHintBoolean_REAL diff --git a/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h b/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h index 3f11a25f9..a08835b26 100644 --- a/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h +++ b/Engine/lib/sdl/src/dynapi/SDL_dynapi_procs.h @@ -631,3 +631,16 @@ SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_JoystickCurrentPowerLevel,(SDL_Joystick *a),(a),return) SDL_DYNAPI_PROC(SDL_GameController*,SDL_GameControllerFromInstanceID,(SDL_JoystickID a),(a),return) SDL_DYNAPI_PROC(SDL_Joystick*,SDL_JoystickFromInstanceID,(SDL_JoystickID a),(a),return) +SDL_DYNAPI_PROC(int,SDL_GetDisplayUsableBounds,(int a, SDL_Rect *b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_GetWindowBordersSize,(SDL_Window *a, int *b, int *c, int *d, int *e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(int,SDL_SetWindowOpacity,(SDL_Window *a, float b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_GetWindowOpacity,(SDL_Window *a, float *b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_SetWindowInputFocus,(SDL_Window *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_SetWindowModalFor,(SDL_Window *a, SDL_Window *b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_RenderSetIntegerScale,(SDL_Renderer *a, SDL_bool b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_RenderGetIntegerScale,(SDL_Renderer *a),(a),return) +SDL_DYNAPI_PROC(Uint32,SDL_DequeueAudio,(SDL_AudioDeviceID a, void *b, Uint32 c),(a,b,c),return) +SDL_DYNAPI_PROC(void,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),) +SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurfaceWithFormat,(Uint32 a, int b, int c, int d, Uint32 e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(SDL_Surface*,SDL_CreateRGBSurfaceWithFormatFrom,(void *a, int b, int c, int d, int e, Uint32 f),(a,b,c,d,e,f),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_GetHintBoolean,(const char *a, SDL_bool b),(a,b),return) diff --git a/Engine/lib/sdl/src/events/SDL_dropevents.c b/Engine/lib/sdl/src/events/SDL_dropevents.c index 8f4405efa..49b07d9a6 100644 --- a/Engine/lib/sdl/src/events/SDL_dropevents.c +++ b/Engine/lib/sdl/src/events/SDL_dropevents.c @@ -26,21 +26,73 @@ #include "SDL_events_c.h" #include "SDL_dropevents_c.h" +#include "../video/SDL_sysvideo.h" /* for SDL_Window internals. */ -int -SDL_SendDropFile(const char *file) + +static int +SDL_SendDrop(SDL_Window *window, const SDL_EventType evtype, const char *data) { - int posted; + static SDL_bool app_is_dropping = SDL_FALSE; + int posted = 0; /* Post the event, if desired */ - posted = 0; - if (SDL_GetEventState(SDL_DROPFILE) == SDL_ENABLE) { + if (SDL_GetEventState(evtype) == SDL_ENABLE) { + const SDL_bool need_begin = window ? !window->is_dropping : !app_is_dropping; SDL_Event event; - event.type = SDL_DROPFILE; - event.drop.file = SDL_strdup(file); + + if (need_begin) { + SDL_zero(event); + event.type = SDL_DROPBEGIN; + + if (window) { + event.drop.windowID = window->id; + } + + posted = (SDL_PushEvent(&event) > 0); + if (!posted) { + return 0; + } + if (window) { + window->is_dropping = SDL_TRUE; + } else { + app_is_dropping = SDL_TRUE; + } + } + + SDL_zero(event); + event.type = evtype; + event.drop.file = data ? SDL_strdup(data) : NULL; + event.drop.windowID = window ? window->id : 0; posted = (SDL_PushEvent(&event) > 0); + + if (posted && (evtype == SDL_DROPCOMPLETE)) { + if (window) { + window->is_dropping = SDL_FALSE; + } else { + app_is_dropping = SDL_FALSE; + } + } } - return (posted); + return posted; } +int +SDL_SendDropFile(SDL_Window *window, const char *file) +{ + return SDL_SendDrop(window, SDL_DROPFILE, file); +} + +int +SDL_SendDropText(SDL_Window *window, const char *text) +{ + return SDL_SendDrop(window, SDL_DROPTEXT, text); +} + +int +SDL_SendDropComplete(SDL_Window *window) +{ + return SDL_SendDrop(window, SDL_DROPCOMPLETE, NULL); +} + + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/events/SDL_dropevents_c.h b/Engine/lib/sdl/src/events/SDL_dropevents_c.h index a60e089f3..a7adb8560 100644 --- a/Engine/lib/sdl/src/events/SDL_dropevents_c.h +++ b/Engine/lib/sdl/src/events/SDL_dropevents_c.h @@ -23,7 +23,9 @@ #ifndef _SDL_dropevents_c_h #define _SDL_dropevents_c_h -extern int SDL_SendDropFile(const char *file); +extern int SDL_SendDropFile(SDL_Window *window, const char *file); +extern int SDL_SendDropText(SDL_Window *window, const char *text); +extern int SDL_SendDropComplete(SDL_Window *window); #endif /* _SDL_dropevents_c_h */ diff --git a/Engine/lib/sdl/src/events/SDL_events.c b/Engine/lib/sdl/src/events/SDL_events.c index ffd103824..2f5b0af29 100644 --- a/Engine/lib/sdl/src/events/SDL_events.c +++ b/Engine/lib/sdl/src/events/SDL_events.c @@ -73,15 +73,15 @@ typedef struct _SDL_SysWMEntry static struct { SDL_mutex *lock; - volatile SDL_bool active; - volatile int count; - volatile int max_events_seen; + SDL_atomic_t active; + SDL_atomic_t count; + 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, 0, 0, NULL, NULL, NULL, NULL, NULL }; +} SDL_EventQ = { NULL, { 1 }, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }; /* Public functions */ @@ -98,7 +98,7 @@ SDL_StopEventLoop(void) SDL_LockMutex(SDL_EventQ.lock); } - SDL_EventQ.active = SDL_FALSE; + SDL_AtomicSet(&SDL_EventQ.active, 0); if (report && SDL_atoi(report)) { SDL_Log("SDL EVENT QUEUE: Maximum events in-flight: %d\n", @@ -127,7 +127,7 @@ SDL_StopEventLoop(void) wmmsg = next; } - SDL_EventQ.count = 0; + SDL_AtomicSet(&SDL_EventQ.count, 0); SDL_EventQ.max_events_seen = 0; SDL_EventQ.head = NULL; SDL_EventQ.tail = NULL; @@ -171,7 +171,7 @@ SDL_StartEventLoop(void) SDL_EventQ.lock = SDL_CreateMutex(); } if (SDL_EventQ.lock == NULL) { - return (-1); + return -1; } #endif /* !SDL_THREADS_DISABLED */ @@ -180,9 +180,9 @@ SDL_StartEventLoop(void) SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE); - SDL_EventQ.active = SDL_TRUE; + SDL_AtomicSet(&SDL_EventQ.active, 1); - return (0); + return 0; } @@ -191,9 +191,11 @@ static int SDL_AddEvent(SDL_Event * event) { SDL_EventEntry *entry; + const int initial_count = SDL_AtomicGet(&SDL_EventQ.count); + int final_count; - if (SDL_EventQ.count >= SDL_MAX_QUEUED_EVENTS) { - SDL_SetError("Event queue is full (%d events)", SDL_EventQ.count); + if (initial_count >= SDL_MAX_QUEUED_EVENTS) { + SDL_SetError("Event queue is full (%d events)", initial_count); return 0; } @@ -225,10 +227,10 @@ SDL_AddEvent(SDL_Event * event) entry->prev = NULL; entry->next = NULL; } - ++SDL_EventQ.count; - if (SDL_EventQ.count > SDL_EventQ.max_events_seen) { - SDL_EventQ.max_events_seen = SDL_EventQ.count; + final_count = SDL_AtomicAdd(&SDL_EventQ.count, 1) + 1; + if (final_count > SDL_EventQ.max_events_seen) { + SDL_EventQ.max_events_seen = final_count; } return 1; @@ -256,8 +258,8 @@ SDL_CutEvent(SDL_EventEntry *entry) entry->next = SDL_EventQ.free; SDL_EventQ.free = entry; - SDL_assert(SDL_EventQ.count > 0); - --SDL_EventQ.count; + SDL_assert(SDL_AtomicGet(&SDL_EventQ.count) > 0); + SDL_AtomicAdd(&SDL_EventQ.count, -1); } /* Lock the event queue, take a peep at it, and unlock it */ @@ -268,7 +270,7 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action, int i, used; /* Don't look after we've quit */ - if (!SDL_EventQ.active) { + if (!SDL_AtomicGet(&SDL_EventQ.active)) { /* We get a few spurious events at shutdown, so don't warn then */ if (action != SDL_ADDEVENT) { SDL_SetError("The event system has been shut down"); @@ -285,56 +287,54 @@ SDL_PeepEvents(SDL_Event * events, int numevents, SDL_eventaction action, } else { SDL_EventEntry *entry, *next; SDL_SysWMEntry *wmmsg, *wmmsg_next; - SDL_Event tmpevent; Uint32 type; - /* If 'events' is NULL, just see if they exist */ - if (events == NULL) { - action = SDL_PEEKEVENT; - numevents = 1; - events = &tmpevent; + if (action == SDL_GETEVENT) { + /* Clean out any used wmmsg data + FIXME: Do we want to retain the data for some period of time? + */ + for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) { + wmmsg_next = wmmsg->next; + wmmsg->next = SDL_EventQ.wmmsg_free; + SDL_EventQ.wmmsg_free = wmmsg; + } + SDL_EventQ.wmmsg_used = NULL; } - /* Clean out any used wmmsg data - FIXME: Do we want to retain the data for some period of time? - */ - for (wmmsg = SDL_EventQ.wmmsg_used; wmmsg; wmmsg = wmmsg_next) { - wmmsg_next = wmmsg->next; - wmmsg->next = SDL_EventQ.wmmsg_free; - SDL_EventQ.wmmsg_free = wmmsg; - } - SDL_EventQ.wmmsg_used = NULL; - - for (entry = SDL_EventQ.head; entry && used < numevents; entry = next) { + for (entry = SDL_EventQ.head; entry && (!events || used < numevents); entry = next) { next = entry->next; type = entry->event.type; if (minType <= type && type <= maxType) { - events[used] = entry->event; - if (entry->event.type == SDL_SYSWMEVENT) { - /* We need to copy the wmmsg somewhere safe. - For now we'll guarantee it's valid at least until - the next call to SDL_PeepEvents() - */ - if (SDL_EventQ.wmmsg_free) { - wmmsg = SDL_EventQ.wmmsg_free; - SDL_EventQ.wmmsg_free = wmmsg->next; - } else { - wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg)); + if (events) { + events[used] = entry->event; + if (entry->event.type == SDL_SYSWMEVENT) { + /* We need to copy the wmmsg somewhere safe. + For now we'll guarantee it's valid at least until + the next call to SDL_PeepEvents() + */ + if (SDL_EventQ.wmmsg_free) { + wmmsg = SDL_EventQ.wmmsg_free; + SDL_EventQ.wmmsg_free = wmmsg->next; + } else { + wmmsg = (SDL_SysWMEntry *)SDL_malloc(sizeof(*wmmsg)); + } + wmmsg->msg = *entry->event.syswm.msg; + wmmsg->next = SDL_EventQ.wmmsg_used; + SDL_EventQ.wmmsg_used = wmmsg; + events[used].syswm.msg = &wmmsg->msg; + } + + if (action == SDL_GETEVENT) { + SDL_CutEvent(entry); } - wmmsg->msg = *entry->event.syswm.msg; - wmmsg->next = SDL_EventQ.wmmsg_used; - SDL_EventQ.wmmsg_used = wmmsg; - events[used].syswm.msg = &wmmsg->msg; } ++used; - - if (action == SDL_GETEVENT) { - SDL_CutEvent(entry); - } } } } - SDL_UnlockMutex(SDL_EventQ.lock); + if (SDL_EventQ.lock) { + SDL_UnlockMutex(SDL_EventQ.lock); + } } else { return SDL_SetError("Couldn't lock event queue"); } @@ -363,7 +363,7 @@ void SDL_FlushEvents(Uint32 minType, Uint32 maxType) { /* Don't look after we've quit */ - if (!SDL_EventQ.active) { + if (!SDL_AtomicGet(&SDL_EventQ.active)) { return; } @@ -376,7 +376,7 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType) #endif /* Lock the event queue */ - if (SDL_LockMutex(SDL_EventQ.lock) == 0) { + if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) { SDL_EventEntry *entry, *next; Uint32 type; for (entry = SDL_EventQ.head; entry; entry = next) { @@ -437,8 +437,6 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout) switch (SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) { case -1: return 0; - case 1: - return 1; case 0: if (timeout == 0) { /* Polling and no events, just return */ @@ -450,6 +448,9 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout) } SDL_Delay(10); break; + default: + /* Has events */ + return 1; } } } diff --git a/Engine/lib/sdl/src/events/SDL_gesture.c b/Engine/lib/sdl/src/events/SDL_gesture.c index 66def4429..43914202c 100644 --- a/Engine/lib/sdl/src/events/SDL_gesture.c +++ b/Engine/lib/sdl/src/events/SDL_gesture.c @@ -21,7 +21,7 @@ #include "../SDL_internal.h" -/* General mouse handling code for SDL */ +/* General gesture handling code for SDL */ #include "SDL_events.h" #include "SDL_endian.h" diff --git a/Engine/lib/sdl/src/events/SDL_mouse.c b/Engine/lib/sdl/src/events/SDL_mouse.c index 7793de870..4236a9901 100644 --- a/Engine/lib/sdl/src/events/SDL_mouse.c +++ b/Engine/lib/sdl/src/events/SDL_mouse.c @@ -322,15 +322,13 @@ static SDL_MouseClickState *GetMouseClickState(SDL_Mouse *mouse, Uint8 button) return &mouse->clickstate[button]; } -int -SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button) +static int +SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks) { SDL_Mouse *mouse = SDL_GetMouse(); int posted; Uint32 type; Uint32 buttonstate = mouse->buttonstate; - SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button); - Uint8 click_count; /* Figure out which event to perform */ switch (state) { @@ -358,25 +356,28 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 } mouse->buttonstate = buttonstate; - if (clickstate) { - if (state == SDL_PRESSED) { - Uint32 now = SDL_GetTicks(); + if (clicks < 0) { + SDL_MouseClickState *clickstate = GetMouseClickState(mouse, button); + if (clickstate) { + if (state == SDL_PRESSED) { + Uint32 now = SDL_GetTicks(); - if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) || - SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius || - SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) { - clickstate->click_count = 0; - } - clickstate->last_timestamp = now; - clickstate->last_x = mouse->x; - clickstate->last_y = mouse->y; - if (clickstate->click_count < 255) { - ++clickstate->click_count; + if (SDL_TICKS_PASSED(now, clickstate->last_timestamp + SDL_double_click_time) || + SDL_abs(mouse->x - clickstate->last_x) > SDL_double_click_radius || + SDL_abs(mouse->y - clickstate->last_y) > SDL_double_click_radius) { + clickstate->click_count = 0; + } + clickstate->last_timestamp = now; + clickstate->last_x = mouse->x; + clickstate->last_y = mouse->y; + if (clickstate->click_count < 255) { + ++clickstate->click_count; + } } + clicks = clickstate->click_count; + } else { + clicks = 1; } - click_count = clickstate->click_count; - } else { - click_count = 1; } /* Post the event, if desired */ @@ -388,7 +389,7 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 event.button.which = mouseID; event.button.state = state; event.button.button = button; - event.button.clicks = click_count; + event.button.clicks = (Uint8) SDL_min(clicks, 255); event.button.x = mouse->x; event.button.y = mouse->y; posted = (SDL_PushEvent(&event) > 0); @@ -398,10 +399,23 @@ SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 if (window && state == SDL_RELEASED) { SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate); } - + return posted; } +int +SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks) +{ + clicks = SDL_max(clicks, 0); + return SDL_PrivateSendMouseButton(window, mouseID, state, button, clicks); +} + +int +SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button) +{ + return SDL_PrivateSendMouseButton(window, mouseID, state, button, -1); +} + int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction) { @@ -550,21 +564,11 @@ SDL_WarpMouseGlobal(int x, int y) static SDL_bool ShouldUseRelativeModeWarp(SDL_Mouse *mouse) { - const char *hint; - if (!mouse->SetRelativeMouseMode) { return SDL_TRUE; } - hint = SDL_GetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - return SDL_FALSE; + return SDL_GetHintBoolean(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, SDL_FALSE); } int diff --git a/Engine/lib/sdl/src/events/SDL_mouse_c.h b/Engine/lib/sdl/src/events/SDL_mouse_c.h index 03aca0a5c..06dc88701 100644 --- a/Engine/lib/sdl/src/events/SDL_mouse_c.h +++ b/Engine/lib/sdl/src/events/SDL_mouse_c.h @@ -119,6 +119,9 @@ extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int rel /* Send a mouse button event */ extern int SDL_SendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button); +/* Send a mouse button event with a click count */ +extern int SDL_SendMouseButtonClicks(SDL_Window * window, SDL_MouseID mouseID, Uint8 state, Uint8 button, int clicks); + /* Send a mouse wheel event */ extern int SDL_SendMouseWheel(SDL_Window * window, SDL_MouseID mouseID, int x, int y, SDL_MouseWheelDirection direction); diff --git a/Engine/lib/sdl/src/events/SDL_quit.c b/Engine/lib/sdl/src/events/SDL_quit.c index 5b7105ef8..3cb6b3d4f 100644 --- a/Engine/lib/sdl/src/events/SDL_quit.c +++ b/Engine/lib/sdl/src/events/SDL_quit.c @@ -91,9 +91,7 @@ SDL_QuitInit_Internal(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) { + if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) { return SDL_QuitInit_Internal(); } return 0; diff --git a/Engine/lib/sdl/src/events/SDL_windowevents.c b/Engine/lib/sdl/src/events/SDL_windowevents.c index 785ea4e0c..b45015bd0 100644 --- a/Engine/lib/sdl/src/events/SDL_windowevents.c +++ b/Engine/lib/sdl/src/events/SDL_windowevents.c @@ -70,6 +70,20 @@ RemovePendingMoveEvents(void * userdata, SDL_Event *event) return 1; } +static int +RemovePendingExposedEvents(void * userdata, SDL_Event *event) +{ + SDL_Event *new_event = (SDL_Event *)userdata; + + if (event->type == SDL_WINDOWEVENT && + event->window.event == SDL_WINDOWEVENT_EXPOSED && + event->window.windowID == new_event->window.windowID) { + /* We're about to post a new exposed event, drop the old one */ + return 0; + } + return 1; +} + int SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1, int data2) @@ -195,7 +209,9 @@ SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1, if (windowevent == SDL_WINDOWEVENT_MOVED) { SDL_FilterEvents(RemovePendingMoveEvents, &event); } - + if (windowevent == SDL_WINDOWEVENT_EXPOSED) { + SDL_FilterEvents(RemovePendingExposedEvents, &event); + } posted = (SDL_PushEvent(&event) > 0); } diff --git a/Engine/lib/sdl/src/events/scancodes_linux.h b/Engine/lib/sdl/src/events/scancodes_linux.h index 8db37df5b..e197ee3fe 100644 --- a/Engine/lib/sdl/src/events/scancodes_linux.h +++ b/Engine/lib/sdl/src/events/scancodes_linux.h @@ -111,7 +111,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 82 */ SDL_SCANCODE_KP_0, /* 83 */ SDL_SCANCODE_KP_PERIOD, 0, - /* 85 */ SDL_SCANCODE_UNKNOWN, /* KEY_ZENKAKUHANKAKU */ + /* 85 */ SDL_SCANCODE_LANG5, /* KEY_ZENKAKUHANKAKU */ /* 86 */ SDL_SCANCODE_NONUSBACKSLASH, /* KEY_102ND */ /* 87 */ SDL_SCANCODE_F11, /* 88 */ SDL_SCANCODE_F12, @@ -153,7 +153,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 124 */ SDL_SCANCODE_INTERNATIONAL3, /* KEY_YEN */ /* 125 */ SDL_SCANCODE_LGUI, /* 126 */ SDL_SCANCODE_RGUI, - /* 127 */ SDL_SCANCODE_UNKNOWN, /* KEY_COMPOSE */ + /* 127 */ SDL_SCANCODE_APPLICATION, /* KEY_COMPOSE */ /* 128 */ SDL_SCANCODE_STOP, /* 129 */ SDL_SCANCODE_AGAIN, /* 130 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROPS */ @@ -174,9 +174,9 @@ static SDL_Scancode const linux_scancode_table[] = { /* 145 */ SDL_SCANCODE_UNKNOWN, /* KEY_SENDFILE */ /* 146 */ SDL_SCANCODE_UNKNOWN, /* KEY_DELETEFILE */ /* 147 */ SDL_SCANCODE_UNKNOWN, /* KEY_XFER */ - /* 148 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG1 */ - /* 149 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG2 */ - /* 150 */ SDL_SCANCODE_UNKNOWN, /* KEY_WWW */ + /* 148 */ SDL_SCANCODE_APP1, /* KEY_PROG1 */ + /* 149 */ SDL_SCANCODE_APP2, /* KEY_PROG2 */ + /* 150 */ SDL_SCANCODE_WWW, /* KEY_WWW */ /* 151 */ SDL_SCANCODE_UNKNOWN, /* KEY_MSDOS */ /* 152 */ SDL_SCANCODE_UNKNOWN, /* KEY_COFFEE */ /* 153 */ SDL_SCANCODE_UNKNOWN, /* KEY_DIRECTION */ @@ -192,7 +192,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 163 */ SDL_SCANCODE_AUDIONEXT, /* KEY_NEXTSONG */ /* 164 */ SDL_SCANCODE_AUDIOPLAY, /* KEY_PLAYPAUSE */ /* 165 */ SDL_SCANCODE_AUDIOPREV, /* KEY_PREVIOUSSONG */ - /* 166 */ SDL_SCANCODE_UNKNOWN, /* KEY_STOPCD */ + /* 166 */ SDL_SCANCODE_AUDIOSTOP, /* KEY_STOPCD */ /* 167 */ SDL_SCANCODE_UNKNOWN, /* KEY_RECORD */ /* 168 */ SDL_SCANCODE_UNKNOWN, /* KEY_REWIND */ /* 169 */ SDL_SCANCODE_UNKNOWN, /* KEY_PHONE */ @@ -221,7 +221,7 @@ static SDL_Scancode const linux_scancode_table[] = { /* 192 */ SDL_SCANCODE_F22, /* 193 */ SDL_SCANCODE_F23, /* 194 */ SDL_SCANCODE_F24, - 0, 0, 0, 0, + 0, 0, 0, 0, 0, /* 200 */ SDL_SCANCODE_UNKNOWN, /* KEY_PLAYCD */ /* 201 */ SDL_SCANCODE_UNKNOWN, /* KEY_PAUSECD */ /* 202 */ SDL_SCANCODE_UNKNOWN, /* KEY_PROG3 */ diff --git a/Engine/lib/sdl/src/events/scancodes_xfree86.h b/Engine/lib/sdl/src/events/scancodes_xfree86.h index 29d9ef944..804196ca4 100644 --- a/Engine/lib/sdl/src/events/scancodes_xfree86.h +++ b/Engine/lib/sdl/src/events/scancodes_xfree86.h @@ -418,4 +418,89 @@ static const SDL_Scancode xfree86_scancode_table2[] = { /* 238 */ SDL_SCANCODE_UNKNOWN, /* XF86WLAN */ }; +/* Xvnc / Xtightvnc scancodes from xmodmap -pk */ +static const SDL_Scancode xvnc_scancode_table[] = { + /* 0 */ SDL_SCANCODE_LCTRL, + /* 1 */ SDL_SCANCODE_RCTRL, + /* 2 */ SDL_SCANCODE_LSHIFT, + /* 3 */ SDL_SCANCODE_RSHIFT, + /* 4 */ SDL_SCANCODE_UNKNOWN, /* Meta_L */ + /* 5 */ SDL_SCANCODE_UNKNOWN, /* Meta_R */ + /* 6 */ SDL_SCANCODE_LALT, + /* 7 */ SDL_SCANCODE_RALT, + /* 8 */ SDL_SCANCODE_SPACE, + /* 9 */ SDL_SCANCODE_0, + /* 10 */ SDL_SCANCODE_1, + /* 11 */ SDL_SCANCODE_2, + /* 12 */ SDL_SCANCODE_3, + /* 13 */ SDL_SCANCODE_4, + /* 14 */ SDL_SCANCODE_5, + /* 15 */ SDL_SCANCODE_6, + /* 16 */ SDL_SCANCODE_7, + /* 17 */ SDL_SCANCODE_8, + /* 18 */ SDL_SCANCODE_9, + /* 19 */ SDL_SCANCODE_MINUS, + /* 20 */ SDL_SCANCODE_EQUALS, + /* 21 */ SDL_SCANCODE_LEFTBRACKET, + /* 22 */ SDL_SCANCODE_RIGHTBRACKET, + /* 23 */ SDL_SCANCODE_SEMICOLON, + /* 24 */ SDL_SCANCODE_APOSTROPHE, + /* 25 */ SDL_SCANCODE_GRAVE, + /* 26 */ SDL_SCANCODE_COMMA, + /* 27 */ SDL_SCANCODE_PERIOD, + /* 28 */ SDL_SCANCODE_SLASH, + /* 29 */ SDL_SCANCODE_BACKSLASH, + /* 30 */ SDL_SCANCODE_A, + /* 31 */ SDL_SCANCODE_B, + /* 32 */ SDL_SCANCODE_C, + /* 33 */ SDL_SCANCODE_D, + /* 34 */ SDL_SCANCODE_E, + /* 35 */ SDL_SCANCODE_F, + /* 36 */ SDL_SCANCODE_G, + /* 37 */ SDL_SCANCODE_H, + /* 38 */ SDL_SCANCODE_I, + /* 39 */ SDL_SCANCODE_J, + /* 40 */ SDL_SCANCODE_K, + /* 41 */ SDL_SCANCODE_L, + /* 42 */ SDL_SCANCODE_M, + /* 43 */ SDL_SCANCODE_N, + /* 44 */ SDL_SCANCODE_O, + /* 45 */ SDL_SCANCODE_P, + /* 46 */ SDL_SCANCODE_Q, + /* 47 */ SDL_SCANCODE_R, + /* 48 */ SDL_SCANCODE_S, + /* 49 */ SDL_SCANCODE_T, + /* 50 */ SDL_SCANCODE_U, + /* 51 */ SDL_SCANCODE_V, + /* 52 */ SDL_SCANCODE_W, + /* 53 */ SDL_SCANCODE_X, + /* 54 */ SDL_SCANCODE_Y, + /* 55 */ SDL_SCANCODE_Z, + /* 56 */ SDL_SCANCODE_BACKSPACE, + /* 57 */ SDL_SCANCODE_RETURN, + /* 58 */ SDL_SCANCODE_TAB, + /* 59 */ SDL_SCANCODE_ESCAPE, + /* 60 */ SDL_SCANCODE_DELETE, + /* 61 */ SDL_SCANCODE_HOME, + /* 62 */ SDL_SCANCODE_END, + /* 63 */ SDL_SCANCODE_PAGEUP, + /* 64 */ SDL_SCANCODE_PAGEDOWN, + /* 65 */ SDL_SCANCODE_UP, + /* 66 */ SDL_SCANCODE_DOWN, + /* 67 */ SDL_SCANCODE_LEFT, + /* 68 */ SDL_SCANCODE_RIGHT, + /* 69 */ SDL_SCANCODE_F1, + /* 70 */ SDL_SCANCODE_F2, + /* 71 */ SDL_SCANCODE_F3, + /* 72 */ SDL_SCANCODE_F4, + /* 73 */ SDL_SCANCODE_F5, + /* 74 */ SDL_SCANCODE_F6, + /* 75 */ SDL_SCANCODE_F7, + /* 76 */ SDL_SCANCODE_F8, + /* 77 */ SDL_SCANCODE_F9, + /* 78 */ SDL_SCANCODE_F10, + /* 79 */ SDL_SCANCODE_F11, + /* 80 */ SDL_SCANCODE_F12, +}; + /* *INDENT-ON* */ diff --git a/Engine/lib/sdl/src/filesystem/dummy/SDL_sysfilesystem.c b/Engine/lib/sdl/src/filesystem/dummy/SDL_sysfilesystem.c index 45273f24a..2570f4c75 100644 --- a/Engine/lib/sdl/src/filesystem/dummy/SDL_sysfilesystem.c +++ b/Engine/lib/sdl/src/filesystem/dummy/SDL_sysfilesystem.c @@ -20,7 +20,7 @@ */ #include "../../SDL_internal.h" -#ifdef SDL_FILESYSTEM_DUMMY +#if defined(SDL_FILESYSTEM_DUMMY) || defined(SDL_FILESYSTEM_DISABLED) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ @@ -42,6 +42,6 @@ SDL_GetPrefPath(const char *org, const char *app) return NULL; } -#endif /* SDL_FILESYSTEM_DUMMY */ +#endif /* SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/filesystem/unix/SDL_sysfilesystem.c b/Engine/lib/sdl/src/filesystem/unix/SDL_sysfilesystem.c index fa034a456..bd2e84cd1 100644 --- a/Engine/lib/sdl/src/filesystem/unix/SDL_sysfilesystem.c +++ b/Engine/lib/sdl/src/filesystem/unix/SDL_sysfilesystem.c @@ -33,7 +33,7 @@ #include #include -#ifdef __FREEBSD__ +#if defined(__FREEBSD__) || defined(__OPENBSD__) #include #endif @@ -90,7 +90,26 @@ SDL_GetBasePath(void) return NULL; } } -#elif defined(__SOLARIS__) +#endif +#if defined(__OPENBSD__) + char **retvalargs; + size_t len; + const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; + if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) { + retvalargs = SDL_malloc(len); + if (!retvalargs) { + SDL_OutOfMemory(); + return NULL; + } + sysctl(mib, 4, retvalargs, &len, NULL, 0); + retval = SDL_malloc(PATH_MAX + 1); + if (retval) + realpath(retvalargs[0], retval); + + SDL_free(retvalargs); + } +#endif +#if defined(__SOLARIS__) const char *path = getexecname(); if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */ retval = SDL_strdup(path); diff --git a/Engine/lib/sdl/src/haptic/linux/SDL_syshaptic.c b/Engine/lib/sdl/src/haptic/linux/SDL_syshaptic.c index e8d785535..7bd966449 100644 --- a/Engine/lib/sdl/src/haptic/linux/SDL_syshaptic.c +++ b/Engine/lib/sdl/src/haptic/linux/SDL_syshaptic.c @@ -609,7 +609,7 @@ SDL_SYS_HapticQuit(void) /* Opened and not closed haptics are leaked, this is on purpose. * Close your haptic devices after usage. */ SDL_free(item->fname); - item->fname = NULL; + SDL_free(item); } #if SDL_USE_LIBUDEV @@ -690,7 +690,7 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src) else if (!src->dir[0]) *dest = (src->dir[1] >= 0 ? 0x8000 : 0); else { - float f = atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */ + float f = SDL_atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */ /* atan2 takes the parameters: Y-axis-value and X-axis-value (in that order) - Y-axis-value is the second coordinate (from center to SOUTH) diff --git a/Engine/lib/sdl/src/haptic/windows/SDL_dinputhaptic.c b/Engine/lib/sdl/src/haptic/windows/SDL_dinputhaptic.c index c51470dd5..c81432c26 100644 --- a/Engine/lib/sdl/src/haptic/windows/SDL_dinputhaptic.c +++ b/Engine/lib/sdl/src/haptic/windows/SDL_dinputhaptic.c @@ -325,20 +325,12 @@ SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device /* Set data format. */ ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device, - &c_dfDIJoystick2); + &SDL_c_dfDIJoystick2); if (FAILED(ret)) { DI_SetError("Setting data format", ret); goto acquire_err; } - /* Get number of axes. */ - ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device, - DI_DeviceObjectCallback, - haptic, DIDFT_AXIS); - if (FAILED(ret)) { - DI_SetError("Getting device axes", ret); - goto acquire_err; - } /* Acquire the device. */ ret = IDirectInputDevice8_Acquire(haptic->hwdata->device); @@ -348,6 +340,15 @@ SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device } } + /* Get number of axes. */ + ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device, + DI_DeviceObjectCallback, + haptic, DIDFT_AXIS); + if (FAILED(ret)) { + DI_SetError("Getting device axes", ret); + goto acquire_err; + } + /* Reset all actuators - just in case. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_RESET); diff --git a/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic.c b/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic.c index 0c038fb1b..c6bcba1f3 100644 --- a/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic.c +++ b/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic.c @@ -255,7 +255,7 @@ SDL_SYS_HapticQuit(void) for (hapticitem = SDL_haptics; hapticitem; hapticitem = hapticitem->next) { if ((hapticitem->hwdata->bXInputHaptic) && (hapticitem->hwdata->thread)) { /* we _have_ to stop the thread before we free the XInput DLL! */ - hapticitem->hwdata->stopThread = 1; + SDL_AtomicSet(&hapticitem->hwdata->stopThread, 1); SDL_WaitThread(hapticitem->hwdata->thread, NULL); hapticitem->hwdata->thread = NULL; } diff --git a/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic_c.h b/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic_c.h index 89fdd2cb9..f34426442 100644 --- a/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic_c.h +++ b/Engine/lib/sdl/src/haptic/windows/SDL_windowshaptic_c.h @@ -42,8 +42,8 @@ struct haptic_hwdata Uint8 userid; /* XInput userid index for this joystick */ SDL_Thread *thread; SDL_mutex *mutex; - volatile Uint32 stopTicks; - volatile int stopThread; + Uint32 stopTicks; + SDL_atomic_t stopThread; }; diff --git a/Engine/lib/sdl/src/haptic/windows/SDL_xinputhaptic.c b/Engine/lib/sdl/src/haptic/windows/SDL_xinputhaptic.c index a46ae5f97..afbab456a 100644 --- a/Engine/lib/sdl/src/haptic/windows/SDL_xinputhaptic.c +++ b/Engine/lib/sdl/src/haptic/windows/SDL_xinputhaptic.c @@ -33,6 +33,7 @@ #include "SDL_xinputhaptic_c.h" #include "../../core/windows/SDL_xinput.h" #include "../../joystick/windows/SDL_windowsjoystick_c.h" +#include "../../thread/SDL_systhread.h" /* * Internal stuff. @@ -43,8 +44,7 @@ static SDL_bool loaded_xinput = SDL_FALSE; int SDL_XINPUT_HapticInit(void) { - const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED); - if (!env || SDL_atoi(env)) { + if (SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE)) { loaded_xinput = (WIN_LoadXInputDLL() == 0); } @@ -146,7 +146,7 @@ SDL_RunXInputHaptic(void *arg) { struct haptic_hwdata *hwdata = (struct haptic_hwdata *) arg; - while (!hwdata->stopThread) { + while (!SDL_AtomicGet(&hwdata->stopThread)) { SDL_Delay(50); SDL_LockMutex(hwdata->mutex); /* If we're currently running and need to stop... */ @@ -205,17 +205,8 @@ SDL_XINPUT_HapticOpenFromUserIndex(SDL_Haptic *haptic, const Uint8 userid) } SDL_snprintf(threadName, sizeof(threadName), "SDLXInputDev%d", (int)userid); + haptic->hwdata->thread = SDL_CreateThreadInternal(SDL_RunXInputHaptic, threadName, 64 * 1024, haptic->hwdata); -#if defined(__WIN32__) && !defined(HAVE_LIBC) /* !!! FIXME: this is nasty. */ -#undef SDL_CreateThread -#if SDL_DYNAMIC_API - haptic->hwdata->thread = SDL_CreateThread_REAL(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL); -#else - haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata, NULL, NULL); -#endif -#else - haptic->hwdata->thread = SDL_CreateThread(SDL_RunXInputHaptic, threadName, haptic->hwdata); -#endif if (haptic->hwdata->thread == NULL) { SDL_DestroyMutex(haptic->hwdata->mutex); SDL_free(haptic->effects); @@ -261,7 +252,7 @@ SDL_XINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) void SDL_XINPUT_HapticClose(SDL_Haptic * haptic) { - haptic->hwdata->stopThread = 1; + SDL_AtomicSet(&haptic->hwdata->stopThread, 1); SDL_WaitThread(haptic->hwdata->thread, NULL); SDL_DestroyMutex(haptic->hwdata->mutex); } diff --git a/Engine/lib/sdl/src/joystick/SDL_gamecontroller.c b/Engine/lib/sdl/src/joystick/SDL_gamecontroller.c index 0fd1ef4a7..1d3a4c203 100644 --- a/Engine/lib/sdl/src/joystick/SDL_gamecontroller.c +++ b/Engine/lib/sdl/src/joystick/SDL_gamecontroller.c @@ -45,7 +45,8 @@ struct _SDL_HatMapping Uint8 mask; }; -#define k_nMaxReverseEntries 20 +/* We need 36 entries for Android (as of SDL v2.0.4) */ +#define k_nMaxReverseEntries 48 /** * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask @@ -105,6 +106,35 @@ struct _SDL_GameController int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value); int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state); +/* + * If there is an existing add event in the queue, it needs to be modified + * to have the right value for which, because the number of controllers in + * the system is now one less. + */ +static void UpdateEventsForDeviceRemoval() +{ + int i, num_events; + SDL_Event *events; + + num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); + if (num_events <= 0) { + return; + } + + events = SDL_stack_alloc(SDL_Event, num_events); + if (!events) { + return; + } + + num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEADDED); + for (i = 0; i < num_events; ++i) { + --events[i].cdevice.which; + } + SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); + + SDL_stack_free(events); +} + /* * Event filter to fire controller events from joystick ones */ @@ -115,7 +145,11 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) { SDL_GameController *controllerlist; - if (event->jaxis.axis >= k_nMaxReverseEntries) break; + if (event->jaxis.axis >= k_nMaxReverseEntries) + { + SDL_SetError("SDL_GameControllerEventWatcher: Axis index %d too large, ignoring motion", (int)event->jaxis.axis); + break; + } controllerlist = SDL_gamecontrollers; while (controllerlist) { @@ -126,8 +160,8 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) switch (axis) { case SDL_CONTROLLER_AXIS_TRIGGERLEFT: case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - /* Shift it to be 0 - 32767. */ value = value / 2 + 16384; + break; default: break; } @@ -146,7 +180,11 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) { SDL_GameController *controllerlist; - if (event->jbutton.button >= k_nMaxReverseEntries) break; + if (event->jbutton.button >= k_nMaxReverseEntries) + { + SDL_SetError("SDL_GameControllerEventWatcher: Button index %d too large, ignoring update", (int)event->jbutton.button); + break; + } controllerlist = SDL_gamecontrollers; while (controllerlist) { @@ -223,9 +261,12 @@ int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event) while (controllerlist) { if (controllerlist->joystick->instance_id == event->jdevice.which) { SDL_Event deviceevent; + deviceevent.type = SDL_CONTROLLERDEVICEREMOVED; deviceevent.cdevice.which = event->jdevice.which; SDL_PushEvent(&deviceevent); + + UpdateEventsForDeviceRemoval(); break; } controllerlist = controllerlist->next; @@ -861,7 +902,6 @@ SDL_GameControllerInit(void) { int i = 0; const char *pMappingString = NULL; - s_pSupportedControllers = NULL; pMappingString = s_ControllerMappings[i]; while (pMappingString) { SDL_GameControllerAddMapping(pMappingString); @@ -971,6 +1011,20 @@ SDL_GameControllerOpen(int device_index) SDL_PrivateLoadButtonMapping(&gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping); + /* The triggers are mapped from -32768 to 32767, where -32768 is the 'unpressed' value */ + { + int leftTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERLEFT]; + int rightTriggerMapping = gamecontroller->mapping.axes[SDL_CONTROLLER_AXIS_TRIGGERRIGHT]; + if (leftTriggerMapping >= 0) { + gamecontroller->joystick->axes[leftTriggerMapping] = + gamecontroller->joystick->axes_zero[leftTriggerMapping] = (Sint16)-32768; + } + if (rightTriggerMapping >= 0) { + gamecontroller->joystick->axes[rightTriggerMapping] = + gamecontroller->joystick->axes_zero[rightTriggerMapping] = (Sint16)-32768; + } + } + /* Add joystick to list */ ++gamecontroller->ref_count; /* Link the joystick in the list */ @@ -1007,7 +1061,7 @@ SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControlle switch (axis) { case SDL_CONTROLLER_AXIS_TRIGGERLEFT: case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - /* Shift it to be 0 - 32767. */ + /* Shift it to be 0 - 32767 */ value = value / 2 + 16384; default: break; diff --git a/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h b/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h index 211d00d01..1e623cbb8 100644 --- a/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h +++ b/Engine/lib/sdl/src/joystick/SDL_gamecontrollerdb.h @@ -35,6 +35,7 @@ static const char *s_ControllerMappings [] = "xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", #endif #if SDL_JOYSTICK_DINPUT + "10280900000000000000504944564944,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,", "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,", "e8206058000000000000504944564944,Cideko AK08b,a:b2,b:b1,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:b3,y:b0,", "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,", @@ -48,6 +49,7 @@ static const char *s_ControllerMappings [] = "4c05c405000000000000504944564944,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,", #endif #if defined(__MACOSX__) + "10280000000000000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,", "830500000000000031b0000000000000,Cideko AK08b,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,", "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. */ @@ -56,11 +58,14 @@ static const char *s_ControllerMappings [] = "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,", "4c05000000000000c405000000000000,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,", + "351200000000000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,", "11010000000000002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,", "11010000000000001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,", "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,", #endif #if defined(__LINUX__) + "05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,", + "03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,", "03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,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:b3,y:b0,", "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,", "030000006f0e00000104000000010000,Gamestop Logic3 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,", @@ -71,6 +76,12 @@ static const char *s_ControllerMappings [] = "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", + "03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,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,", "050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,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,", @@ -78,12 +89,15 @@ static const char *s_ControllerMappings [] = "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,", + "030000004c050000cc09000011010000,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,", + "050000004c050000cc09000000010000,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,", "03000000c6240000045d000025010000,Razer Sabertooth,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,", "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,", "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,", + "050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,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__) diff --git a/Engine/lib/sdl/src/joystick/SDL_joystick.c b/Engine/lib/sdl/src/joystick/SDL_joystick.c index dc910a82b..c426a39e5 100644 --- a/Engine/lib/sdl/src/joystick/SDL_joystick.c +++ b/Engine/lib/sdl/src/joystick/SDL_joystick.c @@ -142,8 +142,8 @@ SDL_JoystickOpen(int device_index) joystick->name = NULL; if (joystick->naxes > 0) { - joystick->axes = (Sint16 *) SDL_malloc - (joystick->naxes * sizeof(Sint16)); + joystick->axes = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16)); + joystick->axes_zero = (Sint16 *) SDL_malloc(joystick->naxes * sizeof(Sint16)); } if (joystick->nhats > 0) { joystick->hats = (Uint8 *) SDL_malloc @@ -167,6 +167,7 @@ SDL_JoystickOpen(int device_index) } if (joystick->axes) { SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16)); + SDL_memset(joystick->axes_zero, 0, joystick->naxes * sizeof(Sint16)); } if (joystick->hats) { SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8)); @@ -497,6 +498,71 @@ SDL_PrivateJoystickShouldIgnoreEvent() /* These are global for SDL_sysjoystick.c and SDL_events.c */ +void SDL_PrivateJoystickAdded(int device_index) +{ +#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 there is an existing add event in the queue, it needs to be modified + * to have the right value for which, because the number of controllers in + * the system is now one less. + */ +static void UpdateEventsForDeviceRemoval() +{ + int i, num_events; + SDL_Event *events; + + num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED); + if (num_events <= 0) { + return; + } + + events = SDL_stack_alloc(SDL_Event, num_events); + if (!events) { + return; + } + + num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED); + for (i = 0; i < num_events; ++i) { + --events[i].jdevice.which; + } + SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0); + + SDL_stack_free(events); +} + +void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance) +{ +#if !SDL_EVENTS_DISABLED + SDL_Event event; + + event.type = SDL_JOYDEVICEREMOVED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = device_instance; + if ( (SDL_EventOK == NULL) || + (*SDL_EventOK) (SDL_EventOKParam, &event) ) { + SDL_PushEvent(&event); + } + } + + UpdateEventsForDeviceRemoval(); +#endif /* !SDL_EVENTS_DISABLED */ +} + int SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value) { @@ -514,8 +580,8 @@ SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value) * events. */ if (SDL_PrivateJoystickShouldIgnoreEvent()) { - if ((value > 0 && value >= joystick->axes[axis]) || - (value < 0 && value <= joystick->axes[axis])) { + if ((value > joystick->axes_zero[axis] && value >= joystick->axes[axis]) || + (value < joystick->axes_zero[axis] && value <= joystick->axes[axis])) { return 0; } } @@ -688,7 +754,7 @@ SDL_JoystickUpdate(void) /* Tell the app that everything is centered/unpressed... */ for (i = 0; i < joystick->naxes; i++) { - SDL_PrivateJoystickAxis(joystick, i, 0); + SDL_PrivateJoystickAxis(joystick, i, joystick->axes_zero[i]); } for (i = 0; i < joystick->nbuttons; i++) { diff --git a/Engine/lib/sdl/src/joystick/SDL_joystick_c.h b/Engine/lib/sdl/src/joystick/SDL_joystick_c.h index 4a076f6d6..cb9c92544 100644 --- a/Engine/lib/sdl/src/joystick/SDL_joystick_c.h +++ b/Engine/lib/sdl/src/joystick/SDL_joystick_c.h @@ -33,6 +33,8 @@ extern void SDL_GameControllerQuit(void); /* Internal event queueing functions */ +extern void SDL_PrivateJoystickAdded(int device_index); +extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance); extern int SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value); extern int SDL_PrivateJoystickBall(SDL_Joystick * joystick, @@ -41,8 +43,8 @@ extern int SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value); extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state); -extern void SDL_PrivateJoystickBatteryLevel( SDL_Joystick * joystick, - SDL_JoystickPowerLevel ePowerLevel ); +extern void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, + SDL_JoystickPowerLevel ePowerLevel); /* Internal sanity checking functions */ extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick); diff --git a/Engine/lib/sdl/src/joystick/SDL_sysjoystick.h b/Engine/lib/sdl/src/joystick/SDL_sysjoystick.h index 1015840af..f4cad05ec 100644 --- a/Engine/lib/sdl/src/joystick/SDL_sysjoystick.h +++ b/Engine/lib/sdl/src/joystick/SDL_sysjoystick.h @@ -36,6 +36,7 @@ struct _SDL_Joystick int naxes; /* Number of axis controls on the joystick */ Sint16 *axes; /* Current axis states */ + Sint16 *axes_zero; /* Zero point on the axis (-32768 for triggers) */ int nhats; /* Number of hats on the joystick */ Uint8 *hats; /* Current hat states */ diff --git a/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick.c index 8656a5322..a09e9a12c 100644 --- a/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick.c @@ -27,10 +27,6 @@ #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" @@ -191,8 +187,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 +203,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; @@ -252,9 +248,6 @@ Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, { SDL_JoystickGUID guid; SDL_joylist_item *item; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif if(JoystickByDeviceId(device_id) != NULL || name == NULL) { return -1; @@ -299,17 +292,7 @@ Android_AddJoystick(int device_id, const char *name, SDL_bool is_accelerometer, /* Need to increment the joystick count before we post the event */ ++numjoysticks; -#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 */ + SDL_PrivateJoystickAdded(numjoysticks - 1); #ifdef DEBUG_JOYSTICK SDL_Log("Added joystick %s with device_id %d", name, device_id); @@ -323,9 +306,6 @@ Android_RemoveJoystick(int device_id) { SDL_joylist_item *item = SDL_joylist; SDL_joylist_item *prev = NULL; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif /* Don't call JoystickByDeviceId here or there'll be an infinite loop! */ while (item != NULL) { @@ -340,7 +320,6 @@ Android_RemoveJoystick(int device_id) return -1; } - const int retval = item->device_instance; if (item->joystick) { item->joystick->hwdata = NULL; } @@ -358,17 +337,7 @@ Android_RemoveJoystick(int device_id) /* 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 */ + SDL_PrivateJoystickRemoved(item->device_instance); #ifdef DEBUG_JOYSTICK SDL_Log("Removed joystick with device_id %d", device_id); @@ -376,18 +345,16 @@ Android_RemoveJoystick(int device_id) SDL_free(item->name); SDL_free(item); - return retval; + return numjoysticks; } int SDL_SYS_JoystickInit(void) { - const char *hint; SDL_SYS_JoystickDetect(); - hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK); - if (!hint || SDL_atoi(hint)) { + if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) { /* Default behavior, accelerometer as joystick */ Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0); } @@ -539,6 +506,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { + SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; + if (item) { + item->joystick = NULL; + } } /* Function to perform any system-specific joystick related cleanup */ diff --git a/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick_c.h b/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick_c.h index 49b494c54..51803db35 100644 --- a/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick_c.h +++ b/Engine/lib/sdl/src/joystick/android/SDL_sysjoystick_c.h @@ -1,23 +1,23 @@ /* - Simple DirectMedia Layer - Copyright (C) 1997-2016 Sam Lantinga - - 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. - */ + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" diff --git a/Engine/lib/sdl/src/joystick/bsd/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/bsd/SDL_sysjoystick.c index 509d43f75..ddc899f6e 100644 --- a/Engine/lib/sdl/src/joystick/bsd/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/bsd/SDL_sysjoystick.c @@ -179,7 +179,7 @@ SDL_SYS_JoystickInit(void) SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i); - joynames[SDL_SYS_numjoysticks] = strdup(s); + joynames[SDL_SYS_numjoysticks] = SDL_strdup(s); if (SDL_SYS_JoystickOpen(&nj, SDL_SYS_numjoysticks) == 0) { SDL_SYS_JoystickClose(&nj); @@ -193,7 +193,7 @@ SDL_SYS_JoystickInit(void) SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i); fd = open(s, O_RDONLY); if (fd != -1) { - joynames[SDL_SYS_numjoysticks++] = strdup(s); + joynames[SDL_SYS_numjoysticks++] = SDL_strdup(s); close(fd); } } @@ -304,14 +304,14 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index) } joy->hwdata = hw; hw->fd = fd; - hw->path = strdup(path); + hw->path = SDL_strdup(path); if (!SDL_strncmp(path, "/dev/joy", 8)) { hw->type = BSDJOY_JOY; joy->naxes = 2; joy->nbuttons = 2; joy->nhats = 0; joy->nballs = 0; - joydevnames[device_index] = strdup("Gameport joystick"); + joydevnames[device_index] = SDL_strdup("Gameport joystick"); goto usbend; } else { hw->type = BSDJOY_UHID; @@ -363,7 +363,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index) str[i] = '\0'; asprintf(&new_name, "%s @ %s", str, path); if (new_name != NULL) { - free(joydevnames[SDL_SYS_numjoysticks]); + SDL_free(joydevnames[SDL_SYS_numjoysticks]); joydevnames[SDL_SYS_numjoysticks] = new_name; } } diff --git a/Engine/lib/sdl/src/joystick/darwin/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/darwin/SDL_sysjoystick.c index 6dd306aa8..da10fbac5 100644 --- a/Engine/lib/sdl/src/joystick/darwin/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/darwin/SDL_sysjoystick.c @@ -34,9 +34,6 @@ #include "SDL_sysjoystick_c.h" #include "SDL_events.h" #include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */ -#if !SDL_EVENTS_DISABLED -#include "../../events/SDL_events_c.h" -#endif #define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick") @@ -154,21 +151,7 @@ JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender) MacHaptic_MaybeRemoveDevice(device->ffservice); #endif -/* !!! 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 */ + SDL_PrivateJoystickRemoved(device->instance_id); } @@ -249,6 +232,7 @@ AddHIDElement(const void *value, void *parameter) case kHIDUsage_GD_DPadLeft: case kHIDUsage_GD_Start: case kHIDUsage_GD_Select: + case kHIDUsage_GD_SystemMainMenu: if (!ElementAlreadyAdded(cookie, pDevice->firstButton)) { element = (recElement *) SDL_calloc(1, sizeof (recElement)); if (element) { @@ -422,6 +406,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic { recDevice *device; int device_index = 0; + io_service_t ioservice; if (res != kIOReturnSuccess) { return; @@ -451,20 +436,11 @@ 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); + ioservice = IOHIDDeviceGetService(ioHIDDeviceObject); #if SDL_HAPTIC_IOKIT - if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { - device->ffservice = ioservice; - MacHaptic_MaybeAddDevice(ioservice); - } -#endif - -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) { + device->ffservice = ioservice; + MacHaptic_MaybeAddDevice(ioservice); } #endif @@ -483,21 +459,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic ++device_index; /* bump by one since we counted by pNext. */ } -/* !!! 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 */ + SDL_PrivateJoystickAdded(device_index); } static SDL_bool diff --git a/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick.c index e0c5833bf..6b203667a 100644 --- a/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick.c @@ -27,10 +27,6 @@ #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" @@ -57,10 +53,6 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa 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; @@ -105,20 +97,12 @@ Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepa } ++numjoysticks; + + SDL_PrivateJoystickAdded(numjoysticks - 1); + #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); @@ -132,9 +116,6 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam { 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) { @@ -165,17 +146,7 @@ Emscripten_JoyStickDisconnected(int eventType, const EmscriptenGamepadEvent *gam /* 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 */ + SDL_PrivateJoystickRemoved(item->device_instance); #ifdef DEBUG_JOYSTICK SDL_Log("Removed joystick with id %d", item->device_instance); @@ -377,6 +348,10 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { + SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; + if (item) { + item->joystick = NULL; + } } /* Function to perform any system-specific joystick related cleanup */ diff --git a/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick_c.h b/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick_c.h index c7103c56a..41f613e11 100644 --- a/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick_c.h +++ b/Engine/lib/sdl/src/joystick/emscripten/SDL_sysjoystick_c.h @@ -1,23 +1,23 @@ /* - Simple DirectMedia Layer - Copyright (C) 1997-2016 Sam Lantinga + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga - 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. + 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: + 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. - */ + 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" diff --git a/Engine/lib/sdl/src/joystick/haiku/SDL_haikujoystick.cc b/Engine/lib/sdl/src/joystick/haiku/SDL_haikujoystick.cc index 3ec9ae107..a680189c7 100644 --- a/Engine/lib/sdl/src/joystick/haiku/SDL_haikujoystick.cc +++ b/Engine/lib/sdl/src/joystick/haiku/SDL_haikujoystick.cc @@ -74,8 +74,8 @@ extern "C" if (joystick.Open(name) != B_ERROR) { BString stick_name; joystick.GetControllerName(&stick_name); - SDL_joyport[SDL_SYS_numjoysticks] = strdup(name); - SDL_joyname[SDL_SYS_numjoysticks] = strdup(stick_name.String()); + SDL_joyport[SDL_SYS_numjoysticks] = SDL_strdup(name); + SDL_joyname[SDL_SYS_numjoysticks] = SDL_strdup(stick_name.String()); SDL_SYS_numjoysticks++; joystick.Close(); } diff --git a/Engine/lib/sdl/src/joystick/iphoneos/SDL_sysjoystick.m b/Engine/lib/sdl/src/joystick/iphoneos/SDL_sysjoystick.m index c8a42af05..eb7e00032 100644 --- a/Engine/lib/sdl/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/Engine/lib/sdl/src/joystick/iphoneos/SDL_sysjoystick.m @@ -26,6 +26,7 @@ /* needed for SDL_IPHONE_MAX_GFORCE macro */ #include "SDL_config_iphoneos.h" +#include "SDL_events.h" #include "SDL_joystick.h" #include "SDL_hints.h" #include "SDL_stdinc.h" @@ -36,7 +37,9 @@ #include "../../events/SDL_events_c.h" #endif +#if !TARGET_OS_TV #import +#endif #ifdef SDL_JOYSTICK_MFI #import @@ -45,8 +48,10 @@ static id connectObserver = nil; static id disconnectObserver = nil; #endif /* SDL_JOYSTICK_MFI */ +#if !TARGET_OS_TV static const char *accelerometerName = "iOS Accelerometer"; static CMMotionManager *motionManager = nil; +#endif /* !TARGET_OS_TV */ static SDL_JoystickDeviceItem *deviceList = NULL; @@ -105,6 +110,11 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr } else if (controller.gamepad) { device->guid.data[10] = 2; } +#if TARGET_OS_TV + else if (controller.microGamepad) { + device->guid.data[10] = 3; + } +#endif /* TARGET_OS_TV */ if (controller.extendedGamepad) { device->naxes = 6; /* 2 thumbsticks and 2 triggers */ @@ -115,21 +125,27 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr device->nhats = 1; /* d-pad */ device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */ } - /* TODO: Handle micro profiles on tvOS. */ +#if TARGET_OS_TV + else if (controller.microGamepad) { + device->naxes = 2; /* treat the touch surface as two axes */ + device->nhats = 0; /* apparently the touch surface-as-dpad is buggy */ + device->nbuttons = 3; /* AX, pause button */ + + controller.microGamepad.allowsRotation = SDL_GetHintBoolean(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, SDL_FALSE); + } +#endif /* TARGET_OS_TV */ /* This will be set when the first button press of the controller is * detected. */ controller.playerIndex = -1; -#endif + +#endif /* SDL_JOYSTICK_MFI */ } static void SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) { SDL_JoystickDeviceItem *device = deviceList; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif while (device != NULL) { if (device->controller == controller) { @@ -149,6 +165,10 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) device->instance_id = instancecounter++; if (accelerometer) { +#if TARGET_OS_TV + SDL_free(device); + return; +#else device->name = SDL_strdup(accelerometerName); device->naxes = 3; /* Device acceleration in the x, y, and z axes. */ device->nhats = 0; @@ -156,6 +176,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) /* Use the accelerometer name as a GUID. */ SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name))); +#endif /* TARGET_OS_TV */ } else if (controller) { SDL_SYS_AddMFIJoystickDevice(device, controller); } @@ -172,17 +193,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) ++numjoysticks; -#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 */ + SDL_PrivateJoystickAdded(numjoysticks - 1); } static SDL_JoystickDeviceItem * @@ -191,9 +202,6 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device) SDL_JoystickDeviceItem *prev = NULL; SDL_JoystickDeviceItem *next = NULL; SDL_JoystickDeviceItem *item = deviceList; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif if (device == NULL) { return NULL; @@ -234,17 +242,7 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device) --numjoysticks; -#if !SDL_EVENTS_DISABLED - 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 */ + SDL_PrivateJoystickRemoved(device->instance_id); SDL_free(device->name); SDL_free(device); @@ -252,6 +250,22 @@ SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device) return next; } +#if TARGET_OS_TV +static void +SDL_AppleTVRemoteRotationHintChanged(void *udata, const char *name, const char *oldValue, const char *newValue) +{ + BOOL allowRotation = newValue != NULL && *newValue != '0'; + + @autoreleasepool { + for (GCController *controller in [GCController controllers]) { + if (controller.microGamepad) { + controller.microGamepad.allowsRotation = allowRotation; + } + } + } +} +#endif /* TARGET_OS_TV */ + /* Function to scan the system for joysticks. * Joystick 0 should be the system default joystick. * It should return 0, or -1 on an unrecoverable fatal error. @@ -261,12 +275,13 @@ SDL_SYS_JoystickInit(void) { @autoreleasepool { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK); - if (!hint || SDL_atoi(hint)) { +#if !TARGET_OS_TV + if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) { /* Default behavior, accelerometer as joystick */ SDL_SYS_AddJoystickDevice(nil, SDL_TRUE); } +#endif /* !TARGET_OS_TV */ #ifdef SDL_JOYSTICK_MFI /* GameController.framework was added in iOS 7. */ @@ -278,6 +293,11 @@ SDL_SYS_JoystickInit(void) SDL_SYS_AddJoystickDevice(controller, SDL_FALSE); } +#if TARGET_OS_TV + SDL_AddHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, + SDL_AppleTVRemoteRotationHintChanged, NULL); +#endif /* TARGET_OS_TV */ + connectObserver = [center addObserverForName:GCControllerDidConnectNotification object:nil queue:nil @@ -355,6 +375,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) @autoreleasepool { if (device->accelerometer) { +#if !TARGET_OS_TV if (motionManager == nil) { motionManager = [[CMMotionManager alloc] init]; } @@ -362,6 +383,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) /* Shorter times between updates can significantly increase CPU usage. */ motionManager.accelerometerUpdateInterval = 0.1; [motionManager startAccelerometerUpdates]; +#endif /* !TARGET_OS_TV */ } else { #ifdef SDL_JOYSTICK_MFI GCController *controller = device->controller; @@ -387,6 +409,7 @@ SDL_SYS_JoystickAttached(SDL_Joystick *joystick) static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) { +#if !TARGET_OS_TV const float maxgforce = SDL_IPHONE_MAX_GFORCE; const SInt16 maxsint16 = 0x7FFF; CMAcceleration accel; @@ -424,6 +447,7 @@ SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16); SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16); SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16); +#endif /* !TARGET_OS_TV */ } #ifdef SDL_JOYSTICK_MFI @@ -455,7 +479,7 @@ SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad) static void SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick) { -#ifdef SDL_JOYSTICK_MFI +#if SDL_JOYSTICK_MFI @autoreleasepool { GCController *controller = joystick->hwdata->controller; Uint8 hatstate = SDL_HAT_CENTERED; @@ -517,7 +541,36 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickButton(joystick, i, buttons[i]); } } - /* TODO: Handle micro profiles on tvOS. */ +#if TARGET_OS_TV + else if (controller.microGamepad) { + GCMicroGamepad *gamepad = controller.microGamepad; + + Sint16 axes[] = { + (Sint16) (gamepad.dpad.xAxis.value * 32767), + (Sint16) (gamepad.dpad.yAxis.value * -32767), + }; + + for (i = 0; i < SDL_arraysize(axes); i++) { + updateplayerindex |= (joystick->axes[i] != axes[i]); + SDL_PrivateJoystickAxis(joystick, i, axes[i]); + } + + /* Apparently the dpad values are not accurate enough to be useful. */ + /* hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); */ + + Uint8 buttons[] = { + gamepad.buttonA.isPressed, + gamepad.buttonX.isPressed, + }; + + for (i = 0; i < SDL_arraysize(buttons); i++) { + updateplayerindex |= (joystick->buttons[i] != buttons[i]); + SDL_PrivateJoystickButton(joystick, i, buttons[i]); + } + + /* TODO: Figure out what to do with reportsAbsoluteDpadValues */ + } +#endif /* TARGET_OS_TV */ if (joystick->nhats > 0) { updateplayerindex |= (joystick->hats[0] != hatstate); @@ -557,7 +610,7 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick) } } } -#endif +#endif /* SDL_JOYSTICK_MFI */ } /* Function to update the state of a joystick - called as a device poll. @@ -595,7 +648,9 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick) @autoreleasepool { if (device->accelerometer) { +#if !TARGET_OS_TV [motionManager stopAccelerometerUpdates]; +#endif /* !TARGET_OS_TV */ } else if (device->controller) { #ifdef SDL_JOYSTICK_MFI GCController *controller = device->controller; @@ -623,13 +678,20 @@ SDL_SYS_JoystickQuit(void) [center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil]; disconnectObserver = nil; } + +#if TARGET_OS_TV + SDL_DelHintCallback(SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION, + SDL_AppleTVRemoteRotationHintChanged, NULL); +#endif /* TARGET_OS_TV */ #endif /* SDL_JOYSTICK_MFI */ while (deviceList != NULL) { SDL_SYS_RemoveJoystickDevice(deviceList); } +#if !TARGET_OS_TV motionManager = nil; +#endif /* !TARGET_OS_TV */ } numjoysticks = 0; diff --git a/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c index 8c73859ea..bd52b1808 100644 --- a/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/linux/SDL_sysjoystick.c @@ -42,11 +42,6 @@ #include "../SDL_joystick_c.h" #include "SDL_sysjoystick_c.h" -/* !!! FIXME: move this somewhere else. */ -#if !SDL_EVENTS_DISABLED -#include "../../events/SDL_events_c.h" -#endif - /* This isn't defined in older Linux kernel headers */ #ifndef SYN_DROPPED #define SYN_DROPPED 3 @@ -176,9 +171,6 @@ MaybeAddDevice(const char *path) char namebuf[128]; SDL_JoystickGUID guid; SDL_joylist_item *item; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif if (path == NULL) { return -1; @@ -239,18 +231,7 @@ MaybeAddDevice(const char *path) /* Need to increment the joystick count before we post the event */ ++numjoysticks; - /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */ -#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 */ + SDL_PrivateJoystickAdded(numjoysticks - 1); return numjoysticks; } @@ -262,9 +243,6 @@ MaybeRemoveDevice(const char *path) { SDL_joylist_item *item; SDL_joylist_item *prev = NULL; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif if (path == NULL) { return -1; @@ -290,18 +268,7 @@ MaybeRemoveDevice(const char *path) /* Need to decrement the joystick count before we post the event */ --numjoysticks; - /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */ -#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 */ + SDL_PrivateJoystickRemoved(item->device_instance); SDL_free(item->path); SDL_free(item->name); diff --git a/Engine/lib/sdl/src/joystick/psp/SDL_sysjoystick.c b/Engine/lib/sdl/src/joystick/psp/SDL_sysjoystick.c index e5247254f..352960edf 100644 --- a/Engine/lib/sdl/src/joystick/psp/SDL_sysjoystick.c +++ b/Engine/lib/sdl/src/joystick/psp/SDL_sysjoystick.c @@ -34,9 +34,9 @@ #include "SDL_events.h" #include "SDL_error.h" -#include "SDL_thread.h" #include "SDL_mutex.h" #include "SDL_timer.h" +#include "../../thread/SDL_systhread.h" /* Current pad state */ static SceCtrlData pad = { .Lx = 0, .Ly = 0, .Buttons = 0 }; @@ -116,7 +116,7 @@ int SDL_SYS_JoystickInit(void) return SDL_SetError("Can't create input semaphore"); } running = 1; - if((thread = SDL_CreateThread(JoystickUpdate, "JoySitckThread",NULL)) == NULL) { + if((thread = SDL_CreateThreadInternal(JoystickUpdate, "JoystickThread", 4096, NULL)) == NULL) { return SDL_SetError("Can't create input thread"); } diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_dinputjoystick.c b/Engine/lib/sdl/src/joystick/windows/SDL_dinputjoystick.c index f6b0cc88d..7166075b1 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_dinputjoystick.c +++ b/Engine/lib/sdl/src/joystick/windows/SDL_dinputjoystick.c @@ -214,7 +214,7 @@ static DIOBJECTDATAFORMAT dfDIJoystick2[] = { { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, }; -const DIDATAFORMAT c_dfDIJoystick2 = { +const DIDATAFORMAT SDL_c_dfDIJoystick2 = { sizeof(DIDATAFORMAT), sizeof(DIOBJECTDATAFORMAT), DIDF_ABSAXIS, @@ -240,11 +240,23 @@ SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput) static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; + static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } }; static const GUID *s_XInputProductGUID[] = { &IID_ValveStreamingGamepad, - &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */ - &IID_X360WirelessGamepad /* Microsoft's wireless X360 controller for Windows. */ + &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */ + &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */ + &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */ + &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */ + &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */ + &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */ + &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */ + &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */ }; size_t iDevice; @@ -582,7 +594,7 @@ SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde /* Use the extended data structure: DIJOYSTATE2. */ result = IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice, - &c_dfDIJoystick2); + &SDL_c_dfDIJoystick2); if (FAILED(result)) { return SetDIerror("IDirectInputDevice8::SetDataFormat", result); } diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick.c b/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick.c index 7123c6151..e528afa7f 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick.c +++ b/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick.c @@ -35,16 +35,13 @@ #include "SDL_error.h" #include "SDL_assert.h" #include "SDL_events.h" -#include "SDL_thread.h" #include "SDL_timer.h" #include "SDL_mutex.h" #include "SDL_events.h" #include "SDL_hints.h" #include "SDL_joystick.h" #include "../SDL_sysjoystick.h" -#if !SDL_EVENTS_DISABLED -#include "../../events/SDL_events_c.h" -#endif +#include "../../thread/SDL_systhread.h" #include "../../core/windows/SDL_windows.h" #if !defined(__WINRT__) #include @@ -301,18 +298,9 @@ SDL_SYS_JoystickInit(void) SDL_SYS_JoystickDetect(); if (!s_threadJoystick) { - s_bJoystickThreadQuit = SDL_FALSE; /* spin up the thread to detect hotplug of devices */ -#if defined(__WIN32__) && !defined(HAVE_LIBC) -#undef SDL_CreateThread -#if SDL_DYNAMIC_API - s_threadJoystick= SDL_CreateThread_REAL(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL); -#else - s_threadJoystick= SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL); -#endif -#else - s_threadJoystick = SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL); -#endif + s_bJoystickThreadQuit = SDL_FALSE; + s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL); } return SDL_SYS_NumJoysticks(); } @@ -336,9 +324,6 @@ void SDL_SYS_JoystickDetect() { JoyStick_DeviceData *pCurList = NULL; -#if !SDL_EVENTS_DISABLED - SDL_Event event; -#endif /* only enum the devices if the joystick thread told us something changed */ if (!s_bDeviceAdded && !s_bDeviceRemoved) { @@ -370,17 +355,7 @@ SDL_SYS_JoystickDetect() SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice); } -#if !SDL_EVENTS_DISABLED - SDL_zero(event); - event.type = SDL_JOYDEVICEREMOVED; - - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = pCurList->nInstanceID; - if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { - SDL_PushEvent(&event); - } - } -#endif /* !SDL_EVENTS_DISABLED */ + SDL_PrivateJoystickRemoved(pCurList->nInstanceID); pListNext = pCurList->pNext; SDL_free(pCurList->joystickname); @@ -401,17 +376,8 @@ SDL_SYS_JoystickDetect() SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice); } -#if !SDL_EVENTS_DISABLED - SDL_zero(event); - event.type = SDL_JOYDEVICEADDED; + SDL_PrivateJoystickAdded(device_index); - if (SDL_GetEventState(event.type) == SDL_ENABLE) { - event.jdevice.which = device_index; - if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { - SDL_PushEvent(&event); - } - } -#endif /* !SDL_EVENTS_DISABLED */ pNewJoystick->send_add_event = SDL_FALSE; } device_index++; @@ -543,6 +509,9 @@ SDL_SYS_JoystickQuit(void) SDL_DINPUT_JoystickQuit(); SDL_XINPUT_JoystickQuit(); + + s_bDeviceAdded = SDL_FALSE; + s_bDeviceRemoved = SDL_FALSE; } /* return the stable device guid for this device index */ diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick_c.h b/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick_c.h index ab946b4f7..d3c5fcaab 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick_c.h +++ b/Engine/lib/sdl/src/joystick/windows/SDL_windowsjoystick_c.h @@ -83,6 +83,10 @@ struct joystick_hwdata DWORD dwPacketNumber; }; +#if SDL_JOYSTICK_DINPUT +extern const DIDATAFORMAT SDL_c_dfDIJoystick2; +#endif + extern void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device); /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c b/Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c index 2f27c47dc..d581d45b9 100644 --- a/Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c +++ b/Engine/lib/sdl/src/joystick/windows/SDL_xinputjoystick.c @@ -40,8 +40,7 @@ SDL_XInputUseOldJoystickMapping() { static int s_XInputUseOldJoystickMapping = -1; if (s_XInputUseOldJoystickMapping < 0) { - const char *hint = SDL_GetHint(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING); - s_XInputUseOldJoystickMapping = (hint && *hint == '1') ? 1 : 0; + s_XInputUseOldJoystickMapping = SDL_GetHintBoolean(SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING, SDL_FALSE); } return (s_XInputUseOldJoystickMapping > 0); } @@ -54,10 +53,7 @@ SDL_bool SDL_XINPUT_Enabled(void) int SDL_XINPUT_JoystickInit(void) { - const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED); - if (env && !SDL_atoi(env)) { - s_bXInputEnabled = SDL_FALSE; - } + s_bXInputEnabled = SDL_GetHintBoolean(SDL_HINT_XINPUT_ENABLED, SDL_TRUE); if (s_bXInputEnabled && WIN_LoadXInputDLL() < 0) { s_bXInputEnabled = SDL_FALSE; /* oh well. */ @@ -376,7 +372,7 @@ SDL_SYS_IsXInputGamepad_DeviceIndex(int device_index) for (index = device_index; index > 0; index--) device = device->pNext; - return (device->SubType == XINPUT_DEVSUBTYPE_GAMEPAD); + return device->bXInputDevice; } #else /* !SDL_JOYSTICK_XINPUT */ diff --git a/Engine/lib/sdl/src/loadso/dlopen/SDL_sysloadso.c b/Engine/lib/sdl/src/loadso/dlopen/SDL_sysloadso.c index 03ffae129..7b30b7735 100644 --- a/Engine/lib/sdl/src/loadso/dlopen/SDL_sysloadso.c +++ b/Engine/lib/sdl/src/loadso/dlopen/SDL_sysloadso.c @@ -30,11 +30,25 @@ #include "SDL_loadso.h" +#if SDL_VIDEO_DRIVER_UIKIT +#include "../../video/uikit/SDL_uikitvideo.h" +#endif + void * SDL_LoadObject(const char *sofile) { - void *handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL); - const char *loaderror = (char *) dlerror(); + void *handle; + const char *loaderror; + +#if SDL_VIDEO_DRIVER_UIKIT + if (!UIKit_IsSystemVersionAtLeast(8.0)) { + SDL_SetError("SDL_LoadObject requires iOS 8+"); + return NULL; + } +#endif + + handle = dlopen(sofile, RTLD_NOW|RTLD_LOCAL); + loaderror = (char *) dlerror(); if (handle == NULL) { SDL_SetError("Failed loading %s: %s", sofile, loaderror); } diff --git a/Engine/lib/sdl/src/main/android/SDL_android_main.c b/Engine/lib/sdl/src/main/android/SDL_android_main.c index 4173bcb1d..671d9328e 100644 --- a/Engine/lib/sdl/src/main/android/SDL_android_main.c +++ b/Engine/lib/sdl/src/main/android/SDL_android_main.c @@ -16,12 +16,17 @@ /* Called before SDL_main() to initialize JNI bindings in SDL library */ extern void SDL_Android_Init(JNIEnv* env, jclass cls); +/* This prototype is needed to prevent a warning about the missing prototype for global function below */ +JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array); + /* Start up the SDL app */ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array) { int i; int argc; int status; + int len; + char** argv; /* This interface could expand with ABI negotiation, callbacks, etc. */ SDL_Android_Init(env, cls); @@ -30,8 +35,8 @@ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jc /* Prepare the arguments. */ - int len = (*env)->GetArrayLength(env, array); - char* argv[1 + len + 1]; + len = (*env)->GetArrayLength(env, array); + argv = SDL_stack_alloc(char*, 1 + len + 1); argc = 0; /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works. https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start @@ -66,7 +71,7 @@ JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jc for (i = 0; i < argc; ++i) { SDL_free(argv[i]); } - + SDL_stack_free(argv); /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ /* exit(status); */ diff --git a/Engine/lib/sdl/src/main/haiku/SDL_BApp.h b/Engine/lib/sdl/src/main/haiku/SDL_BApp.h index 157c23635..9672d462c 100644 --- a/Engine/lib/sdl/src/main/haiku/SDL_BApp.h +++ b/Engine/lib/sdl/src/main/haiku/SDL_BApp.h @@ -193,7 +193,8 @@ public: if(_current_context) _current_context->UnlockGL(); _current_context = newContext; - _current_context->LockGL(); + if (_current_context) + _current_context->LockGL(); } private: /* Event management */ @@ -272,6 +273,17 @@ private: } BE_SetKeyState(scancode, state); SDL_SendKeyboardKey(state, BE_GetScancodeFromBeKey(scancode)); + + if (state == SDL_PRESSED && SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { + const int8 *keyUtf8; + ssize_t count; + if (msg->FindData("key-utf8", B_INT8_TYPE, (const void**)&keyUtf8, &count) == B_OK) { + char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; + SDL_zero(text); + SDL_memcpy(text, keyUtf8, count); + SDL_SendKeyboardText(text); + } + } } void _HandleMouseFocus(BMessage *msg) { diff --git a/Engine/lib/sdl/src/main/haiku/SDL_BeApp.cc b/Engine/lib/sdl/src/main/haiku/SDL_BeApp.cc index 36c2a1ab8..4c5df0954 100644 --- a/Engine/lib/sdl/src/main/haiku/SDL_BeApp.cc +++ b/Engine/lib/sdl/src/main/haiku/SDL_BeApp.cc @@ -31,7 +31,6 @@ #include "SDL_BApp.h" /* SDL_BApp class definition */ #include "SDL_BeApp.h" -#include "SDL_thread.h" #include "SDL_timer.h" #include "SDL_error.h" @@ -40,6 +39,9 @@ #ifdef __cplusplus extern "C" { #endif + +#include "../../thread/SDL_systhread.h" + /* Flag to tell whether or not the Be application is active or not */ int SDL_BeAppActive = 0; static SDL_Thread *SDL_AppThread = NULL; @@ -62,7 +64,7 @@ SDL_InitBeApp(void) { /* Create the BApplication that handles appserver interaction */ if (SDL_BeAppActive <= 0) { - SDL_AppThread = SDL_CreateThread(StartBeApp, "SDLApplication", NULL); + SDL_AppThread = SDL_CreateThreadInternal(StartBeApp, "SDLApplication", 0, NULL); if (SDL_AppThread == NULL) { return SDL_SetError("Couldn't create BApplication thread"); } diff --git a/Engine/lib/sdl/src/main/windows/SDL_windows_main.c b/Engine/lib/sdl/src/main/windows/SDL_windows_main.c index e6378081f..b502ed50e 100644 --- a/Engine/lib/sdl/src/main/windows/SDL_windows_main.c +++ b/Engine/lib/sdl/src/main/windows/SDL_windows_main.c @@ -126,44 +126,15 @@ main_utf8(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) +/* Gets the arguments with GetCommandLine, converts them to argc and argv + and calls main_utf8 */ +static int +main_getcmdline() { char **argv; int argc; char *cmdline; + int retval = 0; /* Grab the command line */ TCHAR *text = GetCommandLine(); @@ -185,15 +156,50 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) } ParseCommandLine(cmdline, argv); - /* Run the main program */ - main_utf8(argc, argv); + retval = main_utf8(argc, argv); SDL_stack_free(argv); - SDL_free(cmdline); - /* Hush little compiler, don't you cry... */ - return 0; + return retval; +} + +/* This is where execution begins [console apps, ansi] */ +int +console_ansi_main(int argc, char *argv[]) +{ + return main_getcmdline(); +} + + +#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 + 1); + int i; + + for (i = 0; i < argc; ++i) { + argv[i] = WIN_StringToUTF8(wargv[i]); + } + argv[argc] = NULL; + + 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) +{ + return main_getcmdline(); } #endif /* __WIN32__ */ diff --git a/Engine/lib/sdl/src/main/windows/version.rc b/Engine/lib/sdl/src/main/windows/version.rc index 8597154aa..e10443b06 100644 --- a/Engine/lib/sdl/src/main/windows/version.rc +++ b/Engine/lib/sdl/src/main/windows/version.rc @@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,4,0 - PRODUCTVERSION 2,0,4,0 + FILEVERSION 2,0,5,0 + PRODUCTVERSION 2,0,5,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L @@ -23,12 +23,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "SDL\0" - VALUE "FileVersion", "2, 0, 4, 0\0" + VALUE "FileVersion", "2, 0, 5, 0\0" VALUE "InternalName", "SDL\0" VALUE "LegalCopyright", "Copyright © 2016 Sam Lantinga\0" VALUE "OriginalFilename", "SDL2.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" - VALUE "ProductVersion", "2, 0, 4, 0\0" + VALUE "ProductVersion", "2, 0, 5, 0\0" END END BLOCK "VarFileInfo" diff --git a/Engine/lib/sdl/src/main/winrt/SDL2-WinRTResource_BlankCursor.cur b/Engine/lib/sdl/src/main/winrt/SDL2-WinRTResource_BlankCursor.cur new file mode 100644 index 0000000000000000000000000000000000000000..c6556b8a72d272dc9b47f2194b05a1bc022f80a7 GIT binary patch literal 326 zcmc(Zu@L|u2m>F6u%@(h1V?jo3_1k4`wy22aEu6KV;Kx!3QcTLd*wWTxvHpS=06&( HA6jz(2=#;* literal 0 HcmV?d00001 diff --git a/Engine/lib/sdl/src/main/winrt/SDL2-WinRTResources.rc b/Engine/lib/sdl/src/main/winrt/SDL2-WinRTResources.rc new file mode 100644 index 000000000..988a8d57d --- /dev/null +++ b/Engine/lib/sdl/src/main/winrt/SDL2-WinRTResources.rc @@ -0,0 +1,3 @@ +#include "winres.h" +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +5000 CURSOR "SDL2-WinRTResource_BlankCursor.cur" diff --git a/Engine/lib/sdl/src/power/uikit/SDL_syspower.m b/Engine/lib/sdl/src/power/uikit/SDL_syspower.m index 14ce3576a..7186b219c 100644 --- a/Engine/lib/sdl/src/power/uikit/SDL_syspower.m +++ b/Engine/lib/sdl/src/power/uikit/SDL_syspower.m @@ -30,6 +30,7 @@ #include "SDL_assert.h" #include "SDL_syspower.h" +#if !TARGET_OS_TV /* turn off the battery monitor if it's been more than X ms since last check. */ static const int BATTERY_MONITORING_TIMEOUT = 3000; static Uint32 SDL_UIKitLastPowerInfoQuery = 0; @@ -46,10 +47,22 @@ SDL_UIKit_UpdateBatteryMonitoring(void) } } } +#else +void +SDL_UIKit_UpdateBatteryMonitoring(void) +{ + /* Do nothing. */ +} +#endif /* !TARGET_OS_TV */ SDL_bool SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent) { +#if TARGET_OS_TV + *state = SDL_POWERSTATE_NO_BATTERY; + *seconds = -1; + *percent = -1; +#else /* TARGET_OS_TV */ @autoreleasepool { UIDevice *uidev = [UIDevice currentDevice]; @@ -88,8 +101,10 @@ SDL_GetPowerInfo_UIKit(SDL_PowerState * state, int *seconds, int *percent) 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 /* TARGET_OS_TV */ + + return SDL_TRUE; /* always the definitive answer on iOS. */ } #endif /* SDL_POWER_UIKIT */ diff --git a/Engine/lib/sdl/src/render/SDL_render.c b/Engine/lib/sdl/src/render/SDL_render.c index 923973ec7..94750810d 100644 --- a/Engine/lib/sdl/src/render/SDL_render.c +++ b/Engine/lib/sdl/src/render/SDL_render.c @@ -234,12 +234,11 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) return NULL; } - hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); - if (hint) { - if (*hint == '0') { - flags &= ~SDL_RENDERER_PRESENTVSYNC; - } else { + if (SDL_GetHint(SDL_HINT_RENDER_VSYNC)) { + if (SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, SDL_TRUE)) { flags |= SDL_RENDERER_PRESENTVSYNC; + } else { + flags &= ~SDL_RENDERER_PRESENTVSYNC; } } @@ -1106,6 +1105,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) renderer->viewport.y = 0; renderer->viewport.w = texture->w; renderer->viewport.h = texture->h; + SDL_zero(renderer->clip_rect); + renderer->clipping_enabled = SDL_FALSE; renderer->scale.x = 1.0f; renderer->scale.y = 1.0f; renderer->logical_w = texture->w; @@ -1144,6 +1145,9 @@ UpdateLogicalSize(SDL_Renderer *renderer) float scale; SDL_Rect viewport; + if (!renderer->logical_w || !renderer->logical_h) { + return 0; + } if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { return -1; } @@ -1154,7 +1158,19 @@ UpdateLogicalSize(SDL_Renderer *renderer) /* Clear the scale because we're setting viewport in output coordinates */ SDL_RenderSetScale(renderer, 1.0f, 1.0f); - if (SDL_fabs(want_aspect-real_aspect) < 0.0001) { + if (renderer->integer_scale) { + if (want_aspect > real_aspect) { + scale = (float)(w / renderer->logical_w); + } else { + scale = (float)(h / renderer->logical_h); + } + viewport.w = (int)SDL_ceil(renderer->logical_w * scale); + viewport.x = (w - viewport.w) / 2; + viewport.h = (int)SDL_ceil(renderer->logical_h * scale); + viewport.y = (h - viewport.h) / 2; + + SDL_RenderSetViewport(renderer, &viewport); + } else if (SDL_fabs(want_aspect-real_aspect) < 0.0001) { /* The aspect ratios are the same, just scale appropriately */ scale = (float)w / renderer->logical_w; SDL_RenderSetViewport(renderer, NULL); @@ -1215,6 +1231,24 @@ SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h) } } +int +SDL_RenderSetIntegerScale(SDL_Renderer * renderer, SDL_bool enable) +{ + CHECK_RENDERER_MAGIC(renderer, -1); + + renderer->integer_scale = enable; + + return UpdateLogicalSize(renderer); +} + +SDL_bool +SDLCALL SDL_RenderGetIntegerScale(SDL_Renderer * renderer) +{ + CHECK_RENDERER_MAGIC(renderer, SDL_FALSE); + + return renderer->integer_scale; +} + int SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) { @@ -1425,6 +1459,7 @@ SDL_RenderDrawPoints(SDL_Renderer * renderer, if (count < 1) { return 0; } + /* Don't draw while we're hidden */ if (renderer->hidden) { return 0; @@ -1534,6 +1569,7 @@ SDL_RenderDrawLines(SDL_Renderer * renderer, if (count < 2) { return 0; } + /* Don't draw while we're hidden */ if (renderer->hidden) { return 0; @@ -1607,6 +1643,7 @@ SDL_RenderDrawRects(SDL_Renderer * renderer, if (renderer->hidden) { return 0; } + for (i = 0; i < count; ++i) { if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) { return -1; @@ -1648,6 +1685,7 @@ SDL_RenderFillRects(SDL_Renderer * renderer, if (count < 1) { return 0; } + /* Don't draw while we're hidden */ if (renderer->hidden) { return 0; @@ -1686,6 +1724,11 @@ SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, return SDL_SetError("Texture was not created with this renderer"); } + /* Don't draw while we're hidden */ + if (renderer->hidden) { + return 0; + } + real_srcrect.x = 0; real_srcrect.y = 0; real_srcrect.w = texture->w; @@ -1710,11 +1753,6 @@ SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, texture = texture->native; } - /* Don't draw while we're hidden */ - if (renderer->hidden) { - return 0; - } - frect.x = real_dstrect.x * renderer->scale.x; frect.y = real_dstrect.y * renderer->scale.y; frect.w = real_dstrect.w * renderer->scale.x; @@ -1735,7 +1773,7 @@ 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 */ + if (flip == SDL_FLIP_NONE && (int)(angle/360) == angle/360) { /* fast path when we don't need rotation or flipping */ return SDL_RenderCopy(renderer, texture, srcrect, dstrect); } @@ -1749,6 +1787,11 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, return SDL_SetError("Renderer does not support RenderCopyEx"); } + /* Don't draw while we're hidden */ + if (renderer->hidden) { + return 0; + } + real_srcrect.x = 0; real_srcrect.y = 0; real_srcrect.w = texture->w; @@ -1772,8 +1815,9 @@ SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, texture = texture->native; } - if(center) real_center = *center; - else { + if (center) { + real_center = *center; + } else { real_center.x = real_dstrect.w/2; real_center.y = real_dstrect.h/2; } diff --git a/Engine/lib/sdl/src/render/SDL_sysrender.h b/Engine/lib/sdl/src/render/SDL_sysrender.h index 19dfe8e64..378fc4d97 100644 --- a/Engine/lib/sdl/src/render/SDL_sysrender.h +++ b/Engine/lib/sdl/src/render/SDL_sysrender.h @@ -135,6 +135,9 @@ struct SDL_Renderer int logical_w_backup; int logical_h_backup; + /* Whether or not to force the viewport to even integer intervals */ + SDL_bool integer_scale; + /* The drawable area within the window */ SDL_Rect viewport; SDL_Rect viewport_backup; diff --git a/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c b/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c index 9d7564224..151dbbf04 100644 --- a/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c +++ b/Engine/lib/sdl/src/render/direct3d/SDL_render_d3d.c @@ -512,7 +512,6 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags) D3D_RenderData *data; SDL_SysWMinfo windowinfo; HRESULT result; - const char *hint; D3DPRESENT_PARAMETERS pparams; IDirect3DSwapChain9 *chain; D3DCAPS9 caps; @@ -607,8 +606,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags) device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; } - hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE); - if (hint && SDL_atoi(hint)) { + if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) { device_flags |= D3DCREATE_MULTITHREADED; } @@ -1004,6 +1002,10 @@ D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata; + if (!texturedata) { + return 0; + } + if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) { return -1; } @@ -1307,6 +1309,10 @@ D3D_RenderClear(SDL_Renderer * renderer) BackBufferHeight = data->pparams.BackBufferHeight; } + if (renderer->clipping_enabled) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE); + } + /* Don't reset the viewport if we don't have to! */ if (!renderer->viewport.x && !renderer->viewport.y && renderer->viewport.w == BackBufferWidth && @@ -1336,6 +1342,10 @@ D3D_RenderClear(SDL_Renderer * renderer) IDirect3DDevice9_SetViewport(data->device, &viewport); } + if (renderer->clipping_enabled) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE); + } + if (FAILED(result)) { return D3D_SetError("Clear()", result); } diff --git a/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c b/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c index a48eacee7..df0f1558a 100644 --- a/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c +++ b/Engine/lib/sdl/src/render/direct3d11/SDL_render_d3d11.c @@ -51,6 +51,8 @@ extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNat #endif /* __WINRT__ */ +#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str + #define SAFE_RELEASE(X) if ((X)) { IUnknown_Release(SDL_static_cast(IUnknown*, X)); X = NULL; } @@ -136,14 +138,31 @@ typedef struct } D3D11_RenderData; -/* Defined here so we don't have to include uuid.lib */ -static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; -static const GUID IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; -static const GUID IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } }; -static const GUID IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } }; -static const GUID IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } }; -static const GUID IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } }; -static const GUID IID_ID3D11Debug = { 0x79cf2233, 0x7536, 0x4948, { 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60 } }; +/* Define D3D GUIDs here so we don't have to include uuid.lib. +* +* Fix for SDL bug https://bugzilla.libsdl.org/show_bug.cgi?id=3437: +* The extra 'SDL_' was added to the start of each IID's name, in order +* to prevent build errors on both MinGW-w64 and WinRT/UWP. +* (SDL bug https://bugzilla.libsdl.org/show_bug.cgi?id=3336 led to +* linker errors in WinRT/UWP builds.) +*/ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-const-variable" +#endif + +static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; +static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; +static const GUID SDL_IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } }; +static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } }; +static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } }; +static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } }; +static const GUID SDL_IID_ID3D11Debug = { 0x79cf2233, 0x7536, 0x4948, { 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60 } }; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif /* Direct3D 11.x shaders @@ -961,7 +980,7 @@ D3D11_CreateBlendMode(SDL_Renderer * renderer, blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; result = ID3D11Device_CreateBlendState(data->d3dDevice, &blendDesc, blendStateOutput); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBlendState", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBlendState"), result); return result; } @@ -976,13 +995,11 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc; D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc; - IDXGIAdapter *d3dAdapter = NULL; ID3D11Device *d3dDevice = NULL; ID3D11DeviceContext *d3dContext = NULL; IDXGIDevice1 *dxgiDevice = NULL; HRESULT result = S_OK; UINT creationFlags; - const char *hint; /* This array defines the set of DirectX hardware feature levels this app will support. * Note the ordering should be preserved. @@ -1041,16 +1058,16 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) } #endif /* __WINRT__ */ - result = CreateDXGIFactoryFunc(&IID_IDXGIFactory2, &data->dxgiFactory); + result = CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("CreateDXGIFactory"), result); goto done; } /* FIXME: Should we use the default adapter? */ result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &data->dxgiAdapter); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", D3D11CreateDevice", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result); goto done; } @@ -1060,8 +1077,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; /* Make sure Direct3D's debugging feature gets used, if the app requests it. */ - hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D11_DEBUG); - if (hint && SDL_atoi(hint) > 0) { + if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D11_DEBUG, SDL_FALSE)) { creationFlags |= D3D11_CREATE_DEVICE_DEBUG; } @@ -1079,25 +1095,25 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &d3dContext /* Returns the device immediate context. */ ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", D3D11CreateDevice", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result); goto done; } - result = ID3D11Device_QueryInterface(d3dDevice, &IID_ID3D11Device1, &data->d3dDevice); + result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_ID3D11Device1, (void **)&data->d3dDevice); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to ID3D11Device1", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to ID3D11Device1"), result); goto done; } - result = ID3D11DeviceContext_QueryInterface(d3dContext, &IID_ID3D11DeviceContext1, &data->d3dContext); + result = ID3D11DeviceContext_QueryInterface(d3dContext, &SDL_IID_ID3D11DeviceContext1, (void **)&data->d3dContext); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext to ID3D11DeviceContext1", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext to ID3D11DeviceContext1"), result); goto done; } - result = ID3D11Device_QueryInterface(d3dDevice, &IID_IDXGIDevice1, &dxgiDevice); + result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_IDXGIDevice1, (void **)&dxgiDevice); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to IDXGIDevice1", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to IDXGIDevice1"), result); goto done; } @@ -1106,7 +1122,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) */ result = IDXGIDevice1_SetMaximumFrameLatency(dxgiDevice, 1); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::SetMaximumFrameLatency", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIDevice1::SetMaximumFrameLatency"), result); goto done; } @@ -1135,7 +1151,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) break; default: - SDL_SetError(__FUNCTION__ ", Unexpected feature level: %d", data->featureLevel); + SDL_SetError("%s, Unexpected feature level: %d", __FUNCTION__, data->featureLevel); result = E_FAIL; goto done; } @@ -1148,7 +1164,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->vertexShader ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateVertexShader", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateVertexShader"), result); goto done; } @@ -1161,7 +1177,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->inputLayout ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateInputLayout", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateInputLayout"), result); goto done; } @@ -1173,7 +1189,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->colorPixelShader ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['color' shader]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreatePixelShader ['color' shader]"), result); goto done; } @@ -1184,7 +1200,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->texturePixelShader ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['textures' shader]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreatePixelShader ['textures' shader]"), result); goto done; } @@ -1195,7 +1211,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->yuvPixelShader ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['yuv' shader]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreatePixelShader ['yuv' shader]"), result); goto done; } @@ -1210,7 +1226,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->vertexShaderConstants ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex shader constants]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex shader constants]"), result); goto done; } @@ -1230,7 +1246,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->nearestPixelSampler ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [nearest-pixel filter]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result); goto done; } @@ -1240,7 +1256,7 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) &data->linearSampler ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [linear filter]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [linear filter]"), result); goto done; } @@ -1258,14 +1274,14 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) rasterDesc.SlopeScaledDepthBias = 0.0f; result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->mainRasterizer); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [main rasterizer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [main rasterizer]"), result); goto done; } rasterDesc.ScissorEnable = TRUE; result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->clippedRasterizer); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [clipped rasterizer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [clipped rasterizer]"), result); goto done; } @@ -1358,7 +1374,6 @@ D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer * renderer) static int 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); switch (rotation) { case DXGI_MODE_ROTATION_IDENTITY: @@ -1444,7 +1459,7 @@ D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h) &data->swapChain ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForCoreWindow", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForCoreWindow"), result); goto done; } } else if (usingXAML) { @@ -1454,18 +1469,18 @@ D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h) NULL, &data->swapChain); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForComposition", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForComposition"), result); goto done; } #if WINAPI_FAMILY == WINAPI_FAMILY_APP result = ISwapChainBackgroundPanelNative_SetSwapChain(WINRT_GlobalSwapChainBackgroundPanelNative, (IDXGISwapChain *) data->swapChain); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ISwapChainBackgroundPanelNative::SetSwapChain", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ISwapChainBackgroundPanelNative::SetSwapChain"), result); goto done; } #else - SDL_SetError(__FUNCTION__ ", XAML support is not yet available for Windows Phone"); + SDL_SetError(SDL_COMPOSE_ERROR("XAML support is not yet available for Windows Phone")); result = E_FAIL; goto done; #endif @@ -1484,7 +1499,7 @@ D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h) &data->swapChain ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForHwnd", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForHwnd"), result); goto done; } @@ -1545,7 +1560,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) */ goto done; } else if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain::ResizeBuffers", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result); goto done; } #endif @@ -1576,7 +1591,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) { result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::SetRotation", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain1::SetRotation"), result); goto done; } } @@ -1584,11 +1599,11 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) result = IDXGISwapChain_GetBuffer(data->swapChain, 0, - &IID_ID3D11Texture2D, - &backBuffer + &SDL_IID_ID3D11Texture2D, + (void **)&backBuffer ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain::GetBuffer [back-buffer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::GetBuffer [back-buffer]"), result); goto done; } @@ -1599,7 +1614,7 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) &data->mainRenderTargetView ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device::CreateRenderTargetView", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateRenderTargetView"), result); goto done; } @@ -1618,14 +1633,12 @@ done: static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer) { - D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata; return D3D11_CreateWindowSizeDependentResources(renderer); } HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer) { - D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; HRESULT result = S_OK; D3D11_ReleaseAll(renderer); @@ -1661,7 +1674,7 @@ D3D11_Trim(SDL_Renderer * renderer) HRESULT result = S_OK; IDXGIDevice3 *dxgiDevice = NULL; - result = ID3D11Device_QueryInterface(data->d3dDevice, &IID_IDXGIDevice3, &dxgiDevice); + result = ID3D11Device_QueryInterface(data->d3dDevice, &SDL_IID_IDXGIDevice3, &dxgiDevice); if (FAILED(result)) { //WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to IDXGIDevice3", result); return; @@ -1702,7 +1715,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) D3D11_TEXTURE2D_DESC textureDesc; D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; - if (textureFormat == SDL_PIXELFORMAT_UNKNOWN) { + if (textureFormat == DXGI_FORMAT_UNKNOWN) { return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", __FUNCTION__, texture->format); } @@ -1747,7 +1760,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); return -1; } @@ -1765,7 +1778,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); return -1; } @@ -1776,7 +1789,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); return -1; } } @@ -1792,7 +1805,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ "ID3D11Device1::CreateShaderResourceView", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); return -1; } @@ -1804,7 +1817,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ "ID3D11Device1::CreateShaderResourceView", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); return -1; } result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, @@ -1814,7 +1827,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ "ID3D11Device1::CreateShaderResourceView", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); return -1; } } @@ -1831,7 +1844,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) &textureData->mainTextureRenderTargetView); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result); return -1; } } @@ -1887,7 +1900,7 @@ D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *tex NULL, &stagingTexture); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D [create staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); return -1; } @@ -1900,7 +1913,7 @@ D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *tex &textureMemory ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [map staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); SAFE_RELEASE(stagingTexture); return -1; } @@ -2062,7 +2075,7 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, NULL, &textureData->stagingTexture); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D [create staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); return -1; } @@ -2075,7 +2088,7 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, &textureMemory ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [map staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); SAFE_RELEASE(textureData->stagingTexture); return -1; } @@ -2359,7 +2372,7 @@ D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, &mappedResource ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [vertex buffer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result); return -1; } SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes); @@ -2383,7 +2396,7 @@ D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, &rendererData->vertexBuffer ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex buffer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result); return -1; } @@ -2842,18 +2855,18 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, HRESULT result; int status = -1; D3D11_TEXTURE2D_DESC stagingTextureDesc; - D3D11_RECT srcRect; + D3D11_RECT srcRect = {0, 0, 0, 0}; D3D11_BOX srcBox; D3D11_MAPPED_SUBRESOURCE textureMemory; /* Retrieve a pointer to the back buffer: */ result = IDXGISwapChain_GetBuffer(data->swapChain, 0, - &IID_ID3D11Texture2D, - &backBuffer + &SDL_IID_ID3D11Texture2D, + (void **)&backBuffer ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::GetBuffer [get back buffer]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain1::GetBuffer [get back buffer]"), result); goto done; } @@ -2870,7 +2883,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, NULL, &stagingTexture); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateTexture2D [create staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); goto done; } @@ -2902,7 +2915,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 0, &textureMemory); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [map staging texture]", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); goto done; } @@ -2921,7 +2934,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, * Get the error message, and attach some extra data to it. */ char errorMessage[1024]; - SDL_snprintf(errorMessage, sizeof(errorMessage), __FUNCTION__ ", Convert Pixels failed: %s", SDL_GetError()); + SDL_snprintf(errorMessage, sizeof(errorMessage), "%s, Convert Pixels failed: %s", __FUNCTION__, SDL_GetError()); SDL_SetError("%s", errorMessage); goto done; } @@ -2991,7 +3004,7 @@ D3D11_RenderPresent(SDL_Renderer * renderer) /* We probably went through a fullscreen <-> windowed transition */ D3D11_CreateWindowSizeDependentResources(renderer); } else { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain::Present", result); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::Present"), result); } } } diff --git a/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c b/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c index 6a4fa3ecf..1ca2cb5c4 100644 --- a/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c +++ b/Engine/lib/sdl/src/render/opengl/SDL_render_gl.c @@ -390,7 +390,6 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) { SDL_Renderer *renderer; GL_RenderData *data; - const char *hint; GLint value; Uint32 window_flags; int profile_mask = 0, major = 0, minor = 0; @@ -450,7 +449,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->GL_BindTexture = GL_BindTexture; renderer->GL_UnbindTexture = GL_UnbindTexture; renderer->info = GL_RenderDriver.info; - renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); + renderer->info.flags = SDL_RENDERER_ACCELERATED; renderer->driverdata = data; renderer->window = window; @@ -528,8 +527,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) } /* Check for shader support */ - hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS); - if (!hint || *hint != '0') { + if (SDL_GetHintBoolean(SDL_HINT_RENDER_OPENGL_SHADERS, SDL_TRUE)) { data->shaders = GL_CreateShaderContext(); } SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s", @@ -594,7 +592,6 @@ static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) { SDL_GL_GetDrawableSize(renderer->window, w, h); - return 0; } @@ -664,6 +661,11 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) GL_ActivateRenderer(renderer); + if (texture->access == SDL_TEXTUREACCESS_TARGET && + !renderdata->GL_EXT_framebuffer_object_supported) { + return SDL_SetError("Render targets not supported by OpenGL"); + } + if (!convert_format(renderdata, texture->format, &internalFormat, &format, &type)) { return SDL_SetError("Texture format %s not supported by OpenGL", @@ -980,6 +982,10 @@ GL_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) GL_ActivateRenderer(renderer); + if (!data->GL_EXT_framebuffer_object_supported) { + return SDL_SetError("Render targets not supported by OpenGL"); + } + if (texture == NULL) { data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); return 0; @@ -1013,7 +1019,7 @@ GL_UpdateViewport(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h), renderer->viewport.w, renderer->viewport.h); } @@ -1051,7 +1057,7 @@ GL_UpdateClipRect(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h); } } else { @@ -1089,21 +1095,17 @@ GL_SetBlendMode(GL_RenderData * data, int blendMode) if (blendMode != data->current.blendMode) { switch (blendMode) { case SDL_BLENDMODE_NONE: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); data->glDisable(GL_BLEND); break; case SDL_BLENDMODE_BLEND: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); break; case SDL_BLENDMODE_ADD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); break; case SDL_BLENDMODE_MOD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); break; @@ -1141,8 +1143,16 @@ GL_RenderClear(SDL_Renderer * renderer) (GLfloat) renderer->b * inv255f, (GLfloat) renderer->a * inv255f); + if (renderer->clipping_enabled) { + data->glDisable(GL_SCISSOR_TEST); + } + data->glClear(GL_COLOR_BUFFER_BIT); + if (renderer->clipping_enabled) { + data->glEnable(GL_SCISSOR_TEST); + } + return 0; } @@ -1409,7 +1419,7 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch) { GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - Uint32 temp_format = SDL_PIXELFORMAT_ARGB8888; + Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ARGB8888; void *temp_pixels; int temp_pitch; GLint internalFormat; @@ -1426,7 +1436,11 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, return SDL_OutOfMemory(); } - convert_format(data, temp_format, &internalFormat, &format, &type); + if (!convert_format(data, temp_format, &internalFormat, &format, &type)) { + SDL_free(temp_pixels); + return SDL_SetError("Texture format %s not supported by OpenGL", + SDL_GetPixelFormatName(temp_format)); + } SDL_GetRendererOutputSize(renderer, &w, &h); @@ -1434,28 +1448,30 @@ GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, data->glPixelStorei(GL_PACK_ROW_LENGTH, (temp_pitch / SDL_BYTESPERPIXEL(temp_format))); - data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, - format, type, temp_pixels); + data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h, + rect->w, rect->h, format, type, temp_pixels); if (GL_CheckError("glReadPixels()", renderer) < 0) { SDL_free(temp_pixels); return -1; } - /* Flip the rows to be top-down */ - length = rect->w * SDL_BYTESPERPIXEL(temp_format); - src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; - dst = (Uint8*)temp_pixels; - tmp = SDL_stack_alloc(Uint8, length); - rows = rect->h / 2; - while (rows--) { - SDL_memcpy(tmp, dst, length); - SDL_memcpy(dst, src, length); - SDL_memcpy(src, tmp, length); - dst += temp_pitch; - src -= temp_pitch; + /* Flip the rows to be top-down if necessary */ + if (!renderer->target) { + length = rect->w * SDL_BYTESPERPIXEL(temp_format); + src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; + dst = (Uint8*)temp_pixels; + tmp = SDL_stack_alloc(Uint8, length); + rows = rect->h / 2; + while (rows--) { + SDL_memcpy(tmp, dst, length); + SDL_memcpy(dst, src, length); + SDL_memcpy(src, tmp, length); + dst += temp_pitch; + src -= temp_pitch; + } + SDL_stack_free(tmp); } - SDL_stack_free(tmp); status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, diff --git a/Engine/lib/sdl/src/render/opengles/SDL_render_gles.c b/Engine/lib/sdl/src/render/opengles/SDL_render_gles.c index 0d59da360..71f5b3a7a 100644 --- a/Engine/lib/sdl/src/render/opengles/SDL_render_gles.c +++ b/Engine/lib/sdl/src/render/opengles/SDL_render_gles.c @@ -129,8 +129,6 @@ typedef struct GLES_FBOList *framebuffers; GLuint window_framebuffer; - SDL_bool useDrawTexture; - SDL_bool GL_OES_draw_texture_supported; SDL_bool GL_OES_blend_func_separate_supported; } GLES_RenderData; @@ -369,19 +367,6 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; } -#if SDL_VIDEO_DRIVER_PANDORA - data->GL_OES_draw_texture_supported = SDL_FALSE; - data->useDrawTexture = SDL_FALSE; -#else - if (SDL_GL_ExtensionSupported("GL_OES_draw_texture")) { - data->GL_OES_draw_texture_supported = SDL_TRUE; - data->useDrawTexture = SDL_TRUE; - } else { - data->GL_OES_draw_texture_supported = SDL_FALSE; - data->useDrawTexture = SDL_FALSE; - } -#endif - value = 0; data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); renderer->info.max_texture_width = value; @@ -605,6 +590,7 @@ GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, data->format, data->formattype, src); + renderdata->glDisable(data->type); SDL_free(blob); if (renderdata->glGetError() != GL_NO_ERROR) { @@ -686,18 +672,27 @@ GLES_UpdateViewport(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h), renderer->viewport.w, renderer->viewport.h); } + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); if (renderer->viewport.w && renderer->viewport.h) { - data->glMatrixMode(GL_PROJECTION); - data->glLoadIdentity(); - data->glOrthof((GLfloat) 0, - (GLfloat) renderer->viewport.w, - (GLfloat) renderer->viewport.h, - (GLfloat) 0, 0.0, 1.0); + if (renderer->target) { + data->glOrthof((GLfloat) 0, + (GLfloat) renderer->viewport.w, + (GLfloat) 0, + (GLfloat) renderer->viewport.h, + 0.0, 1.0); + } else { + data->glOrthof((GLfloat) 0, + (GLfloat) renderer->viewport.w, + (GLfloat) renderer->viewport.h, + (GLfloat) 0, + 0.0, 1.0); + } } return 0; } @@ -720,7 +715,7 @@ GLES_UpdateClipRect(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h); } } else { @@ -749,11 +744,9 @@ GLES_SetBlendMode(GLES_RenderData * data, int blendMode) if (blendMode != data->current.blendMode) { switch (blendMode) { case SDL_BLENDMODE_NONE: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); data->glDisable(GL_BLEND); break; case SDL_BLENDMODE_BLEND: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); if (data->GL_OES_blend_func_separate_supported) { data->glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -762,7 +755,6 @@ GLES_SetBlendMode(GLES_RenderData * data, int blendMode) } break; case SDL_BLENDMODE_ADD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); if (data->GL_OES_blend_func_separate_supported) { data->glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); @@ -771,7 +763,6 @@ GLES_SetBlendMode(GLES_RenderData * data, int blendMode) } break; case SDL_BLENDMODE_MOD: - data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); data->glEnable(GL_BLEND); if (data->GL_OES_blend_func_separate_supported) { data->glBlendFuncSeparateOES(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); @@ -825,9 +816,17 @@ GLES_RenderClear(SDL_Renderer * renderer) (GLfloat) renderer->g * inv255f, (GLfloat) renderer->b * inv255f, (GLfloat) renderer->a * inv255f); + + if (renderer->clipping_enabled) { + data->glDisable(GL_SCISSOR_TEST); + } data->glClear(GL_COLOR_BUFFER_BIT); + if (renderer->clipping_enabled) { + data->glEnable(GL_SCISSOR_TEST); + } + return 0; } @@ -952,71 +951,42 @@ GLES_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, GLES_SetTexCoords(data, SDL_TRUE); - if (data->GL_OES_draw_texture_supported && data->useDrawTexture) { - /* this code is a little funny because the viewport is upside down vs SDL's coordinate system */ - GLint cropRect[4]; - int w, h; - SDL_Window *window = renderer->window; + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; - SDL_GetWindowSize(window, &w, &h); - if (renderer->target) { - cropRect[0] = srcrect->x; - cropRect[1] = srcrect->y; - cropRect[2] = srcrect->w; - cropRect[3] = srcrect->h; - data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, - cropRect); - data->glDrawTexfOES(renderer->viewport.x + dstrect->x, renderer->viewport.y + dstrect->y, 0, - dstrect->w, dstrect->h); - } else { - cropRect[0] = srcrect->x; - cropRect[1] = srcrect->y + srcrect->h; - cropRect[2] = srcrect->w; - cropRect[3] = -srcrect->h; - data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, - cropRect); - data->glDrawTexfOES(renderer->viewport.x + dstrect->x, - h - (renderer->viewport.y + dstrect->y) - dstrect->h, 0, - dstrect->w, dstrect->h); - } - } else { + minu = (GLfloat) srcrect->x / texture->w; + minu *= texturedata->texw; + maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; + maxu *= texturedata->texw; + minv = (GLfloat) srcrect->y / texture->h; + minv *= texturedata->texh; + maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; + maxv *= texturedata->texh; - minx = dstrect->x; - miny = dstrect->y; - maxx = dstrect->x + dstrect->w; - maxy = dstrect->y + dstrect->h; + vertices[0] = minx; + vertices[1] = miny; + vertices[2] = maxx; + vertices[3] = miny; + vertices[4] = minx; + vertices[5] = maxy; + vertices[6] = maxx; + vertices[7] = maxy; - minu = (GLfloat) srcrect->x / texture->w; - minu *= texturedata->texw; - maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w; - maxu *= texturedata->texw; - minv = (GLfloat) srcrect->y / texture->h; - minv *= texturedata->texh; - maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h; - maxv *= texturedata->texh; + texCoords[0] = minu; + texCoords[1] = minv; + texCoords[2] = maxu; + texCoords[3] = minv; + texCoords[4] = minu; + texCoords[5] = maxv; + texCoords[6] = maxu; + texCoords[7] = maxv; - vertices[0] = minx; - vertices[1] = miny; - vertices[2] = maxx; - vertices[3] = miny; - vertices[4] = minx; - vertices[5] = maxy; - vertices[6] = maxx; - vertices[7] = maxy; + data->glVertexPointer(2, GL_FLOAT, 0, vertices); + data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - texCoords[0] = minu; - texCoords[1] = minv; - texCoords[2] = maxu; - texCoords[3] = minv; - texCoords[4] = minu; - texCoords[5] = maxv; - texCoords[6] = maxu; - texCoords[7] = maxv; - - data->glVertexPointer(2, GL_FLOAT, 0, vertices); - data->glTexCoordPointer(2, GL_FLOAT, 0, texCoords); - data->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - } data->glDisable(GL_TEXTURE_2D); return 0; @@ -1117,7 +1087,7 @@ GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch) { GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata; - Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888; + Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888; void *temp_pixels; int temp_pitch; Uint8 *src, *dst, *tmp; @@ -1136,23 +1106,25 @@ GLES_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, data->glPixelStorei(GL_PACK_ALIGNMENT, 1); - data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, - GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); + data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h, + rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); - /* Flip the rows to be top-down */ - length = rect->w * SDL_BYTESPERPIXEL(temp_format); - src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; - dst = (Uint8*)temp_pixels; - tmp = SDL_stack_alloc(Uint8, length); - rows = rect->h / 2; - while (rows--) { - SDL_memcpy(tmp, dst, length); - SDL_memcpy(dst, src, length); - SDL_memcpy(src, tmp, length); - dst += temp_pitch; - src -= temp_pitch; + /* Flip the rows to be top-down if necessary */ + if (!renderer->target) { + length = rect->w * SDL_BYTESPERPIXEL(temp_format); + src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; + dst = (Uint8*)temp_pixels; + tmp = SDL_stack_alloc(Uint8, length); + rows = rect->h / 2; + while (rows--) { + SDL_memcpy(tmp, dst, length); + SDL_memcpy(dst, src, length); + SDL_memcpy(src, tmp, length); + dst += temp_pitch; + src -= temp_pitch; + } + SDL_stack_free(tmp); } - SDL_stack_free(tmp); status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, diff --git a/Engine/lib/sdl/src/render/opengles2/SDL_render_gles2.c b/Engine/lib/sdl/src/render/opengles2/SDL_render_gles2.c index e41ab6231..c846a7b39 100644 --- a/Engine/lib/sdl/src/render/opengles2/SDL_render_gles2.c +++ b/Engine/lib/sdl/src/render/opengles2/SDL_render_gles2.c @@ -388,7 +388,7 @@ GLES2_UpdateViewport(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glViewport(renderer->viewport.x, (h - renderer->viewport.y - renderer->viewport.h), renderer->viewport.w, renderer->viewport.h); } @@ -417,7 +417,7 @@ GLES2_UpdateClipRect(SDL_Renderer * renderer) } else { int w, h; - SDL_GetRendererOutputSize(renderer, &w, &h); + SDL_GL_GetDrawableSize(renderer->window, &w, &h); data->glScissor(renderer->viewport.x + rect->x, h - renderer->viewport.y - rect->y - rect->h, rect->w, rect->h); } } else { @@ -1327,8 +1327,16 @@ GLES2_RenderClear(SDL_Renderer * renderer) data->clear_a = renderer->a; } + if (renderer->clipping_enabled) { + data->glDisable(GL_SCISSOR_TEST); + } + data->glClear(GL_COLOR_BUFFER_BIT); + if (renderer->clipping_enabled) { + data->glEnable(GL_SCISSOR_TEST); + } + return 0; } @@ -1817,7 +1825,7 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch) { GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata; - Uint32 temp_format = SDL_PIXELFORMAT_ABGR8888; + Uint32 temp_format = renderer->target ? renderer->target->format : SDL_PIXELFORMAT_ABGR8888; void *temp_pixels; int temp_pitch; Uint8 *src, *dst, *tmp; @@ -1834,26 +1842,28 @@ GLES2_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, SDL_GetRendererOutputSize(renderer, &w, &h); - data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h, - GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); + data->glReadPixels(rect->x, renderer->target ? rect->y : (h-rect->y)-rect->h, + rect->w, rect->h, GL_RGBA, GL_UNSIGNED_BYTE, temp_pixels); if (GL_CheckError("glReadPixels()", renderer) < 0) { return -1; } - /* Flip the rows to be top-down */ - length = rect->w * SDL_BYTESPERPIXEL(temp_format); - src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; - dst = (Uint8*)temp_pixels; - tmp = SDL_stack_alloc(Uint8, length); - rows = rect->h / 2; - while (rows--) { - SDL_memcpy(tmp, dst, length); - SDL_memcpy(dst, src, length); - SDL_memcpy(src, tmp, length); - dst += temp_pitch; - src -= temp_pitch; + /* Flip the rows to be top-down if necessary */ + if (!renderer->target) { + length = rect->w * SDL_BYTESPERPIXEL(temp_format); + src = (Uint8*)temp_pixels + (rect->h-1)*temp_pitch; + dst = (Uint8*)temp_pixels; + tmp = SDL_stack_alloc(Uint8, length); + rows = rect->h / 2; + while (rows--) { + SDL_memcpy(tmp, dst, length); + SDL_memcpy(dst, src, length); + SDL_memcpy(src, tmp, length); + dst += temp_pitch; + src -= temp_pitch; + } + SDL_stack_free(tmp); } - SDL_stack_free(tmp); status = SDL_ConvertPixels(rect->w, rect->h, temp_format, temp_pixels, temp_pitch, @@ -1959,9 +1969,15 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) int profile_mask = 0, major = 0, minor = 0; SDL_bool changed_window = SDL_FALSE; - SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor); + if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile_mask) < 0) { + goto error; + } + if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major) < 0) { + goto error; + } + if (SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor) < 0) { + goto error; + } window_flags = SDL_GetWindowFlags(window); if (!(window_flags & SDL_WINDOW_OPENGL) || diff --git a/Engine/lib/sdl/src/render/psp/SDL_render_psp.c b/Engine/lib/sdl/src/render/psp/SDL_render_psp.c index 8e8c87353..f2851319e 100644 --- a/Engine/lib/sdl/src/render/psp/SDL_render_psp.c +++ b/Engine/lib/sdl/src/render/psp/SDL_render_psp.c @@ -50,6 +50,8 @@ static SDL_Renderer *PSP_CreateRenderer(SDL_Window * window, Uint32 flags); static void PSP_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event); static int PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); +static int PSP_SetTextureColorMod(SDL_Renderer * renderer, + SDL_Texture * texture); static int PSP_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch); @@ -359,6 +361,7 @@ PSP_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->WindowEvent = PSP_WindowEvent; renderer->CreateTexture = PSP_CreateTexture; + renderer->SetTextureColorMod = PSP_SetTextureColorMod; renderer->UpdateTexture = PSP_UpdateTexture; renderer->LockTexture = PSP_LockTexture; renderer->UnlockTexture = PSP_UnlockTexture; @@ -501,6 +504,11 @@ PSP_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) return 0; } +static int +PSP_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + return SDL_Unsupported(); +} void TextureActivate(SDL_Texture * texture) @@ -853,7 +861,7 @@ PSP_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch) { - return 0; + return SDL_Unsupported(); } diff --git a/Engine/lib/sdl/src/render/software/SDL_render_sw.c b/Engine/lib/sdl/src/render/software/SDL_render_sw.c index dadd2442f..e7a6cd88d 100644 --- a/Engine/lib/sdl/src/render/software/SDL_render_sw.c +++ b/Engine/lib/sdl/src/render/software/SDL_render_sw.c @@ -677,8 +677,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, } 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); + 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; diff --git a/Engine/lib/sdl/src/render/software/SDL_rotate.c b/Engine/lib/sdl/src/render/software/SDL_rotate.c index 8d92758f8..0141d174d 100644 --- a/Engine/lib/sdl/src/render/software/SDL_rotate.c +++ b/Engine/lib/sdl/src/render/software/SDL_rotate.c @@ -110,31 +110,105 @@ SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle) { - double x, y, cx, cy, sx, sy; - double radangle; - int dstwidthhalf, dstheighthalf; - - /* - * Determine destination width and height by rotating a centered source box - */ - radangle = angle * (M_PI / 180.0); - *sangle = SDL_sin(radangle); - *cangle = SDL_cos(radangle); - x = (double)(width / 2); - y = (double)(height / 2); - cx = *cangle * x; - cy = *cangle * y; - sx = *sangle * x; - sy = *sangle * y; - - dstwidthhalf = MAX((int) - SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1); - dstheighthalf = MAX((int) - SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1); - *dstwidth = 2 * dstwidthhalf; - *dstheight = 2 * dstheighthalf; + /* The trig code below gets the wrong size (due to FP inaccuracy?) when angle is a multiple of 90 degrees */ + int angle90 = (int)(angle/90); + if(angle90 == angle/90) { /* if the angle is a multiple of 90 degrees */ + angle90 %= 4; + if(angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + if(angle90 & 1) { + *dstwidth = height; + *dstheight = width; + *cangle = 0; + *sangle = angle90 == 1 ? -1 : 1; /* reversed because our rotations are clockwise */ + } else { + *dstwidth = width; + *dstheight = height; + *cangle = angle90 == 0 ? 1 : -1; + *sangle = 0; + } + } else { + double x, y, cx, cy, sx, sy; + double radangle; + int dstwidthhalf, dstheighthalf; + /* + * Determine destination width and height by rotating a centered source box + */ + radangle = angle * (M_PI / -180.0); /* reverse the angle because our rotations are clockwise */ + *sangle = SDL_sin(radangle); + *cangle = SDL_cos(radangle); + x = (double)(width / 2); + y = (double)(height / 2); + cx = *cangle * x; + cy = *cangle * y; + sx = *sangle * x; + sy = *sangle * y; + + dstwidthhalf = MAX((int) + SDL_ceil(MAX(MAX(MAX(SDL_fabs(cx + sy), SDL_fabs(cx - sy)), SDL_fabs(-cx + sy)), SDL_fabs(-cx - sy))), 1); + dstheighthalf = MAX((int) + SDL_ceil(MAX(MAX(MAX(SDL_fabs(sx + cy), SDL_fabs(sx - cy)), SDL_fabs(-sx + cy)), SDL_fabs(-sx - cy))), 1); + *dstwidth = 2 * dstwidthhalf; + *dstheight = 2 * dstheighthalf; + } } +/* Computes source pointer X/Y increments for a rotation that's a multiple of 90 degrees. */ +static void +computeSourceIncrements90(SDL_Surface * src, int bpp, int angle, int flipx, int flipy, + int *sincx, int *sincy, int *signx, int *signy) +{ + int pitch = flipy ? -src->pitch : src->pitch; + if (flipx) { + bpp = -bpp; + } + switch (angle) { /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + case 0: *sincx = bpp; *sincy = pitch - src->w * *sincx; *signx = *signy = 1; break; + case 1: *sincx = -pitch; *sincy = bpp - *sincx * src->h; *signx = 1; *signy = -1; break; + case 2: *sincx = -bpp; *sincy = -src->w * *sincx - pitch; *signx = *signy = -1; break; + case 3: default: *sincx = pitch; *sincy = -*sincx * src->h - bpp; *signx = -1; *signy = 1; break; + } + if (flipx) { + *signx = -*signx; + } + if (flipy) { + *signy = -*signy; + } +} + +/* Performs a relatively fast rotation/flip when the angle is a multiple of 90 degrees. */ +#define TRANSFORM_SURFACE_90(pixelType) \ + int dy, dincy = dst->pitch - dst->w*sizeof(pixelType), sincx, sincy, signx, signy; \ + Uint8 *sp = (Uint8*)src->pixels, *dp = (Uint8*)dst->pixels, *de; \ + \ + computeSourceIncrements90(src, sizeof(pixelType), angle, flipx, flipy, &sincx, &sincy, &signx, &signy); \ + if (signx < 0) sp += (src->w-1)*sizeof(pixelType); \ + if (signy < 0) sp += (src->h-1)*src->pitch; \ + \ + for (dy = 0; dy < dst->h; sp += sincy, dp += dincy, dy++) { \ + if (sincx == sizeof(pixelType)) { /* if advancing src and dest equally, use memcpy */ \ + SDL_memcpy(dp, sp, dst->w*sizeof(pixelType)); \ + sp += dst->w*sizeof(pixelType); \ + dp += dst->w*sizeof(pixelType); \ + } else { \ + for (de = dp + dst->w*sizeof(pixelType); dp != de; sp += sincx, dp += sizeof(pixelType)) { \ + *(pixelType*)dp = *(pixelType*)sp; \ + } \ + } \ + } + +static void +transformSurfaceRGBA90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorRGBA); +} + +static void +transformSurfaceY90(SDL_Surface * src, SDL_Surface * dst, int angle, int flipx, int flipy) +{ + TRANSFORM_SURFACE_90(tColorY); +} + +#undef TRANSFORM_SURFACE_90 /* ! \brief Internal 32 bit rotozoomer with optional anti-aliasing. @@ -341,9 +415,9 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, { SDL_Surface *rz_src; SDL_Surface *rz_dst; - int is32bit; + int is32bit, angle90; int i; - Uint8 r,g,b; + Uint8 r = 0, g = 0, b = 0; Uint32 colorkey = 0; int colorKeyAvailable = 0; double sangleinv, cangleinv; @@ -370,18 +444,13 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, */ rz_src = src; } else { - Uint32 format = SDL_MasksToPixelFormatEnum(32, -#if SDL_BYTEORDER == SDL_LIL_ENDIAN - 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 -#else - 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff -#endif - ); - rz_src = SDL_ConvertSurfaceFormat(src, format, src->flags); + rz_src = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_ARGB32, src->flags); + if (rz_src == NULL) { + return NULL; + } is32bit = 1; } - /* Determine target size */ /* _rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, &dstwidth, &dstheight, &cangle, &sangle); */ @@ -394,7 +463,6 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Alloc space to completely contain the rotated surface */ - rz_dst = NULL; if (is32bit) { /* * Target surface is 32bit with source RGBA/ABGR ordering @@ -430,6 +498,18 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, SDL_LockSurface(rz_src); } + /* check if the rotation is a multiple of 90 degrees so we can take a fast path and also somewhat reduce + * the off-by-one problem in _transformSurfaceRGBA that expresses itself when the rotation is near + * multiples of 90 degrees. + */ + angle90 = (int)(angle/90); + if (angle90 == angle/90) { + angle90 %= 4; + if (angle90 < 0) angle90 += 4; /* 0:0 deg, 1:90 deg, 2:180 deg, 3:270 deg */ + } else { + angle90 = -1; + } + /* * Check which kind of surface we have */ @@ -437,10 +517,11 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Call the 32bit transformation routine to do the rotation (using alpha) */ - _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery, - (int) (sangleinv), (int) (cangleinv), - flipx, flipy, - smooth); + if (angle90 >= 0) { + transformSurfaceRGBA90(rz_src, rz_dst, angle90, flipx, flipy); + } else { + _transformSurfaceRGBA(rz_src, rz_dst, centerx, centery, (int) (sangleinv), (int) (cangleinv), flipx, flipy, smooth); + } /* * Turn on source-alpha support */ @@ -457,9 +538,11 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, /* * Call the 8bit transformation routine to do the rotation */ - transformSurfaceY(rz_src, rz_dst, centerx, centery, - (int) (sangleinv), (int) (cangleinv), - flipx, flipy); + if(angle90 >= 0) { + transformSurfaceY90(rz_src, rz_dst, angle90, flipx, flipy); + } else { + transformSurfaceY(rz_src, rz_dst, centerx, centery, (int)(sangleinv), (int)(cangleinv), flipx, flipy); + } SDL_SetColorKey(rz_dst, /* SDL_SRCCOLORKEY */ SDL_TRUE | SDL_RLEACCEL, _colorkey(rz_src)); } diff --git a/Engine/lib/sdl/src/stdlib/SDL_iconv.c b/Engine/lib/sdl/src/stdlib/SDL_iconv.c index 8f0403734..34bcd8431 100644 --- a/Engine/lib/sdl/src/stdlib/SDL_iconv.c +++ b/Engine/lib/sdl/src/stdlib/SDL_iconv.c @@ -30,7 +30,8 @@ #include "SDL_stdinc.h" #include "SDL_endian.h" -#ifdef HAVE_ICONV +#if defined(HAVE_ICONV) && defined(HAVE_ICONV_H) +#include /* Depending on which standard the iconv() was implemented with, iconv() may or may not use const char ** for the inbuf param. diff --git a/Engine/lib/sdl/src/stdlib/SDL_qsort.c b/Engine/lib/sdl/src/stdlib/SDL_qsort.c index 0d1978424..2ef33b15e 100644 --- a/Engine/lib/sdl/src/stdlib/SDL_qsort.c +++ b/Engine/lib/sdl/src/stdlib/SDL_qsort.c @@ -1,46 +1,23 @@ -/* qsort.c - * (c) 1998 Gareth McCaughan - * - * This is a drop-in replacement for the C library's |qsort()| routine. - * - * Features: - * - Median-of-three pivoting (and more) - * - Truncation and final polishing by a single insertion sort - * - Early truncation when no swaps needed in pivoting step - * - Explicit recursion, guaranteed not to overflow - * - A few little wrinkles stolen from the GNU |qsort()|. - * - separate code for non-aligned / aligned / word-size objects - * - * This code may be reproduced freely provided - * - this file is retained unaltered apart from minor - * changes for portability and efficiency - * - no changes are made to this comment - * - any changes that *are* made are clearly flagged - * - the _ID string below is altered by inserting, after - * the date, the string " altered" followed at your option - * by other material. (Exceptions: you may change the name - * of the exported routine without changing the ID string. - * You may change the values of the macros TRUNC_* and - * PIVOT_THRESHOLD without changing the ID string, provided - * they remain constants with TRUNC_nonaligned, TRUNC_aligned - * and TRUNC_words/WORD_BYTES between 8 and 24, and - * PIVOT_THRESHOLD between 32 and 200.) - * - * You may use it in anything you like; you may make money - * out of it; you may distribute it in object form or as - * part of an executable without including source code; - * you don't have to credit me. (But it would be nice if - * you did.) - * - * If you find problems with this code, or find ways of - * making it significantly faster, please let me know! - * My e-mail address, valid as of early 1998 and certainly - * OK for at least the next 18 months, is - * gjm11@dpmms.cam.ac.uk - * Thanks! - * - * Gareth McCaughan Peterhouse Cambridge 1998 - */ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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. +*/ #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) #define SDL_DISABLE_ANALYZE_MACROS 1 @@ -48,11 +25,6 @@ #include "../SDL_internal.h" -/* -#include -#include -#include -*/ #include "SDL_stdinc.h" #include "SDL_assert.h" @@ -62,34 +34,128 @@ SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, c { qsort(base, nmemb, size, compare); } + #else #ifdef assert #undef assert #endif -#define assert(X) SDL_assert(X) +#define assert SDL_assert #ifdef malloc #undef malloc #endif -#define malloc SDL_malloc +#define malloc SDL_malloc #ifdef free #undef free #endif -#define free SDL_free +#define free SDL_free #ifdef memcpy #undef memcpy #endif -#define memcpy SDL_memcpy +#define memcpy SDL_memcpy #ifdef memmove #undef memmove #endif -#define memmove SDL_memmove -#ifdef qsort -#undef qsort +#define memmove SDL_memmove +#ifdef qsortG +#undef qsortG #endif -#define qsort SDL_qsort +#define qsortG SDL_qsort -static const char _ID[] = ""; +/* +This code came from Gareth McCaughan, under the zlib license. +Specifically this: https://www.mccaughan.org.uk/software/qsort.c-1.14 + +Everything below this comment until the HAVE_QSORT #endif was from Gareth +(any minor changes will be noted inline). + +Thank you to Gareth for relicensing this code under the zlib license for our +benefit! + +--ryan. +*/ + +/* This is a drop-in replacement for the C library's |qsort()| routine. + * + * It is intended for use where you know or suspect that your + * platform's qsort is bad. If that isn't the case, then you + * should probably use the qsort your system gives you in preference + * to mine -- it will likely have been tested and tuned better. + * + * Features: + * - Median-of-three pivoting (and more) + * - Truncation and final polishing by a single insertion sort + * - Early truncation when no swaps needed in pivoting step + * - Explicit recursion, guaranteed not to overflow + * - A few little wrinkles stolen from the GNU |qsort()|. + * (For the avoidance of doubt, no code was stolen, only + * broad ideas.) + * - separate code for non-aligned / aligned / word-size objects + * + * Earlier releases of this code used an idiosyncratic licence + * I wrote myself, because I'm an idiot. The code is now released + * under the "zlib/libpng licence"; you will find the actual + * terms in the next comment. I request (but do not require) + * that if you make any changes beyond the name of the exported + * routine and reasonable tweaks to the TRUNC_* and + * PIVOT_THRESHOLD values, you modify the _ID string so as + * to make it clear that you have changed the code. + * + * If you find problems with this code, or find ways of + * making it significantly faster, please let me know! + * My e-mail address, valid as of early 2016 and for the + * foreseeable future, is + * gareth.mccaughan@pobox.com + * Thanks! + * + * Gareth McCaughan + */ + +/* Copyright (c) 1998-2016 Gareth McCaughan + * + * 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. + */ + +/* Revision history since release: + * 1998-03-19 v1.12 First release I have any records of. + * 2007-09-02 v1.13 Fix bug kindly reported by Dan Bodoh + * (premature termination of recursion). + * Add a few clarifying comments. + * Minor improvements to debug output. + * 2016-02-21 v1.14 Replace licence with 2-clause BSD, + * and clarify a couple of things in + * comments. No code changes. + */ + +/* BEGIN SDL CHANGE ... commented this out with an #if 0 block. --ryan. */ +#if 0 +#include +#include +#include + +#define DEBUG_QSORT + +static char _ID[]=""; +#endif +/* END SDL CHANGE ... commented this out with an #if 0 block. --ryan. */ /* How many bytes are there per word? (Must be a power of 2, * and must in fact equal sizeof(int).) @@ -110,7 +176,7 @@ static const char _ID[] = ""; */ #define TRUNC_nonaligned 12 #define TRUNC_aligned 12 -#define TRUNC_words 12*WORD_BYTES /* nb different meaning */ +#define TRUNC_words 12*WORD_BYTES /* nb different meaning */ /* We use a simple pivoting algorithm for shortish sub-arrays * and a more complicated one for larger ones. The threshold @@ -118,11 +184,7 @@ static const char _ID[] = ""; */ #define PIVOT_THRESHOLD 40 -typedef struct -{ - char *first; - char *last; -} stack_entry; +typedef struct { char * first; char * last; } stack_entry; #define pushLeft {stack[stacktop].first=ffirst;stack[stacktop++].last=last;} #define pushRight {stack[stacktop].first=first;stack[stacktop++].last=llast;} #define doLeft {first=ffirst;llast=last;continue;} @@ -197,7 +259,9 @@ typedef struct * 16-bit |int|s and 4096-bit |size_t|s. :-) */ -/* The recursion logic is the same in each case: */ +/* The recursion logic is the same in each case. + * We keep chopping up until we reach subarrays of size + * strictly less than Trunc; we leave these unsorted. */ #define Recurse(Trunc) \ { size_t l=last-ffirst,r=llast-first; \ if (lPIVOT_THRESHOLD*sz) mid=pivot_big(first,mid,last,sz,compare);\ + if (last-first>PIVOT_THRESHOLD*sz) mid=pivot_big(first,mid,last,sz,compare);\ else { \ if (compare(first,mid)<0) { \ if (compare(mid,last)>0) { \ @@ -235,26 +299,28 @@ typedef struct /* and so is the partitioning logic: */ #define Partition(swapper,sz) { \ - int swapped=0; \ do { \ while (compare(first,pivot)<0) first+=sz; \ while (compare(pivot,last)<0) last-=sz; \ if (firstlimit ? limit : nmemb-1)*sz;\ + last=first + ((nmemb>limit ? limit : nmemb)-1)*sz;\ while (last!=base) { \ if (compare(first,last)>0) first=last; \ last-=sz; } \ @@ -294,188 +360,175 @@ typedef struct /* ---------------------------------------------------------------------- */ -static char * -pivot_big(char *first, char *mid, char *last, size_t size, - int compare(const void *, const void *)) -{ - size_t d = (((last - first) / size) >> 3) * size; - char *m1, *m2, *m3; - { - char *a = first, *b = first + d, *c = first + 2 * d; +static char * pivot_big(char *first, char *mid, char *last, size_t size, + int compare(const void *, const void *)) { + int d=(((last-first)/size)>>3)*size; #ifdef DEBUG_QSORT - fprintf(stderr, "< %d %d %d\n", *(int *) a, *(int *) b, *(int *) c); +fprintf(stderr, "pivot_big: first=%p last=%p size=%lu n=%lu\n", first, (unsigned long)last, size, (unsigned long)((last-first+1)/size)); #endif - m1 = compare(a, b) < 0 ? - (compare(b, c) < 0 ? b : (compare(a, c) < 0 ? c : a)) - : (compare(a, c) < 0 ? a : (compare(b, c) < 0 ? c : b)); - } - { - char *a = mid - d, *b = mid, *c = mid + d; + char *m1,*m2,*m3; + { char *a=first, *b=first+d, *c=first+2*d; #ifdef DEBUG_QSORT - fprintf(stderr, ". %d %d %d\n", *(int *) a, *(int *) b, *(int *) c); +fprintf(stderr,"< %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c); #endif - m2 = compare(a, b) < 0 ? - (compare(b, c) < 0 ? b : (compare(a, c) < 0 ? c : a)) - : (compare(a, c) < 0 ? a : (compare(b, c) < 0 ? c : b)); - } - { - char *a = last - 2 * d, *b = last - d, *c = last; + m1 = compare(a,b)<0 ? + (compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a)) + : (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b)); + } + { char *a=mid-d, *b=mid, *c=mid+d; #ifdef DEBUG_QSORT - fprintf(stderr, "> %d %d %d\n", *(int *) a, *(int *) b, *(int *) c); +fprintf(stderr,". %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c); #endif - m3 = compare(a, b) < 0 ? - (compare(b, c) < 0 ? b : (compare(a, c) < 0 ? c : a)) - : (compare(a, c) < 0 ? a : (compare(b, c) < 0 ? c : b)); - } + m2 = compare(a,b)<0 ? + (compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a)) + : (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b)); + } + { char *a=last-2*d, *b=last-d, *c=last; #ifdef DEBUG_QSORT - fprintf(stderr, "-> %d %d %d\n", *(int *) m1, *(int *) m2, *(int *) m3); +fprintf(stderr,"> %d %d %d @ %p %p %p\n",*(int*)a,*(int*)b,*(int*)c, a,b,c); #endif - return compare(m1, m2) < 0 ? - (compare(m2, m3) < 0 ? m2 : (compare(m1, m3) < 0 ? m3 : m1)) - : (compare(m1, m3) < 0 ? m1 : (compare(m2, m3) < 0 ? m3 : m2)); + m3 = compare(a,b)<0 ? + (compare(b,c)<0 ? b : (compare(a,c)<0 ? c : a)) + : (compare(a,c)<0 ? a : (compare(b,c)<0 ? c : b)); + } +#ifdef DEBUG_QSORT +fprintf(stderr,"-> %d %d %d @ %p %p %p\n",*(int*)m1,*(int*)m2,*(int*)m3, m1,m2,m3); +#endif + return compare(m1,m2)<0 ? + (compare(m2,m3)<0 ? m2 : (compare(m1,m3)<0 ? m3 : m1)) + : (compare(m1,m3)<0 ? m1 : (compare(m2,m3)<0 ? m3 : m2)); } /* ---------------------------------------------------------------------- */ -static void -qsort_nonaligned(void *base, size_t nmemb, size_t size, - int (*compare) (const void *, const void *)) -{ +static void qsort_nonaligned(void *base, size_t nmemb, size_t size, + int (*compare)(const void *, const void *)) { - stack_entry stack[STACK_SIZE]; - int stacktop = 0; - char *first, *last; - char *pivot = malloc(size); - size_t trunc = TRUNC_nonaligned * size; - assert(pivot != 0); + stack_entry stack[STACK_SIZE]; + int stacktop=0; + char *first,*last; + char *pivot=malloc(size); + size_t trunc=TRUNC_nonaligned*size; + assert(pivot!=0); - first = (char *) base; - last = first + (nmemb - 1) * size; + first=(char*)base; last=first+(nmemb-1)*size; - if ((size_t) (last - first) > trunc) { - char *ffirst = first, *llast = last; - while (1) { - /* Select pivot */ - { - char *mid = first + size * ((last - first) / size >> 1); - Pivot(SWAP_nonaligned, size); - memcpy(pivot, mid, size); - } - /* Partition. */ - Partition(SWAP_nonaligned, size); - /* Prepare to recurse/iterate. */ - Recurse(trunc)} + if (last-first>=trunc) { + char *ffirst=first, *llast=last; + while (1) { + /* Select pivot */ + { char * mid=first+size*((last-first)/size >> 1); + Pivot(SWAP_nonaligned,size); + memcpy(pivot,mid,size); + } + /* Partition. */ + Partition(SWAP_nonaligned,size); + /* Prepare to recurse/iterate. */ + Recurse(trunc) } - PreInsertion(SWAP_nonaligned, TRUNC_nonaligned, size); - Insertion(SWAP_nonaligned); - free(pivot); + } + PreInsertion(SWAP_nonaligned,TRUNC_nonaligned,size); + Insertion(SWAP_nonaligned); + free(pivot); } -static void -qsort_aligned(void *base, size_t nmemb, size_t size, - int (*compare) (const void *, const void *)) -{ +static void qsort_aligned(void *base, size_t nmemb, size_t size, + int (*compare)(const void *, const void *)) { - stack_entry stack[STACK_SIZE]; - int stacktop = 0; - char *first, *last; - char *pivot = malloc(size); - size_t trunc = TRUNC_aligned * size; - assert(pivot != 0); + stack_entry stack[STACK_SIZE]; + int stacktop=0; + char *first,*last; + char *pivot=malloc(size); + size_t trunc=TRUNC_aligned*size; + assert(pivot!=0); - first = (char *) base; - last = first + (nmemb - 1) * size; + first=(char*)base; last=first+(nmemb-1)*size; - if ((size_t) (last - first) > trunc) { - char *ffirst = first, *llast = last; - while (1) { - /* Select pivot */ - { - char *mid = first + size * ((last - first) / size >> 1); - Pivot(SWAP_aligned, size); - memcpy(pivot, mid, size); - } - /* Partition. */ - Partition(SWAP_aligned, size); - /* Prepare to recurse/iterate. */ - Recurse(trunc)} + if (last-first>=trunc) { + char *ffirst=first,*llast=last; + while (1) { + /* Select pivot */ + { char * mid=first+size*((last-first)/size >> 1); + Pivot(SWAP_aligned,size); + memcpy(pivot,mid,size); + } + /* Partition. */ + Partition(SWAP_aligned,size); + /* Prepare to recurse/iterate. */ + Recurse(trunc) } - PreInsertion(SWAP_aligned, TRUNC_aligned, size); - Insertion(SWAP_aligned); - free(pivot); + } + PreInsertion(SWAP_aligned,TRUNC_aligned,size); + Insertion(SWAP_aligned); + free(pivot); } -static void -qsort_words(void *base, size_t nmemb, - int (*compare) (const void *, const void *)) -{ +static void qsort_words(void *base, size_t nmemb, + int (*compare)(const void *, const void *)) { - stack_entry stack[STACK_SIZE]; - int stacktop = 0; - char *first, *last; - char *pivot = malloc(WORD_BYTES); - assert(pivot != 0); + stack_entry stack[STACK_SIZE]; + int stacktop=0; + char *first,*last; + char *pivot=malloc(WORD_BYTES); + assert(pivot!=0); - first = (char *) base; - last = first + (nmemb - 1) * WORD_BYTES; + first=(char*)base; last=first+(nmemb-1)*WORD_BYTES; - if (last - first > TRUNC_words) { - char *ffirst = first, *llast = last; - while (1) { + if (last-first>=TRUNC_words) { + char *ffirst=first, *llast=last; + while (1) { #ifdef DEBUG_QSORT - fprintf(stderr, "Doing %d:%d: ", - (first - (char *) base) / WORD_BYTES, - (last - (char *) base) / WORD_BYTES); +fprintf(stderr,"Doing %d:%d: ", + (first-(char*)base)/WORD_BYTES, + (last-(char*)base)/WORD_BYTES); #endif - /* Select pivot */ - { - char *mid = - first + WORD_BYTES * ((last - first) / (2 * WORD_BYTES)); - Pivot(SWAP_words, WORD_BYTES); - *(int *) pivot = *(int *) mid; - } + /* Select pivot */ + { char * mid=first+WORD_BYTES*((last-first) / (2*WORD_BYTES)); + Pivot(SWAP_words,WORD_BYTES); + *(int*)pivot=*(int*)mid; #ifdef DEBUG_QSORT - fprintf(stderr, "pivot=%d\n", *(int *) pivot); +fprintf(stderr,"pivot = %p = #%lu = %d\n", mid, (unsigned long)(((int*)mid)-((int*)base)), *(int*)mid); #endif - /* Partition. */ - Partition(SWAP_words, WORD_BYTES); - /* Prepare to recurse/iterate. */ - Recurse(TRUNC_words)} + } + /* Partition. */ + Partition(SWAP_words,WORD_BYTES); +#ifdef DEBUG_QSORT +fprintf(stderr, "after partitioning first=#%lu last=#%lu\n", (first-(char*)base)/4lu, (last-(char*)base)/4lu); +#endif + /* Prepare to recurse/iterate. */ + Recurse(TRUNC_words) } - PreInsertion(SWAP_words, (TRUNC_words / WORD_BYTES), WORD_BYTES); - /* Now do insertion sort. */ - last = ((char *) base) + nmemb * WORD_BYTES; - for (first = ((char *) base) + WORD_BYTES; first != last; - first += WORD_BYTES) { - /* Find the right place for |first|. My apologies for var reuse */ - int *pl = (int *) (first - WORD_BYTES), *pr = (int *) first; - *(int *) pivot = *(int *) first; - for (; compare(pl, pivot) > 0; pr = pl, --pl) { - *pr = *pl; - } - if (pr != (int *) first) - *pr = *(int *) pivot; - } - free(pivot); + } + PreInsertion(SWAP_words,(TRUNC_words/WORD_BYTES),WORD_BYTES); + /* Now do insertion sort. */ + last=((char*)base)+nmemb*WORD_BYTES; + for (first=((char*)base)+WORD_BYTES;first!=last;first+=WORD_BYTES) { + /* Find the right place for |first|. My apologies for var reuse */ + int *pl=(int*)(first-WORD_BYTES),*pr=(int*)first; + *(int*)pivot=*(int*)first; + for (;compare(pl,pivot)>0;pr=pl,--pl) { + *pr=*pl; } + if (pr!=(int*)first) *pr=*(int*)pivot; + } + free(pivot); } /* ---------------------------------------------------------------------- */ -void -qsort(void *base, size_t nmemb, size_t size, - int (*compare) (const void *, const void *)) -{ +extern void qsortG(void *base, size_t nmemb, size_t size, + int (*compare)(const void *, const void *)) { - if (nmemb <= 1) - return; - if (((uintptr_t) base | size) & (WORD_BYTES - 1)) - qsort_nonaligned(base, nmemb, size, compare); - else if (size != WORD_BYTES) - qsort_aligned(base, nmemb, size, compare); - else - qsort_words(base, nmemb, compare); + if (nmemb<=1) return; + if (((int)base|size)&(WORD_BYTES-1)) + qsort_nonaligned(base,nmemb,size,compare); + else if (size!=WORD_BYTES) + qsort_aligned(base,nmemb,size,compare); + else + qsort_words(base,nmemb,compare); } -#endif /* !SDL_qsort */ + +#endif /* HAVE_QSORT */ /* vi: set ts=4 sw=4 expandtab: */ + diff --git a/Engine/lib/sdl/src/stdlib/SDL_stdlib.c b/Engine/lib/sdl/src/stdlib/SDL_stdlib.c index 6723d4e2c..f5a152b49 100644 --- a/Engine/lib/sdl/src/stdlib/SDL_stdlib.c +++ b/Engine/lib/sdl/src/stdlib/SDL_stdlib.c @@ -34,7 +34,7 @@ double SDL_atan(double x) { -#ifdef HAVE_ATAN +#if defined(HAVE_ATAN) return atan(x); #else return SDL_uclibc_atan(x); @@ -90,7 +90,7 @@ SDL_asin(double val) double SDL_ceil(double x) { -#ifdef HAVE_CEIL +#if defined(HAVE_CEIL) return ceil(x); #else double integer = SDL_floor(x); @@ -127,7 +127,7 @@ SDL_cos(double x) float SDL_cosf(float x) { -#ifdef HAVE_COSF +#if defined(HAVE_COSF) return cosf(x); #else return (float)SDL_cos((double)x); @@ -199,7 +199,7 @@ SDL_sin(double x) float SDL_sinf(float x) { -#ifdef HAVE_SINF +#if defined(HAVE_SINF) return sinf(x); #else return (float)SDL_sin((double)x); @@ -248,14 +248,14 @@ SDL_tanf(float x) int SDL_abs(int x) { -#ifdef HAVE_ABS +#if defined(HAVE_ABS) return abs(x); #else return ((x) < 0 ? -(x) : (x)); #endif } -#ifdef HAVE_CTYPE_H +#if defined(HAVE_CTYPE_H) int SDL_isdigit(int x) { return isdigit(x); } int SDL_isspace(int x) { return isspace(x); } int SDL_toupper(int x) { return toupper(x); } @@ -279,7 +279,7 @@ __declspec(selectany) int _fltused = 1; #endif /* The optimizer on Visual Studio 2005 and later generates memcpy() calls */ -#if (_MSC_VER >= 1400) && defined(_WIN64) && !defined(_DEBUG) +#if (_MSC_VER >= 1400) && defined(_WIN64) && !defined(_DEBUG) && !(_MSC_VER >= 1900 && defined(_MT)) #include #pragma function(memcpy) diff --git a/Engine/lib/sdl/src/stdlib/SDL_string.c b/Engine/lib/sdl/src/stdlib/SDL_string.c index 5debb2285..debbebaed 100644 --- a/Engine/lib/sdl/src/stdlib/SDL_string.c +++ b/Engine/lib/sdl/src/stdlib/SDL_string.c @@ -1315,6 +1315,7 @@ static size_t SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string) { size_t length = 0; + size_t slen; if (info && info->width && (size_t)info->width > SDL_strlen(string)) { char fill = info->pad_zeroes ? '0' : ' '; @@ -1326,7 +1327,8 @@ SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *str } } - length += SDL_strlcpy(text, string, maxlen); + slen = SDL_strlcpy(text, string, maxlen); + length += SDL_min(slen, maxlen); if (info) { if (info->force_case == SDL_CASE_LOWER) { @@ -1402,10 +1404,11 @@ SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg) } value = (unsigned long) arg; len = SDL_PrintUnsignedLong(text, left, NULL, value); - text += len; if (len >= left) { + text += (left > 1) ? left - 1 : 0; left = SDL_min(left, 1); } else { + text += len; left -= len; } arg -= value; @@ -1422,10 +1425,11 @@ SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg) while (info->precision-- > 0) { value = (unsigned long) (arg * mult); len = SDL_PrintUnsignedLong(text, left, NULL, value); - text += len; if (len >= left) { + text += (left > 1) ? left - 1 : 0; left = SDL_min(left, 1); } else { + text += len; left -= len; } arg -= (double) value / mult; @@ -1458,10 +1462,11 @@ SDL_PrintFloat(char *text, size_t maxlen, SDL_FormatInfo *info, double arg) } } len = (size_t)width; - text += len; if (len >= left) { + text += (left > 1) ? left - 1 : 0; left = SDL_min(left, 1); } else { + text += len; left -= len; } while (len--) { @@ -1637,10 +1642,11 @@ SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, } ++fmt; } - text += len; if (len >= left) { + text += (left > 1) ? left - 1 : 0; left = SDL_min(left, 1); } else { + text += len; left -= len; } } else { diff --git a/Engine/lib/sdl/src/test/SDL_test_assert.c b/Engine/lib/sdl/src/test/SDL_test_assert.c index 98a84d386..ee2f13248 100644 --- a/Engine/lib/sdl/src/test/SDL_test_assert.c +++ b/Engine/lib/sdl/src/test/SDL_test_assert.c @@ -30,10 +30,10 @@ #include "SDL_test.h" /* Assert check message format */ -const char *SDLTest_AssertCheckFormat = "Assert '%s': %s"; +#define SDLTEST_ASSERT_CHECK_FORMAT "Assert '%s': %s" /* Assert summary message format */ -const char *SDLTest_AssertSummaryFormat = "Assert Summary: Total=%d Passed=%d Failed=%d"; +#define SDLTEST_ASSERT_SUMMARY_FORMAT "Assert Summary: Total=%d Passed=%d Failed=%d" /* ! \brief counts the failed asserts */ static Uint32 SDLTest_AssertsFailed = 0; @@ -77,12 +77,12 @@ int SDLTest_AssertCheck(int assertCondition, SDL_PRINTF_FORMAT_STRING const char if (assertCondition == ASSERT_FAIL) { SDLTest_AssertsFailed++; - SDLTest_LogError(SDLTest_AssertCheckFormat, logMessage, "Failed"); + SDLTest_LogError(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, "Failed"); } else { SDLTest_AssertsPassed++; - SDLTest_Log(SDLTest_AssertCheckFormat, logMessage, "Passed"); + SDLTest_Log(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, "Passed"); } return assertCondition; @@ -104,7 +104,7 @@ void SDLTest_AssertPass(SDL_PRINTF_FORMAT_STRING const char *assertDescription, /* Log pass message */ SDLTest_AssertsPassed++; - SDLTest_Log(SDLTest_AssertCheckFormat, logMessage, "Pass"); + SDLTest_Log(SDLTEST_ASSERT_CHECK_FORMAT, logMessage, "Pass"); } /* @@ -125,11 +125,11 @@ void SDLTest_LogAssertSummary() Uint32 totalAsserts = SDLTest_AssertsPassed + SDLTest_AssertsFailed; if (SDLTest_AssertsFailed == 0) { - SDLTest_Log(SDLTest_AssertSummaryFormat, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed); + SDLTest_Log(SDLTEST_ASSERT_SUMMARY_FORMAT, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed); } else { - SDLTest_LogError(SDLTest_AssertSummaryFormat, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed); + SDLTest_LogError(SDLTEST_ASSERT_SUMMARY_FORMAT, totalAsserts, SDLTest_AssertsPassed, SDLTest_AssertsFailed); } } diff --git a/Engine/lib/sdl/src/test/SDL_test_common.c b/Engine/lib/sdl/src/test/SDL_test_common.c index fee249cb9..1d0b005b5 100644 --- a/Engine/lib/sdl/src/test/SDL_test_common.c +++ b/Engine/lib/sdl/src/test/SDL_test_common.c @@ -1064,6 +1064,12 @@ SDLTest_PrintEvent(SDL_Event * event) case SDL_WINDOWEVENT_CLOSE: SDL_Log("SDL EVENT: Window %d closed", event->window.windowID); break; + case SDL_WINDOWEVENT_TAKE_FOCUS: + SDL_Log("SDL EVENT: Window %d take focus", event->window.windowID); + break; + case SDL_WINDOWEVENT_HIT_TEST: + SDL_Log("SDL EVENT: Window %d hit test", event->window.windowID); + break; default: SDL_Log("SDL EVENT: Window %d got unknown event %d", event->window.windowID, event->window.event); @@ -1368,6 +1374,24 @@ SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done) } } break; + case SDLK_o: + if (withControl) { + /* Ctrl-O (or Ctrl-Shift-O) changes window opacity. */ + SDL_Window *window = SDL_GetWindowFromID(event->key.windowID); + if (window) { + float opacity; + if (SDL_GetWindowOpacity(window, &opacity) == 0) { + if (withShift) { + opacity += 0.20f; + } else { + opacity -= 0.20f; + } + SDL_SetWindowOpacity(window, opacity); + } + } + } + break; + case SDLK_c: if (withControl) { /* Ctrl-C copy awesome text! */ diff --git a/Engine/lib/sdl/src/test/SDL_test_compare.c b/Engine/lib/sdl/src/test/SDL_test_compare.c index 45eb3c689..d06ead9f7 100644 --- a/Engine/lib/sdl/src/test/SDL_test_compare.c +++ b/Engine/lib/sdl/src/test/SDL_test_compare.c @@ -43,7 +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; + int sampleErrorX = 0, sampleErrorY = 0, sampleDist = 0; Uint8 R, G, B, A; Uint8 Rd, Gd, Bd, Ad; char imageFilename[128]; diff --git a/Engine/lib/sdl/src/test/SDL_test_harness.c b/Engine/lib/sdl/src/test/SDL_test_harness.c index fec34164c..4b86c7a0d 100644 --- a/Engine/lib/sdl/src/test/SDL_test_harness.c +++ b/Engine/lib/sdl/src/test/SDL_test_harness.c @@ -29,13 +29,13 @@ #include /* Invalid test name/description message format */ -const char *SDLTest_InvalidNameFormat = "(Invalid)"; +#define SDLTEST_INVALID_NAME_FORMAT "(Invalid)" /* Log summary message format */ -const char *SDLTest_LogSummaryFormat = "%s Summary: Total=%d Passed=%d Failed=%d Skipped=%d"; +#define SDLTEST_LOG_SUMMARY_FORMAT "%s Summary: Total=%d Passed=%d Failed=%d Skipped=%d" /* Final result message format */ -const char *SDLTest_FinalResultFormat = ">>> %s '%s': %s\n"; +#define SDLTEST_FINAL_RESULT_FORMAT ">>> %s '%s': %s\n" /* ! \brief Timeout for single test case execution */ static Uint32 SDLTest_TestCaseTimeout = 3600; @@ -239,7 +239,7 @@ SDLTest_RunTest(SDLTest_TestSuiteReference *testSuite, SDLTest_TestCaseReference if (!testCase->enabled && forceTestRun == SDL_FALSE) { - SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Skipped (Disabled)"); + SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, "Skipped (Disabled)"); return TEST_RESULT_SKIPPED; } @@ -256,7 +256,7 @@ SDLTest_RunTest(SDLTest_TestSuiteReference *testSuite, SDLTest_TestCaseReference if (testSuite->testSetUp) { testSuite->testSetUp(0x0); if (SDLTest_AssertSummaryToTestResult() == TEST_RESULT_FAILED) { - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Suite Setup", testSuite->name, "Failed"); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Suite Setup", testSuite->name, "Failed"); return TEST_RESULT_SETUP_FAILURE; } } @@ -298,13 +298,13 @@ SDLTest_RunTest(SDLTest_TestSuiteReference *testSuite, SDLTest_TestCaseReference /* Final log based on test execution result */ if (testCaseResult == TEST_SKIPPED) { /* Test was programatically skipped */ - SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Skipped (Programmatically)"); + SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, "Skipped (Programmatically)"); } else if (testCaseResult == TEST_STARTED) { /* Test did not return a TEST_COMPLETED value; assume it failed */ - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Failed (test started, but did not return TEST_COMPLETED)"); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, "Failed (test started, but did not return TEST_COMPLETED)"); } else if (testCaseResult == TEST_ABORTED) { /* Test was aborted early; assume it failed */ - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", testCase->name, "Failed (Aborted)"); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", testCase->name, "Failed (Aborted)"); } else { SDLTest_LogAssertSummary(); } @@ -326,7 +326,7 @@ void SDLTest_LogTestSuiteSummary(SDLTest_TestSuiteReference *testSuites) testSuite=&testSuites[suiteCounter]; suiteCounter++; SDLTest_Log("Test Suite %i - %s\n", suiteCounter, - (testSuite->name) ? testSuite->name : SDLTest_InvalidNameFormat); + (testSuite->name) ? testSuite->name : SDLTEST_INVALID_NAME_FORMAT); /* Loop over all test cases */ testCounter = 0; @@ -335,8 +335,8 @@ void SDLTest_LogTestSuiteSummary(SDLTest_TestSuiteReference *testSuites) testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter]; testCounter++; SDLTest_Log(" Test Case %i - %s: %s", testCounter, - (testCase->name) ? testCase->name : SDLTest_InvalidNameFormat, - (testCase->description) ? testCase->description : SDLTest_InvalidNameFormat); + (testCase->name) ? testCase->name : SDLTEST_INVALID_NAME_FORMAT, + (testCase->description) ? testCase->description : SDLTEST_INVALID_NAME_FORMAT); } } } @@ -396,7 +396,6 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user Uint32 testPassedCount = 0; Uint32 testSkippedCount = 0; Uint32 countSum = 0; - char *logFormat = (char *)SDLTest_LogSummaryFormat; SDLTest_TestCaseReference **failedTests; /* Sanitize test iterations */ @@ -493,7 +492,7 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user suiteCounter = 0; while(testSuites[suiteCounter]) { testSuite=(SDLTest_TestSuiteReference *)testSuites[suiteCounter]; - currentSuiteName = (char *)((testSuite->name) ? testSuite->name : SDLTest_InvalidNameFormat); + currentSuiteName = (char *)((testSuite->name) ? testSuite->name : SDLTEST_INVALID_NAME_FORMAT); suiteCounter++; /* Filter suite if flag set and we have a name */ @@ -523,7 +522,7 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user while(testSuite->testCases[testCounter]) { testCase=(SDLTest_TestCaseReference *)testSuite->testCases[testCounter]; - currentTestName = (char *)((testCase->name) ? testCase->name : SDLTest_InvalidNameFormat); + currentTestName = (char *)((testCase->name) ? testCase->name : SDLTEST_INVALID_NAME_FORMAT); testCounter++; /* Filter tests if flag set and we have a name */ @@ -551,7 +550,7 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user currentTestName); if (testCase->description != NULL && testCase->description[0] != '\0') { SDLTest_Log("Test Description: '%s'", - (testCase->description) ? testCase->description : SDLTest_InvalidNameFormat); + (testCase->description) ? testCase->description : SDLTEST_INVALID_NAME_FORMAT); } /* Loop over all iterations */ @@ -598,13 +597,13 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user /* Log final test result */ switch (testResult) { case TEST_RESULT_PASSED: - SDLTest_Log((char *)SDLTest_FinalResultFormat, "Test", currentTestName, "Passed"); + SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, "Passed"); break; case TEST_RESULT_FAILED: - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Test", currentTestName, "Failed"); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Test", currentTestName, "Failed"); break; case TEST_RESULT_NO_ASSERT: - SDLTest_LogError((char *)SDLTest_FinalResultFormat,"Test", currentTestName, "No Asserts"); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT,"Test", currentTestName, "No Asserts"); break; } @@ -628,13 +627,13 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user countSum = testPassedCount + testFailedCount + testSkippedCount; if (testFailedCount == 0) { - SDLTest_Log(logFormat, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount); - SDLTest_Log((char *)SDLTest_FinalResultFormat, "Suite", currentSuiteName, "Passed"); + SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount); + SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, "Passed"); } else { - SDLTest_LogError(logFormat, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount); - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Suite", currentSuiteName, "Failed"); + SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Suite", countSum, testPassedCount, testFailedCount, testSkippedCount); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Suite", currentSuiteName, "Failed"); } } @@ -653,14 +652,14 @@ int SDLTest_RunSuites(SDLTest_TestSuiteReference *testSuites[], const char *user if (totalTestFailedCount == 0) { runResult = 0; - SDLTest_Log(logFormat, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount); - SDLTest_Log((char *)SDLTest_FinalResultFormat, "Run /w seed", runSeed, "Passed"); + SDLTest_Log(SDLTEST_LOG_SUMMARY_FORMAT, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount); + SDLTest_Log(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, "Passed"); } else { runResult = 1; - SDLTest_LogError(logFormat, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount); - SDLTest_LogError((char *)SDLTest_FinalResultFormat, "Run /w seed", runSeed, "Failed"); + SDLTest_LogError(SDLTEST_LOG_SUMMARY_FORMAT, "Run", countSum, totalTestPassedCount, totalTestFailedCount, totalTestSkippedCount); + SDLTest_LogError(SDLTEST_FINAL_RESULT_FORMAT, "Run /w seed", runSeed, "Failed"); } /* Print repro steps for failed tests */ diff --git a/Engine/lib/sdl/src/test/SDL_test_log.c b/Engine/lib/sdl/src/test/SDL_test_log.c index 097372e7a..a2f857f26 100644 --- a/Engine/lib/sdl/src/test/SDL_test_log.c +++ b/Engine/lib/sdl/src/test/SDL_test_log.c @@ -55,12 +55,11 @@ char *SDLTest_TimestampToString(const time_t timestamp) time_t copy; static char buffer[64]; struct tm *local; - const char *fmt = "%x %X"; SDL_memset(buffer, 0, sizeof(buffer)); copy = timestamp; local = localtime(©); - strftime(buffer, sizeof(buffer), fmt, local); + strftime(buffer, sizeof(buffer), "%x %X", local); return buffer; } diff --git a/Engine/lib/sdl/src/thread/SDL_systhread.h b/Engine/lib/sdl/src/thread/SDL_systhread.h index f13f3e203..05a012536 100644 --- a/Engine/lib/sdl/src/thread/SDL_systhread.h +++ b/Engine/lib/sdl/src/thread/SDL_systhread.h @@ -60,6 +60,11 @@ extern SDL_TLSData *SDL_SYS_GetTLSData(); /* Set the thread local storage for this thread */ extern int SDL_SYS_SetTLSData(SDL_TLSData *data); +/* This is for internal SDL use, so we don't need #ifdefs everywhere. */ +extern SDL_Thread * +SDL_CreateThreadInternal(int (SDLCALL * fn) (void *), const char *name, + const size_t stacksize, void *data); + #endif /* _SDL_systhread_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/thread/SDL_thread.c b/Engine/lib/sdl/src/thread/SDL_thread.c index e66c5819c..ae865790a 100644 --- a/Engine/lib/sdl/src/thread/SDL_thread.c +++ b/Engine/lib/sdl/src/thread/SDL_thread.c @@ -26,6 +26,7 @@ #include "SDL_thread.h" #include "SDL_thread_c.h" #include "SDL_systhread.h" +#include "SDL_hints.h" #include "../SDL_error_c.h" @@ -304,15 +305,15 @@ SDL_RunThread(void *data) #endif #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD -DECLSPEC SDL_Thread *SDLCALL -SDL_CreateThread(int (SDLCALL * fn) (void *), - const char *name, void *data, +static SDL_Thread * +SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *), + const char *name, const size_t stacksize, void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread) #else -DECLSPEC SDL_Thread *SDLCALL -SDL_CreateThread(int (SDLCALL * fn) (void *), - const char *name, void *data) +static SDL_Thread * +SDL_CreateThreadWithStackSize(int (SDLCALL * fn) (void *), + const char *name, const size_t stacksize, void *data) #endif { SDL_Thread *thread; @@ -362,6 +363,8 @@ SDL_CreateThread(int (SDLCALL * fn) (void *), return (NULL); } + thread->stacksize = stacksize; + /* Create the thread and go! */ #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread); @@ -386,6 +389,50 @@ SDL_CreateThread(int (SDLCALL * fn) (void *), return (thread); } +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +DECLSPEC SDL_Thread *SDLCALL +SDL_CreateThread(int (SDLCALL * fn) (void *), + const char *name, void *data, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread) +#else +DECLSPEC SDL_Thread *SDLCALL +SDL_CreateThread(int (SDLCALL * fn) (void *), + const char *name, void *data) +#endif +{ + /* !!! FIXME: in 2.1, just make stackhint part of the usual API. */ + const char *stackhint = SDL_GetHint(SDL_HINT_THREAD_STACK_SIZE); + size_t stacksize = 0; + + /* If the SDL_HINT_THREAD_STACK_SIZE exists, use it */ + if (stackhint != NULL) { + char *endp = NULL; + const Sint64 hintval = SDL_strtoll(stackhint, &endp, 10); + if ((*stackhint != '\0') && (*endp == '\0')) { /* a valid number? */ + if (hintval > 0) { /* reject bogus values. */ + stacksize = (size_t) hintval; + } + } + } + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, pfnBeginThread, pfnEndThread); +#else + return SDL_CreateThreadWithStackSize(fn, name, stacksize, data); +#endif +} + +SDL_Thread * +SDL_CreateThreadInternal(int (SDLCALL * fn) (void *), const char *name, + const size_t stacksize, void *data) { +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + return SDL_CreateThreadWithStackSize(fn, name, stacksize, data, NULL, NULL); +#else + return SDL_CreateThreadWithStackSize(fn, name, stacksize, data); +#endif +} + SDL_threadID SDL_GetThreadID(SDL_Thread * thread) { diff --git a/Engine/lib/sdl/src/thread/SDL_thread_c.h b/Engine/lib/sdl/src/thread/SDL_thread_c.h index a283a0e2c..554325d6d 100644 --- a/Engine/lib/sdl/src/thread/SDL_thread_c.h +++ b/Engine/lib/sdl/src/thread/SDL_thread_c.h @@ -59,6 +59,7 @@ struct SDL_Thread SDL_atomic_t state; /* SDL_THREAD_STATE_* */ SDL_error errbuf; char *name; + size_t stacksize; /* 0 for default, >0 for user-specified stack size. */ void *data; }; diff --git a/Engine/lib/sdl/src/thread/psp/SDL_systhread.c b/Engine/lib/sdl/src/thread/psp/SDL_systhread.c index ab8aff376..c6003b8ed 100644 --- a/Engine/lib/sdl/src/thread/psp/SDL_systhread.c +++ b/Engine/lib/sdl/src/thread/psp/SDL_systhread.c @@ -52,8 +52,8 @@ int SDL_SYS_CreateThread(SDL_Thread *thread, void *args) priority = status.currentPriority; } - thread->handle = sceKernelCreateThread("SDL thread", ThreadEntry, - priority, 0x8000, + thread->handle = sceKernelCreateThread(thread->name, ThreadEntry, + priority, thread->stacksize ? ((int) thread->stacksize) : 0x8000, PSP_THREAD_ATTR_VFPU, NULL); if (thread->handle < 0) { return SDL_SetError("sceKernelCreateThread() failed"); diff --git a/Engine/lib/sdl/src/thread/pthread/SDL_systhread.c b/Engine/lib/sdl/src/thread/pthread/SDL_systhread.c index 22f7bd57b..4958f6fb9 100644 --- a/Engine/lib/sdl/src/thread/pthread/SDL_systhread.c +++ b/Engine/lib/sdl/src/thread/pthread/SDL_systhread.c @@ -45,7 +45,6 @@ #include "SDL_platform.h" #include "SDL_thread.h" -#include "SDL_hints.h" #include "../SDL_thread_c.h" #include "../SDL_systhread.h" #ifdef __ANDROID__ @@ -87,7 +86,6 @@ int SDL_SYS_CreateThread(SDL_Thread * thread, void *args) { pthread_attr_t type; - 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__) @@ -108,12 +106,9 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) } 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); - } + /* Set caller-requested stack size. Otherwise: use the system default. */ + if (thread->stacksize) { + pthread_attr_setstacksize(&type, (size_t) thread->stacksize); } /* Create the thread and go! */ @@ -127,10 +122,10 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) void SDL_SYS_SetupThread(const char *name) { -#if !defined(__ANDROID__) && !defined(__NACL__) +#if !defined(__NACL__) int i; sigset_t mask; -#endif /* !__ANDROID__ && !__NACL__ */ +#endif /* !__NACL__ */ if (name != NULL) { #if defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__LINUX__) @@ -160,14 +155,14 @@ SDL_SYS_SetupThread(const char *name) } /* NativeClient does not yet support signals.*/ -#if !defined(__ANDROID__) && !defined(__NACL__) +#if !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 /* !__ANDROID__ && !__NACL__ */ +#endif /* !__NACL__ */ #ifdef PTHREAD_CANCEL_ASYNCHRONOUS @@ -204,6 +199,10 @@ SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) if (setpriority(PRIO_PROCESS, syscall(SYS_gettid), value) < 0) { /* Note that this fails if you're trying to set high priority and you don't have root permission. BUT DON'T RUN AS ROOT! + + You can grant the ability to increase thread priority by + running the following command on your application binary: + sudo setcap 'cap_sys_nice=eip' */ return SDL_SetError("setpriority() failed"); } diff --git a/Engine/lib/sdl/src/thread/stdcpp/SDL_systhread.cpp b/Engine/lib/sdl/src/thread/stdcpp/SDL_systhread.cpp index 219c67e93..6e5ef473e 100644 --- a/Engine/lib/sdl/src/thread/stdcpp/SDL_systhread.cpp +++ b/Engine/lib/sdl/src/thread/stdcpp/SDL_systhread.cpp @@ -48,6 +48,7 @@ int SDL_SYS_CreateThread(SDL_Thread * thread, void *args) { try { + // !!! FIXME: no way to set a thread stack size here. std::thread cpp_thread(RunThread, args); thread->handle = (void *) new std::thread(std::move(cpp_thread)); return 0; diff --git a/Engine/lib/sdl/src/thread/windows/SDL_systhread.c b/Engine/lib/sdl/src/thread/windows/SDL_systhread.c index 308145e30..20a4bd6e2 100644 --- a/Engine/lib/sdl/src/thread/windows/SDL_systhread.c +++ b/Engine/lib/sdl/src/thread/windows/SDL_systhread.c @@ -24,6 +24,7 @@ /* Win32 thread management routines for SDL */ +#include "SDL_hints.h" #include "SDL_thread.h" #include "../SDL_thread_c.h" #include "../SDL_systhread.h" @@ -33,6 +34,10 @@ /* We'll use the C library from this DLL */ #include +#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION +#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 +#endif + /* Cygwin gcc-3 ... MingW64 (even with a i386 host) does this like MSVC. */ #if (defined(__MINGW32__) && (__GNUC__ < 4)) typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, @@ -121,6 +126,7 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) #endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ pThreadStartParms pThreadParms = (pThreadStartParms) SDL_malloc(sizeof(tThreadStartParms)); + const DWORD flags = thread->stacksize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0; if (!pThreadParms) { return SDL_OutOfMemory(); } @@ -129,15 +135,18 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) /* Also save the real parameters we have to pass to thread function */ pThreadParms->args = args; + /* thread->stacksize == 0 means "system default", same as win32 expects */ if (pfnBeginThread) { unsigned threadid = 0; thread->handle = (SYS_ThreadHandle) - ((size_t) pfnBeginThread(NULL, 0, RunThreadViaBeginThreadEx, - pThreadParms, 0, &threadid)); + ((size_t) pfnBeginThread(NULL, (unsigned int) thread->stacksize, + RunThreadViaBeginThreadEx, + pThreadParms, flags, &threadid)); } else { DWORD threadid = 0; - thread->handle = CreateThread(NULL, 0, RunThreadViaCreateThread, - pThreadParms, 0, &threadid); + thread->handle = CreateThread(NULL, thread->stacksize, + RunThreadViaCreateThread, + pThreadParms, flags, &threadid); } if (thread->handle == NULL) { return SDL_SetError("Not enough resources to create thread"); @@ -145,9 +154,6 @@ SDL_SYS_CreateThread(SDL_Thread * thread, void *args) return 0; } -#if 0 /* !!! FIXME: revisit this later. See https://bugzilla.libsdl.org/show_bug.cgi?id=2089 */ -#ifdef _MSC_VER -#pragma warning(disable : 4733) #pragma pack(push,8) typedef struct tagTHREADNAME_INFO { @@ -158,48 +164,26 @@ typedef struct tagTHREADNAME_INFO } THREADNAME_INFO; #pragma pack(pop) -static EXCEPTION_DISPOSITION -ignore_exception(void *a, void *b, void *c, void *d) -{ - return ExceptionContinueExecution; -} -#endif -#endif - void SDL_SYS_SetupThread(const char *name) { - if (name != NULL) { - #if 0 /* !!! FIXME: revisit this later. See https://bugzilla.libsdl.org/show_bug.cgi?id=2089 */ - #if (defined(_MSC_VER) && defined(_M_IX86)) - /* This magic tells the debugger to name a thread if it's listening. - The inline asm sets up SEH (__try/__except) without C runtime - support. See Microsoft Systems Journal, January 1997: - http://www.microsoft.com/msj/0197/exception/exception.aspx */ - INT_PTR handler = (INT_PTR) ignore_exception; + if ((name != NULL) && IsDebuggerPresent()) { THREADNAME_INFO inf; + /* C# and friends will try to catch this Exception, let's avoid it. */ + if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, SDL_FALSE)) { + return; + } + + /* This magic tells the debugger to name a thread if it's listening. */ + SDL_zero(inf); inf.dwType = 0x1000; inf.szName = name; inf.dwThreadID = (DWORD) -1; inf.dwFlags = 0; - __asm { /* set up SEH */ - push handler - push fs:[0] - mov fs:[0],esp - } - - /* The program itself should ignore this bogus exception. */ - RaiseException(0x406D1388, 0, sizeof(inf)/sizeof(DWORD), (DWORD*)&inf); - - __asm { /* tear down SEH. */ - mov eax,[esp] - mov fs:[0], eax - add esp, 8 - } - #endif - #endif + /* The debugger catches this, renames the thread, continues on. */ + RaiseException(0x406D1388, 0, sizeof(inf) / sizeof(ULONG), (const ULONG_PTR*) &inf); } } @@ -230,11 +214,7 @@ SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) void SDL_SYS_WaitThread(SDL_Thread * thread) { -#if __WINRT__ WaitForSingleObjectEx(thread->handle, INFINITE, FALSE); -#else - WaitForSingleObject(thread->handle, INFINITE); -#endif CloseHandle(thread->handle); } diff --git a/Engine/lib/sdl/src/timer/SDL_timer.c b/Engine/lib/sdl/src/timer/SDL_timer.c index 6189ab8b5..abe968e86 100644 --- a/Engine/lib/sdl/src/timer/SDL_timer.c +++ b/Engine/lib/sdl/src/timer/SDL_timer.c @@ -24,7 +24,7 @@ #include "SDL_timer_c.h" #include "SDL_atomic.h" #include "SDL_cpuinfo.h" -#include "SDL_thread.h" +#include "../thread/SDL_systhread.h" /* #define DEBUG_TIMERS */ @@ -35,7 +35,7 @@ typedef struct _SDL_Timer void *param; Uint32 interval; Uint32 scheduled; - volatile SDL_bool canceled; + SDL_atomic_t canceled; struct _SDL_Timer *next; } SDL_Timer; @@ -60,9 +60,9 @@ typedef struct { /* Data used to communicate with the timer thread */ SDL_SpinLock lock; SDL_sem *sem; - SDL_Timer * volatile pending; - SDL_Timer * volatile freelist; - volatile SDL_bool active; + SDL_Timer *pending; + SDL_Timer *freelist; + SDL_atomic_t active; /* List of timers - this is only touched by the timer thread */ SDL_Timer *timers; @@ -138,7 +138,7 @@ SDL_TimerThread(void *_data) freelist_tail = NULL; /* Check to see if we're still running, after maintenance */ - if (!data->active) { + if (!SDL_AtomicGet(&data->active)) { break; } @@ -160,7 +160,7 @@ SDL_TimerThread(void *_data) /* We're going to do something with this timer */ data->timers = current->next; - if (current->canceled) { + if (SDL_AtomicGet(¤t->canceled)) { interval = 0; } else { interval = current->callback(current->interval, current->param); @@ -179,7 +179,7 @@ SDL_TimerThread(void *_data) } freelist_tail = current; - current->canceled = SDL_TRUE; + SDL_AtomicSet(¤t->canceled, 1); } } @@ -207,7 +207,7 @@ SDL_TimerInit(void) { SDL_TimerData *data = &SDL_timer_data; - if (!data->active) { + if (!SDL_AtomicGet(&data->active)) { const char *name = "SDLTimer"; data->timermap_lock = SDL_CreateMutex(); if (!data->timermap_lock) { @@ -220,18 +220,10 @@ SDL_TimerInit(void) return -1; } - data->active = SDL_TRUE; - /* !!! FIXME: this is nasty. */ -#if defined(__WIN32__) && !defined(HAVE_LIBC) -#undef SDL_CreateThread -#if SDL_DYNAMIC_API - data->thread = SDL_CreateThread_REAL(SDL_TimerThread, name, data, NULL, NULL); -#else - data->thread = SDL_CreateThread(SDL_TimerThread, name, data, NULL, NULL); -#endif -#else - data->thread = SDL_CreateThread(SDL_TimerThread, name, data); -#endif + SDL_AtomicSet(&data->active, 1); + + /* Timer threads use a callback into the app, so we can't set a limited stack size here. */ + data->thread = SDL_CreateThreadInternal(SDL_TimerThread, name, 0, data); if (!data->thread) { SDL_TimerQuit(); return -1; @@ -249,9 +241,7 @@ SDL_TimerQuit(void) SDL_Timer *timer; SDL_TimerMap *entry; - if (data->active) { - data->active = SDL_FALSE; - + if (SDL_AtomicCAS(&data->active, 1, 0)) { /* active? Move to inactive. */ /* Shutdown the timer thread */ if (data->thread) { SDL_SemPost(data->sem); @@ -291,21 +281,14 @@ SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) SDL_Timer *timer; SDL_TimerMap *entry; - if (!data->active) { - int status = 0; - - SDL_AtomicLock(&data->lock); - if (!data->active) { - status = SDL_TimerInit(); - } - SDL_AtomicUnlock(&data->lock); - - if (status < 0) { + SDL_AtomicLock(&data->lock); + if (!SDL_AtomicGet(&data->active)) { + if (SDL_TimerInit() < 0) { + SDL_AtomicUnlock(&data->lock); return 0; } } - SDL_AtomicLock(&data->lock); timer = data->freelist; if (timer) { data->freelist = timer->next; @@ -326,7 +309,7 @@ SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param) timer->param = param; timer->interval = interval; timer->scheduled = SDL_GetTicks() + interval; - timer->canceled = SDL_FALSE; + SDL_AtomicSet(&timer->canceled, 0); entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry)); if (!entry) { @@ -377,8 +360,8 @@ SDL_RemoveTimer(SDL_TimerID id) SDL_UnlockMutex(data->timermap_lock); if (entry) { - if (!entry->timer->canceled) { - entry->timer->canceled = SDL_TRUE; + if (!SDL_AtomicGet(&entry->timer->canceled)) { + SDL_AtomicSet(&entry->timer->canceled, 1); canceled = SDL_TRUE; } SDL_free(entry); diff --git a/Engine/lib/sdl/src/timer/windows/SDL_systimer.c b/Engine/lib/sdl/src/timer/windows/SDL_systimer.c index abfbcb99a..5c9121a51 100644 --- a/Engine/lib/sdl/src/timer/windows/SDL_systimer.c +++ b/Engine/lib/sdl/src/timer/windows/SDL_systimer.c @@ -107,10 +107,8 @@ SDL_TicksInit(void) void SDL_TicksQuit(void) { - if (!hires_timer_available) { - SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION, - SDL_TimerResolutionChanged, NULL); - } + SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION, + SDL_TimerResolutionChanged, NULL); SDL_SetSystemTimerResolution(0); /* always release our timer resolution request. */ @@ -189,6 +187,10 @@ SDL_Delay(Uint32 ms) } WaitForSingleObjectEx(mutex, ms, FALSE); #else + if (!ticks_started) { + SDL_TicksInit(); + } + Sleep(ms); #endif } diff --git a/Engine/lib/sdl/src/video/SDL_blit_copy.c b/Engine/lib/sdl/src/video/SDL_blit_copy.c index 7b9a91ffd..674650dd9 100644 --- a/Engine/lib/sdl/src/video/SDL_blit_copy.c +++ b/Engine/lib/sdl/src/video/SDL_blit_copy.c @@ -109,10 +109,20 @@ SDL_BlitCopy(SDL_BlitInfo * info) overlap = (src < (dst + h*dstskip)); } if (overlap) { - while (h--) { - SDL_memmove(dst, src, w); - src += srcskip; - dst += dstskip; + if ( dst < src ) { + while ( h-- ) { + SDL_memmove(dst, src, w); + src += srcskip; + dst += dstskip; + } + } else { + src += ((h-1) * srcskip); + dst += ((h-1) * dstskip); + while ( h-- ) { + SDL_memmove(dst, src, w); + src -= srcskip; + dst -= dstskip; + } } return; } diff --git a/Engine/lib/sdl/src/video/SDL_blit_slow.c b/Engine/lib/sdl/src/video/SDL_blit_slow.c index 3a462f6e2..02ab41de7 100644 --- a/Engine/lib/sdl/src/video/SDL_blit_slow.c +++ b/Engine/lib/sdl/src/video/SDL_blit_slow.c @@ -46,6 +46,8 @@ SDL_Blit_Slow(SDL_BlitInfo * info) SDL_PixelFormat *dst_fmt = info->dst_fmt; int srcbpp = src_fmt->BytesPerPixel; int dstbpp = dst_fmt->BytesPerPixel; + Uint32 rgbmask = ~src_fmt->Amask; + Uint32 ckey = info->colorkey & rgbmask; srcy = 0; posy = 0; @@ -85,7 +87,7 @@ SDL_Blit_Slow(SDL_BlitInfo * info) srcpixel = (srcR << src_fmt->Rshift) | (srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift); } - if (srcpixel == info->colorkey) { + if ((srcpixel & rgbmask) == ckey) { posx += incx; dst += dstbpp; continue; @@ -127,6 +129,7 @@ SDL_Blit_Slow(SDL_BlitInfo * info) dstR = srcR + ((255 - srcA) * dstR) / 255; dstG = srcG + ((255 - srcA) * dstG) / 255; dstB = srcB + ((255 - srcA) * dstB) / 255; + dstA = srcA + ((255 - srcA) * dstA) / 255; break; case SDL_COPY_ADD: dstR = srcR + dstR; diff --git a/Engine/lib/sdl/src/video/SDL_bmp.c b/Engine/lib/sdl/src/video/SDL_bmp.c index f80f93696..2d9cf240b 100644 --- a/Engine/lib/sdl/src/video/SDL_bmp.c +++ b/Engine/lib/sdl/src/video/SDL_bmp.c @@ -32,6 +32,7 @@ This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp. */ +#include "SDL_hints.h" #include "SDL_video.h" #include "SDL_assert.h" #include "SDL_endian.h" @@ -47,6 +48,11 @@ #define BI_BITFIELDS 3 #endif +/* Logical color space values for BMP files */ +#ifndef LCS_WINDOWS_COLOR_SPACE +/* 0x57696E20 == "Win " */ +#define LCS_WINDOWS_COLOR_SPACE 0x57696E20 +#endif static void CorrectAlphaChannel(SDL_Surface *surface) { @@ -457,6 +463,8 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) int i, pad; SDL_Surface *surface; Uint8 *bits; + SDL_bool save32bit = SDL_FALSE; + SDL_bool saveLegacyBMP = SDL_FALSE; /* The Win32 BMP file header (14 bytes) */ char magic[2] = { 'B', 'M' }; @@ -478,14 +486,24 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) Uint32 biClrUsed; Uint32 biClrImportant; + /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */ + Uint32 bV4RedMask = 0; + Uint32 bV4GreenMask = 0; + Uint32 bV4BlueMask = 0; + Uint32 bV4AlphaMask = 0; + Uint32 bV4CSType = 0; + Sint32 bV4Endpoints[3 * 3] = {0}; + Uint32 bV4GammaRed = 0; + Uint32 bV4GammaGreen = 0; + Uint32 bV4GammaBlue = 0; + /* Make sure we have somewhere to save */ surface = NULL; if (dst) { - SDL_bool save32bit = SDL_FALSE; #ifdef SAVE_32BIT_BMP /* We can save alpha information in a 32-bit BMP */ - if (saveme->map->info.flags & SDL_COPY_COLORKEY || - saveme->format->Amask) { + if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask || + saveme->map->info.flags & SDL_COPY_COLORKEY)) { save32bit = SDL_TRUE; } #endif /* SAVE_32BIT_BMP */ @@ -497,7 +515,7 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) SDL_SetError("%d bpp BMP files not supported", saveme->format->BitsPerPixel); } - } else if ((saveme->format->BitsPerPixel == 24) && + } else if ((saveme->format->BitsPerPixel == 24) && !save32bit && #if SDL_BYTEORDER == SDL_LIL_ENDIAN (saveme->format->Rmask == 0x00FF0000) && (saveme->format->Gmask == 0x0000FF00) && @@ -515,13 +533,7 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) /* If the surface has a colorkey or alpha channel we'll save a 32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */ if (save32bit) { - SDL_InitFormat(&format, -#if SDL_BYTEORDER == SDL_LIL_ENDIAN - SDL_PIXELFORMAT_ARGB8888 -#else - SDL_PIXELFORMAT_BGRA8888 -#endif - ); + SDL_InitFormat(&format, SDL_PIXELFORMAT_BGRA32); } else { SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24); } @@ -537,6 +549,10 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) return -1; } + if (save32bit) { + saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_FALSE); + } + if (surface && (SDL_LockSurface(surface) == 0)) { const int bw = surface->w * surface->format->BytesPerPixel; @@ -572,6 +588,21 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) } biClrImportant = 0; + /* Set the BMP info values for the version 4 header */ + if (save32bit && !saveLegacyBMP) { + biSize = 108; + biCompression = BI_BITFIELDS; + /* The BMP format is always little endian, these masks stay the same */ + bV4RedMask = 0x00ff0000; + bV4GreenMask = 0x0000ff00; + bV4BlueMask = 0x000000ff; + bV4AlphaMask = 0xff000000; + bV4CSType = LCS_WINDOWS_COLOR_SPACE; + bV4GammaRed = 0; + bV4GammaGreen = 0; + bV4GammaBlue = 0; + } + /* Write the BMP info values */ SDL_WriteLE32(dst, biSize); SDL_WriteLE32(dst, biWidth); @@ -585,6 +616,21 @@ SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) SDL_WriteLE32(dst, biClrUsed); SDL_WriteLE32(dst, biClrImportant); + /* Write the BMP info values for the version 4 header */ + if (save32bit && !saveLegacyBMP) { + SDL_WriteLE32(dst, bV4RedMask); + SDL_WriteLE32(dst, bV4GreenMask); + SDL_WriteLE32(dst, bV4BlueMask); + SDL_WriteLE32(dst, bV4AlphaMask); + SDL_WriteLE32(dst, bV4CSType); + for (i = 0; i < 3 * 3; i++) { + SDL_WriteLE32(dst, bV4Endpoints[i]); + } + SDL_WriteLE32(dst, bV4GammaRed); + SDL_WriteLE32(dst, bV4GammaGreen); + SDL_WriteLE32(dst, bV4GammaBlue); + } + /* Write the palette (in BGR color order) */ if (surface->format->palette) { SDL_Color *colors; diff --git a/Engine/lib/sdl/src/video/SDL_egl.c b/Engine/lib/sdl/src/video/SDL_egl.c index bfd4affb9..c90380566 100644 --- a/Engine/lib/sdl/src/video/SDL_egl.c +++ b/Engine/lib/sdl/src/video/SDL_egl.c @@ -161,7 +161,7 @@ int SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_display) { void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */ - char *path = NULL; + const char *path = NULL; #if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT const char *d3dcompiler; #endif @@ -558,7 +558,8 @@ int SDL_EGL_GetSwapInterval(_THIS) { if (!_this->egl_data) { - return SDL_SetError("EGL not initialized"); + SDL_SetError("EGL not initialized"); + return 0; } return _this->egl_data->egl_swapinterval; diff --git a/Engine/lib/sdl/src/video/SDL_surface.c b/Engine/lib/sdl/src/video/SDL_surface.c index dae07f285..9d52e5ca4 100644 --- a/Engine/lib/sdl/src/video/SDL_surface.c +++ b/Engine/lib/sdl/src/video/SDL_surface.c @@ -27,27 +27,20 @@ #include "SDL_pixels_c.h" /* Public routines */ + /* - * Create an empty RGB surface of the appropriate depth + * Create an empty RGB surface of the appropriate depth using the given + * enum SDL_PIXELFORMAT_* format */ SDL_Surface * -SDL_CreateRGBSurface(Uint32 flags, - int width, int height, int depth, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) +SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, + Uint32 format) { SDL_Surface *surface; - Uint32 format; /* The flags are no longer used, make the compiler happy */ (void)flags; - /* Get the pixel format */ - format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); - if (format == SDL_PIXELFORMAT_UNKNOWN) { - SDL_SetError("Unknown pixel format"); - return NULL; - } - /* Allocate the surface */ surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface)); if (surface == NULL) { @@ -105,7 +98,7 @@ SDL_CreateRGBSurface(Uint32 flags, } /* By default surface with an alpha mask are set up for blending */ - if (Amask) { + if (surface->format->Amask) { SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND); } @@ -114,6 +107,26 @@ SDL_CreateRGBSurface(Uint32 flags, return surface; } +/* + * Create an empty RGB surface of the appropriate depth + */ +SDL_Surface * +SDL_CreateRGBSurface(Uint32 flags, + int width, int height, int depth, + Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) +{ + Uint32 format; + + /* Get the pixel format */ + format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); + if (format == SDL_PIXELFORMAT_UNKNOWN) { + SDL_SetError("Unknown pixel format"); + return NULL; + } + + return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format); +} + /* * Create an RGB surface from an existing memory buffer */ @@ -125,8 +138,30 @@ SDL_CreateRGBSurfaceFrom(void *pixels, { SDL_Surface *surface; - surface = - SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask); + surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask); + if (surface != NULL) { + surface->flags |= SDL_PREALLOC; + surface->pixels = pixels; + surface->w = width; + surface->h = height; + surface->pitch = pitch; + SDL_SetClipRect(surface, NULL); + } + return surface; +} + +/* + * Create an RGB surface from an existing memory buffer using the given given + * enum SDL_PIXELFORMAT_* format + */ +SDL_Surface * +SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, + int width, int height, int depth, int pitch, + Uint32 format) +{ + SDL_Surface *surface; + + surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format); if (surface != NULL) { surface->flags |= SDL_PREALLOC; surface->pixels = pixels; diff --git a/Engine/lib/sdl/src/video/SDL_sysvideo.h b/Engine/lib/sdl/src/video/SDL_sysvideo.h index 77426c3eb..cd2ed2a7e 100644 --- a/Engine/lib/sdl/src/video/SDL_sysvideo.h +++ b/Engine/lib/sdl/src/video/SDL_sysvideo.h @@ -86,6 +86,8 @@ struct SDL_Window SDL_DisplayMode fullscreen_mode; + float opacity; + float brightness; Uint16 *gamma; Uint16 *saved_gamma; /* (just offset into gamma) */ @@ -95,6 +97,7 @@ struct SDL_Window SDL_bool is_hiding; SDL_bool is_destroying; + SDL_bool is_dropping; /* drag/drop in progress, expecting SDL_SendDropComplete(). */ SDL_WindowShaper *shaper; @@ -175,6 +178,11 @@ struct SDL_VideoDevice */ int (*GetDisplayDPI) (_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi); + /* + * Get the usable bounds of a display (bounds minus menubar or whatever) + */ + int (*GetDisplayUsableBounds) (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); + /* * Get a list of the available display modes for a display. */ @@ -200,6 +208,10 @@ struct SDL_VideoDevice void (*SetWindowSize) (_THIS, SDL_Window * window); void (*SetWindowMinimumSize) (_THIS, SDL_Window * window); void (*SetWindowMaximumSize) (_THIS, SDL_Window * window); + int (*GetWindowBordersSize) (_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right); + int (*SetWindowOpacity) (_THIS, SDL_Window * window, float opacity); + int (*SetWindowModalFor) (_THIS, SDL_Window * modal_window, SDL_Window * parent_window); + int (*SetWindowInputFocus) (_THIS, SDL_Window * window); void (*ShowWindow) (_THIS, SDL_Window * window); void (*HideWindow) (_THIS, SDL_Window * window); void (*RaiseWindow) (_THIS, SDL_Window * window); @@ -207,6 +219,7 @@ struct SDL_VideoDevice void (*MinimizeWindow) (_THIS, SDL_Window * window); void (*RestoreWindow) (_THIS, SDL_Window * window); void (*SetWindowBordered) (_THIS, SDL_Window * window, SDL_bool bordered); + void (*SetWindowResizable) (_THIS, SDL_Window * window, SDL_bool resizable); void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp); int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp); diff --git a/Engine/lib/sdl/src/video/SDL_video.c b/Engine/lib/sdl/src/video/SDL_video.c index 511b4c087..0a21ef5fc 100644 --- a/Engine/lib/sdl/src/video/SDL_video.c +++ b/Engine/lib/sdl/src/video/SDL_video.c @@ -55,6 +55,10 @@ #undef CreateWindow #endif +#ifdef __EMSCRIPTEN__ +#include +#endif + /* Available video drivers */ static VideoBootStrap *bootstrap[] = { #if SDL_VIDEO_DRIVER_COCOA @@ -177,7 +181,7 @@ ShouldUseTextureFramebuffer() /* See if the user or application wants a specific behavior */ hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); if (hint) { - if (*hint == '0') { + if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) { return SDL_FALSE; } else { return SDL_TRUE; @@ -254,6 +258,8 @@ SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * f /* Check to see if there's a specific driver requested */ if (hint && *hint != '0' && *hint != '1' && + SDL_strcasecmp(hint, "true") != 0 && + SDL_strcasecmp(hint, "false") != 0 && SDL_strcasecmp(hint, "software") != 0) { for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { SDL_RendererInfo info; @@ -443,10 +449,8 @@ int SDL_VideoInit(const char *driver_name) { SDL_VideoDevice *video; - const char *hint; int index; int i; - SDL_bool allow_screensaver; /* Check to make sure we don't overwrite '_this' */ if (_this != NULL) { @@ -534,13 +538,7 @@ SDL_VideoInit(const char *driver_name) joystick, or passively watching a movie. Things that use SDL but function more like a normal desktop app should explicitly reenable the screensaver. */ - hint = SDL_GetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER); - if (hint) { - allow_screensaver = SDL_atoi(hint) ? SDL_TRUE : SDL_FALSE; - } else { - allow_screensaver = SDL_FALSE; - } - if (!allow_screensaver) { + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, SDL_FALSE)) { SDL_DisableScreenSaver(); } @@ -684,7 +682,26 @@ SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect) rect->w = display->current_mode.w; rect->h = display->current_mode.h; } - return 0; + return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */ +} + +int SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect) +{ + CHECK_DISPLAY_INDEX(displayIndex, -1); + + if (rect) { + SDL_VideoDisplay *display = &_this->displays[displayIndex]; + + if (_this->GetDisplayUsableBounds) { + if (_this->GetDisplayUsableBounds(_this, display, rect) == 0) { + return 0; + } + } + + /* Oh well, just give the entire display bounds. */ + return SDL_GetDisplayBounds(displayIndex, rect); + } + return 0; /* !!! FIXME: should this be an error if (rect==NULL) ? */ } int @@ -700,7 +717,9 @@ SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi) if (_this->GetDisplayDPI(_this, display, ddpi, hdpi, vdpi) == 0) { return 0; } - } + } else { + return SDL_Unsupported(); + } return -1; } @@ -1285,16 +1304,11 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) } #define CREATE_FLAGS \ - (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI) + (SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_POPUP_MENU | SDL_WINDOW_UTILITY | SDL_WINDOW_TOOLTIP) static void SDL_FinishWindowCreation(SDL_Window *window, Uint32 flags) { - window->windowed.x = window->x; - window->windowed.y = window->y; - window->windowed.w = window->w; - window->windowed.h = window->h; - if (flags & SDL_WINDOW_MAXIMIZED) { SDL_MaximizeWindow(window); } @@ -1316,7 +1330,6 @@ SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) { SDL_Window *window; - const char *hint; if (!_this) { /* Initialize the video system if needed */ @@ -1325,6 +1338,11 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) } } + if ( (((flags & SDL_WINDOW_UTILITY) != 0) + ((flags & SDL_WINDOW_TOOLTIP) != 0) + ((flags & SDL_WINDOW_POPUP_MENU) != 0)) > 1 ) { + SDL_SetError("Conflicting window flags specified"); + return NULL; + } + /* Some platforms can't create zero-sized windows */ if (w < 1) { w = 1; @@ -1341,7 +1359,9 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) /* Some platforms have OpenGL enabled by default */ #if (SDL_VIDEO_OPENGL && __MACOSX__) || __IPHONEOS__ || __ANDROID__ || __NACL__ - flags |= SDL_WINDOW_OPENGL; + if (SDL_strcmp(_this->name, "dummy") != 0) { + flags |= SDL_WINDOW_OPENGL; + } #endif if (flags & SDL_WINDOW_OPENGL) { if (!_this->GL_CreateContext) { @@ -1357,8 +1377,7 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) * SDL_WINDOW_ALLOW_HIGHDPI flag. */ if (flags & SDL_WINDOW_ALLOW_HIGHDPI) { - hint = SDL_GetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED); - if (hint && SDL_atoi(hint) > 0) { + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_HIGHDPI_DISABLED, SDL_FALSE)) { flags &= ~SDL_WINDOW_ALLOW_HIGHDPI; } } @@ -1389,8 +1408,28 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) window->y = bounds.y + (bounds.h - h) / 2; } } + window->windowed.x = window->x; + window->windowed.y = window->y; + window->windowed.w = window->w; + window->windowed.h = window->h; + + if (flags & SDL_WINDOW_FULLSCREEN) { + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + int displayIndex; + SDL_Rect bounds; + + displayIndex = SDL_GetIndexOfDisplay(display); + SDL_GetDisplayBounds(displayIndex, &bounds); + + window->x = bounds.x; + window->y = bounds.y; + window->w = bounds.w; + window->h = bounds.h; + } + window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN); window->last_fullscreen_flags = window->flags; + window->opacity = 1.0f; window->brightness = 1.0f; window->next = _this->windows; window->is_destroying = SDL_FALSE; @@ -1451,6 +1490,7 @@ SDL_CreateWindowFrom(const void *data) window->flags = SDL_WINDOW_FOREIGN; window->last_fullscreen_flags = window->flags; window->is_destroying = SDL_FALSE; + window->opacity = 1.0f; window->brightness = 1.0f; window->next = _this->windows; if (_this->windows) { @@ -1795,6 +1835,24 @@ SDL_SetWindowBordered(SDL_Window * window, SDL_bool bordered) } } +void +SDL_SetWindowResizable(SDL_Window * window, SDL_bool resizable) +{ + CHECK_WINDOW_MAGIC(window,); + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + const int want = (resizable != SDL_FALSE); /* normalize the flag. */ + const int have = ((window->flags & SDL_WINDOW_RESIZABLE) != 0); + if ((want != have) && (_this->SetWindowResizable)) { + if (want) { + window->flags |= SDL_WINDOW_RESIZABLE; + } else { + window->flags &= ~SDL_WINDOW_RESIZABLE; + } + _this->SetWindowResizable(_this, window, (SDL_bool) want); + } + } +} + void SDL_SetWindowSize(SDL_Window * window, int w, int h) { @@ -1883,6 +1941,28 @@ SDL_SetWindowMinimumSize(SDL_Window * window, int min_w, int min_h) } } +int +SDL_GetWindowBordersSize(SDL_Window * window, int *top, int *left, int *bottom, int *right) +{ + int dummy = 0; + + if (!top) { top = &dummy; } + if (!left) { left = &dummy; } + if (!right) { right = &dummy; } + if (!bottom) { bottom = &dummy; } + + /* Always initialize, so applications don't have to care */ + *top = *left = *bottom = *right = 0; + + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->GetWindowBordersSize) { + return SDL_Unsupported(); + } + + return _this->GetWindowBordersSize(_this, window, top, left, bottom, right); +} + void SDL_GetWindowMinimumSize(SDL_Window * window, int *min_w, int *min_h) { @@ -2144,6 +2224,68 @@ SDL_GetWindowBrightness(SDL_Window * window) return window->brightness; } +int +SDL_SetWindowOpacity(SDL_Window * window, float opacity) +{ + int retval; + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->SetWindowOpacity) { + return SDL_Unsupported(); + } + + if (opacity < 0.0f) { + opacity = 0.0f; + } else if (opacity > 1.0f) { + opacity = 1.0f; + } + + retval = _this->SetWindowOpacity(_this, window, opacity); + if (retval == 0) { + window->opacity = opacity; + } + + return retval; +} + +int +SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (out_opacity) { + *out_opacity = window->opacity; + } + + return 0; +} + +int +SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window) +{ + CHECK_WINDOW_MAGIC(modal_window, -1); + CHECK_WINDOW_MAGIC(parent_window, -1); + + if (!_this->SetWindowModalFor) { + return SDL_Unsupported(); + } + + return _this->SetWindowModalFor(_this, modal_window, parent_window); +} + +int +SDL_SetWindowInputFocus(SDL_Window * window) +{ + CHECK_WINDOW_MAGIC(window, -1); + + if (!_this->SetWindowInputFocus) { + return SDL_Unsupported(); + } + + return _this->SetWindowInputFocus(_this, window); +} + + int SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red, const Uint16 * green, @@ -2359,8 +2501,6 @@ SDL_OnWindowFocusGained(SDL_Window * window) static SDL_bool ShouldMinimizeOnFocusLoss(SDL_Window * window) { - const char *hint; - if (!(window->flags & SDL_WINDOW_FULLSCREEN) || window->is_destroying) { return SDL_FALSE; } @@ -2371,16 +2511,7 @@ ShouldMinimizeOnFocusLoss(SDL_Window * window) } #endif - hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - - return SDL_TRUE; + return SDL_GetHintBoolean(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, SDL_TRUE); } void @@ -3596,6 +3727,16 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window) { +#ifdef __EMSCRIPTEN__ + /* !!! FIXME: propose a browser API for this, get this #ifdef out of here? */ + /* Web browsers don't (currently) have an API for a custom message box + that can block, but for the most common case (SDL_ShowSimpleMessageBox), + we can use the standard Javascript alert() function. */ + EM_ASM_({ + alert(UTF8ToString($0) + "\n\n" + UTF8ToString($1)); + }, title, message); + return 0; +#else SDL_MessageBoxData data; SDL_MessageBoxButtonData button; @@ -3613,20 +3754,13 @@ SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, S button.text = "OK"; return SDL_ShowMessageBox(&data, NULL); +#endif } SDL_bool SDL_ShouldAllowTopmost(void) { - const char *hint = SDL_GetHint(SDL_HINT_ALLOW_TOPMOST); - if (hint) { - if (*hint == '0') { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - return SDL_TRUE; + return SDL_GetHintBoolean(SDL_HINT_ALLOW_TOPMOST, SDL_TRUE); } int diff --git a/Engine/lib/sdl/src/video/android/SDL_androidevents.c b/Engine/lib/sdl/src/video/android/SDL_androidevents.c index 326361af0..c3cd4cc1b 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidevents.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidevents.c @@ -34,11 +34,11 @@ void android_egl_context_backup(); void android_egl_context_restore(); #if SDL_AUDIO_DRIVER_ANDROID -void AndroidAUD_ResumeDevices(void); -void AndroidAUD_PauseDevices(void); +void ANDROIDAUDIO_ResumeDevices(void); +void ANDROIDAUDIO_PauseDevices(void); #else -static void AndroidAUD_ResumeDevices(void) {} -static void AndroidAUD_PauseDevices(void) {} +static void ANDROIDAUDIO_ResumeDevices(void) {} +static void ANDROIDAUDIO_PauseDevices(void) {} #endif void @@ -83,14 +83,14 @@ Android_PumpEvents(_THIS) if (isPaused && !isPausing) { /* Make sure this is the last thing we do before pausing */ android_egl_context_backup(); - AndroidAUD_PauseDevices(); + ANDROIDAUDIO_PauseDevices(); if(SDL_SemWait(Android_ResumeSem) == 0) { #else if (isPaused) { if(SDL_SemTryWait(Android_ResumeSem) == 0) { #endif isPaused = 0; - AndroidAUD_ResumeDevices(); + ANDROIDAUDIO_ResumeDevices(); /* Restore the GL Context from here, as this operation is thread dependent */ if (!SDL_HasEvent(SDL_QUIT)) { android_egl_context_restore(); @@ -113,7 +113,7 @@ Android_PumpEvents(_THIS) #else if(SDL_SemTryWait(Android_PauseSem) == 0) { android_egl_context_backup(); - AndroidAUD_PauseDevices(); + ANDROIDAUDIO_PauseDevices(); isPaused = 1; } #endif diff --git a/Engine/lib/sdl/src/video/android/SDL_androidkeyboard.c b/Engine/lib/sdl/src/video/android/SDL_androidkeyboard.c index dc8951ff9..652e0cca7 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidkeyboard.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidkeyboard.c @@ -304,18 +304,22 @@ static SDL_Scancode Android_Keycodes[] = { SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_NEXT */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_IN */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_NAVIGATE_OUT */ - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, - SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_PRIMARY */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_1 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_2 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_STEM_3 */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_UP_LEFT */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_DOWN_LEFT */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_UP_RIGHT */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_DPAD_DOWN_RIGHT */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_SKIP_FORWARD */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_SKIP_BACKWARD */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_STEP_FORWARD */ SDL_SCANCODE_UNKNOWN, /* AKEYCODE_MEDIA_STEP_BACKWARD */ + SDL_SCANCODE_UNKNOWN, /* AKEYCODE_SOFT_SLEEP */ + SDL_SCANCODE_CUT, /* AKEYCODE_CUT */ + SDL_SCANCODE_COPY, /* AKEYCODE_COPY */ + SDL_SCANCODE_PASTE, /* AKEYCODE_PASTE */ }; static SDL_Scancode diff --git a/Engine/lib/sdl/src/video/android/SDL_androidmouse.c b/Engine/lib/sdl/src/video/android/SDL_androidmouse.c index 3e9c0aff5..883fa8d22 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidmouse.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidmouse.c @@ -32,15 +32,24 @@ #define ACTION_DOWN 0 #define ACTION_UP 1 +#define ACTION_MOVE 2 #define ACTION_HOVER_MOVE 7 #define ACTION_SCROLL 8 #define BUTTON_PRIMARY 1 #define BUTTON_SECONDARY 2 #define BUTTON_TERTIARY 4 +#define BUTTON_BACK 8 +#define BUTTON_FORWARD 16 + +static Uint8 SDLButton; + +void +Android_InitMouse(void) +{ + SDLButton = 0; +} void Android_OnMouse( int androidButton, int action, float x, float y) { - static Uint8 SDLButton; - if (!Android_Window) { return; } @@ -53,6 +62,10 @@ void Android_OnMouse( int androidButton, int action, float x, float y) { SDLButton = SDL_BUTTON_RIGHT; } else if (androidButton == BUTTON_TERTIARY) { SDLButton = SDL_BUTTON_MIDDLE; + } else if (androidButton == BUTTON_FORWARD) { + SDLButton = SDL_BUTTON_X1; + } else if (androidButton == BUTTON_BACK) { + SDLButton = SDL_BUTTON_X2; } SDL_SendMouseMotion(Android_Window, 0, 0, x, y); SDL_SendMouseButton(Android_Window, 0, SDL_PRESSED, SDLButton); @@ -65,6 +78,7 @@ void Android_OnMouse( int androidButton, int action, float x, float y) { SDL_SendMouseButton(Android_Window, 0, SDL_RELEASED, SDLButton); break; + case ACTION_MOVE: case ACTION_HOVER_MOVE: SDL_SendMouseMotion(Android_Window, 0, 0, x, y); break; diff --git a/Engine/lib/sdl/src/video/android/SDL_androidmouse.h b/Engine/lib/sdl/src/video/android/SDL_androidmouse.h index 9b68eed57..a64e06d51 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidmouse.h +++ b/Engine/lib/sdl/src/video/android/SDL_androidmouse.h @@ -24,6 +24,7 @@ #include "SDL_androidvideo.h" +extern void Android_InitMouse(void); extern void Android_OnMouse( int button, int action, float x, float y); #endif /* _SDL_androidmouse_h */ diff --git a/Engine/lib/sdl/src/video/android/SDL_androidtouch.c b/Engine/lib/sdl/src/video/android/SDL_androidtouch.c index a6e0b896a..0ff11ef57 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidtouch.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidtouch.c @@ -50,7 +50,7 @@ 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 SDL_bool separate_mouse_and_touch = SDL_FALSE; static void SeparateEventsHintWatcher(void *userdata, const char *name, diff --git a/Engine/lib/sdl/src/video/android/SDL_androidvideo.c b/Engine/lib/sdl/src/video/android/SDL_androidvideo.c index e14b96641..178a3e691 100644 --- a/Engine/lib/sdl/src/video/android/SDL_androidvideo.c +++ b/Engine/lib/sdl/src/video/android/SDL_androidvideo.c @@ -36,6 +36,7 @@ #include "SDL_androidclipboard.h" #include "SDL_androidevents.h" #include "SDL_androidkeyboard.h" +#include "SDL_androidmouse.h" #include "SDL_androidtouch.h" #include "SDL_androidwindow.h" @@ -181,6 +182,8 @@ Android_VideoInit(_THIS) Android_InitTouch(); + Android_InitMouse(); + /* We're done! */ return 0; } @@ -191,7 +194,6 @@ Android_VideoQuit(_THIS) Android_QuitTouch(); } -/* This function gets called before VideoInit() */ void Android_SetScreenResolution(int width, int height, Uint32 format, float rate) { @@ -200,8 +202,33 @@ Android_SetScreenResolution(int width, int height, Uint32 format, float rate) Android_ScreenFormat = format; Android_ScreenRate = rate; + /* + Update the resolution of the desktop mode, so that the window + can be properly resized. The screen resolution change can for + example happen when the Activity enters or exists immersive mode, + which can happen after VideoInit(). + */ + SDL_VideoDevice* device = SDL_GetVideoDevice(); + if (device && device->num_displays > 0) + { + SDL_VideoDisplay* display = &device->displays[0]; + display->desktop_mode.format = Android_ScreenFormat; + display->desktop_mode.w = Android_ScreenWidth; + display->desktop_mode.h = Android_ScreenHeight; + display->desktop_mode.refresh_rate = Android_ScreenRate; + } + if (Android_Window) { SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESIZED, width, height); + + /* Force the current mode to match the resize otherwise the SDL_WINDOWEVENT_RESTORED event + * will fall back to the old mode */ + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(Android_Window); + + display->current_mode.format = format; + display->current_mode.w = width; + display->current_mode.h = height; + display->current_mode.refresh_rate = rate; } } diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaclipboard.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaclipboard.m index 015d77106..fd8680925 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaclipboard.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaclipboard.m @@ -25,23 +25,13 @@ #include "SDL_cocoavideo.h" #include "../../events/SDL_clipboardevents_c.h" -static NSString * -GetTextFormat(_THIS) -{ - if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) { - return NSPasteboardTypeString; - } else { - return NSStringPboardType; - } -} - int Cocoa_SetClipboardText(_THIS, const char *text) { @autoreleasepool { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; NSPasteboard *pasteboard; - NSString *format = GetTextFormat(_this); + NSString *format = NSPasteboardTypeString; pasteboard = [NSPasteboard generalPasteboard]; data->clipboard_count = [pasteboard declareTypes:[NSArray arrayWithObject:format] owner:nil]; @@ -55,12 +45,12 @@ Cocoa_GetClipboardText(_THIS) { @autoreleasepool { NSPasteboard *pasteboard; - NSString *format = GetTextFormat(_this); + NSString *format = NSPasteboardTypeString; NSString *available; char *text; pasteboard = [NSPasteboard generalPasteboard]; - available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:format]]; + available = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:format]]; if ([available isEqualToString:format]) { NSString* string; const char *utf8; diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaevents.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaevents.m index e0da11fd4..17a3183b7 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaevents.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaevents.m @@ -36,6 +36,7 @@ @interface SDLApplication : NSApplication - (void)terminate:(id)sender; +- (void)sendEvent:(NSEvent *)theEvent; @end @@ -47,6 +48,48 @@ SDL_SendQuit(); } +static SDL_bool s_bShouldHandleEventsInSDLApplication = SDL_FALSE; + +static void Cocoa_DispatchEvent(NSEvent *theEvent) +{ + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + + switch ([theEvent type]) { + case NSLeftMouseDown: + case NSOtherMouseDown: + case NSRightMouseDown: + case NSLeftMouseUp: + case NSOtherMouseUp: + case NSRightMouseUp: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: /* usually middle mouse dragged */ + case NSMouseMoved: + case NSScrollWheel: + Cocoa_HandleMouseEvent(_this, theEvent); + break; + case NSKeyDown: + case NSKeyUp: + case NSFlagsChanged: + Cocoa_HandleKeyEvent(_this, theEvent); + break; + default: + break; + } +} + +// Dispatch events here so that we can handle events caught by +// nextEventMatchingMask in SDL, as well as events caught by other +// processes (such as CEF) that are passed down to NSApp. +- (void)sendEvent:(NSEvent *)theEvent +{ + if (s_bShouldHandleEventsInSDLApplication) { + Cocoa_DispatchEvent(theEvent); + } + + [super sendEvent:theEvent]; +} + @end // SDLApplication /* setAppleMenu disappeared from the headers in 10.4 */ @@ -114,28 +157,23 @@ */ for (NSWindow *window in [NSApp orderedWindows]) { if (window != win && [window canBecomeKeyWindow]) { - if ([window respondsToSelector:@selector(isOnActiveSpace)]) { - if (![window isOnActiveSpace]) { - continue; - } + 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 a window wasn't found above, iterate through all visible windows in + * the active Space in z-order (including the 'About' window, if it's shown) + * and make the first one key. */ - 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; - } + for (NSNumber *num in [NSWindow windowNumbersWithOptions:0]) { + NSWindow *window = [NSApp windowWithWindowNumber:[num integerValue]]; + if (window && window != win && [window canBecomeKeyWindow]) { + [window makeKeyAndOrderFront:self]; + return; } } } @@ -176,7 +214,7 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { - return (BOOL)SDL_SendDropFile([filename UTF8String]); + return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL); } @end @@ -291,7 +329,7 @@ CreateApplicationMenus(void) /* Add the fullscreen view toggle menu option, if supported */ - if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) { + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) { /* Create the view menu */ viewMenu = [[NSMenu alloc] initWithTitle:@"View"]; @@ -319,18 +357,10 @@ Cocoa_RegisterApp(void) [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 + s_bShouldHandleEventsInSDLApplication = SDL_TRUE; + + if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) { + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp activateIgnoringOtherApps:YES]; } @@ -381,29 +411,11 @@ Cocoa_PumpEvents(_THIS) break; } - switch ([event type]) { - case NSLeftMouseDown: - case NSOtherMouseDown: - case NSRightMouseDown: - case NSLeftMouseUp: - case NSOtherMouseUp: - case NSRightMouseUp: - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: /* usually middle mouse dragged */ - case NSMouseMoved: - case NSScrollWheel: - Cocoa_HandleMouseEvent(_this, event); - break; - case NSKeyDown: - case NSKeyUp: - case NSFlagsChanged: - Cocoa_HandleKeyEvent(_this, event); - break; - default: - break; + if (!s_bShouldHandleEventsInSDLApplication) { + Cocoa_DispatchEvent(event); } - /* Pass through to NSApp to make sure everything stays in sync */ + + // Pass events down to SDLApplication to be handled in sendEvent: [NSApp sendEvent:event]; } }} diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoakeyboard.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoakeyboard.m index 7f1d2308f..8b2ed91c2 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoakeyboard.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoakeyboard.m @@ -29,6 +29,7 @@ #include "../../events/scancodes_darwin.h" #include +#include /*#define DEBUG_IME NSLog */ #define DEBUG_IME(...) @@ -69,14 +70,6 @@ SDL_SendKeyboardText(str); } -- (void)insertText:(id)insertString -{ - /* This method is part of NSTextInput and not NSTextInputClient, but - * apparently it still might be called in OS X 10.5 and can cause beeps if - * the implementation is missing: http://crbug.com/47890 */ - [self insertText:insertString replacementRange:NSMakeRange(0, 0)]; -} - - (void)doCommandBySelector:(SEL)myselector { /* No need to do anything since we are not using Cocoa @@ -102,7 +95,7 @@ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange; { - if ([aString isKindOfClass: [NSAttributedString class]]) { + if ([aString isKindOfClass:[NSAttributedString class]]) { aString = [aString string]; } @@ -120,7 +113,7 @@ _markedRange = NSMakeRange(0, [aString length]); SDL_SendEditingText([aString UTF8String], - selectedRange.location, selectedRange.length); + (int) selectedRange.location, (int) selectedRange.length); DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText, selRange.location, selRange.length); @@ -150,10 +143,10 @@ aRange.location, aRange.length, windowHeight, NSStringFromRect(rect)); - if ([[self window] respondsToSelector:@selector(convertRectToScreen:)]) { - rect = [[self window] convertRectToScreen:rect]; + if ([window respondsToSelector:@selector(convertRectToScreen:)]) { + rect = [window convertRectToScreen:rect]; } else { - rect.origin = [[self window] convertBaseToScreen:rect.origin]; + rect.origin = [window convertBaseToScreen:rect.origin]; } return rect; @@ -191,6 +184,116 @@ @end +/*------------------------------------------------------------------------------ +Set up a HID callback to properly detect Caps Lock up/down events. +Derived from: +http://stackoverflow.com/questions/7190852/using-iohidmanager-to-get-modifier-key-events +*/ + +static IOHIDManagerRef s_hidManager = NULL; + +static void +HIDCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) +{ + if (context != s_hidManager) { + /* An old callback, ignore it (related to bug 2157 below) */ + return; + } + + IOHIDElementRef elem = IOHIDValueGetElement(value); + if (IOHIDElementGetUsagePage(elem) != kHIDPage_KeyboardOrKeypad + || IOHIDElementGetUsage(elem) != kHIDUsage_KeyboardCapsLock) { + return; + } + CFIndex pressed = IOHIDValueGetIntegerValue(value); + SDL_SendKeyboardKey(pressed ? SDL_PRESSED : SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); +} + +static CFDictionaryRef +CreateHIDDeviceMatchingDictionary(UInt32 usagePage, UInt32 usage) +{ + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (dict) { + CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); + if (number) { + CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), number); + CFRelease(number); + number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + if (number) { + CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), number); + CFRelease(number); + return dict; + } + } + CFRelease(dict); + } + return NULL; +} + +static void +QuitHIDCallback() +{ + if (!s_hidManager) { + return; + } + +#if 0 /* Releasing here causes a crash on Mac OS X 10.10 and earlier, + * so just leak it for now. See bug 2157 for details. + */ + IOHIDManagerUnscheduleFromRunLoop(s_hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDManagerRegisterInputValueCallback(s_hidManager, NULL, NULL); + IOHIDManagerClose(s_hidManager, 0); + + CFRelease(s_hidManager); +#endif + s_hidManager = NULL; +} + +static void +InitHIDCallback() +{ + s_hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (!s_hidManager) { + return; + } + CFDictionaryRef keyboard = NULL, keypad = NULL; + CFArrayRef matches = NULL; + keyboard = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); + if (!keyboard) { + goto fail; + } + keypad = CreateHIDDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keypad); + if (!keypad) { + goto fail; + } + CFDictionaryRef matchesList[] = { keyboard, keypad }; + matches = CFArrayCreate(kCFAllocatorDefault, (const void **)matchesList, 2, NULL); + if (!matches) { + goto fail; + } + IOHIDManagerSetDeviceMatchingMultiple(s_hidManager, matches); + IOHIDManagerRegisterInputValueCallback(s_hidManager, HIDCallback, s_hidManager); + IOHIDManagerScheduleWithRunLoop(s_hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); + if (IOHIDManagerOpen(s_hidManager, kIOHIDOptionsTypeNone) == kIOReturnSuccess) { + goto cleanup; + } + +fail: + QuitHIDCallback(); + +cleanup: + if (matches) { + CFRelease(matches); + } + if (keypad) { + CFRelease(keypad); + } + if (keyboard) { + CFRelease(keyboard); + } +} + /* This is a helper function for HandleModifierSide. This * function reverts back to behavior before the distinction between * sides was made. @@ -328,24 +431,6 @@ ReleaseModifierSide(unsigned int device_independent_mask, } } -/* This is a helper function for DoSidedModifiers. - * This function handles the CapsLock case. - */ -static void -HandleCapsLock(unsigned short scancode, - unsigned int oldMods, unsigned int newMods) -{ - unsigned int oldMask, newMask; - - oldMask = oldMods & NSAlphaShiftKeyMask; - newMask = newMods & NSAlphaShiftKeyMask; - - if (oldMask != newMask) { - SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_CAPSLOCK); - SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_CAPSLOCK); - } -} - /* This function will handle the modifier keys and also determine the * correct side of the key. */ @@ -374,9 +459,6 @@ DoSidedModifiers(unsigned short scancode, unsigned int i, bit; - /* Handle CAPSLOCK separately because it doesn't have a left/right side */ - HandleCapsLock(scancode, oldMods, newMods); - /* Iterate through the bits, testing each against the old modifiers */ for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { unsigned int oldMask, newMask; @@ -498,11 +580,10 @@ Cocoa_InitKeyboard(_THIS) SDL_SetScancodeName(SDL_SCANCODE_RALT, "Right Option"); SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command"); - /* On pre-10.6, you might have the initial capslock key state wrong. */ - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_6) { - data->modifierFlags = [NSEvent modifierFlags]; - SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSAlphaShiftKeyMask) != 0); - } + data->modifierFlags = [NSEvent modifierFlags]; + SDL_ToggleModState(KMOD_CAPS, (data->modifierFlags & NSAlphaShiftKeyMask) != 0); + + InitHIDCallback(); } void @@ -628,6 +709,7 @@ Cocoa_HandleKeyEvent(_THIS, NSEvent *event) void Cocoa_QuitKeyboard(_THIS) { + QuitHIDCallback(); } #endif /* SDL_VIDEO_DRIVER_COCOA */ diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.h b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.h index a0a29f501..ce8601cba 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.h +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.h @@ -30,12 +30,14 @@ typedef struct typedef struct { - const void *moderef; + CGDisplayModeRef moderef; } SDL_DisplayModeData; extern void Cocoa_InitModes(_THIS); extern int Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); +extern int Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); extern void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display); +extern int Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hpdi, float * vdpi); extern int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); extern void Cocoa_QuitModes(_THIS); diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.m index 7d98264a7..6ae9decbc 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamodes.m @@ -19,6 +19,7 @@ 3. This notice may not be removed or altered from any source distribution. */ #include "../../SDL_internal.h" +#include "SDL_assert.h" #if SDL_VIDEO_DRIVER_COCOA @@ -55,25 +56,6 @@ Cocoa_ToggleMenuBar(const BOOL show) #endif } - -/* !!! FIXME: clean out the pre-10.6 code when it makes sense to do so. */ -#define FORCE_OLD_API 0 - -#if FORCE_OLD_API -#undef MAC_OS_X_VERSION_MIN_REQUIRED -#define MAC_OS_X_VERSION_MIN_REQUIRED 1050 -#endif - -static BOOL -IS_SNOW_LEOPARD_OR_LATER() -{ -#if FORCE_OLD_API - return NO; -#else - return floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5; -#endif -} - static int CG_SetError(const char *prefix, CGDisplayErr result) { @@ -118,65 +100,46 @@ CG_SetError(const char *prefix, CGDisplayErr result) } static SDL_bool -GetDisplayMode(_THIS, const void *moderef, CVDisplayLinkRef link, SDL_DisplayMode *mode) +GetDisplayMode(_THIS, CGDisplayModeRef vidmode, CVDisplayLinkRef link, SDL_DisplayMode *mode) { SDL_DisplayModeData *data; - long width = 0; - long height = 0; - long bpp = 0; - long refreshRate = 0; + int width = 0; + int height = 0; + int bpp = 0; + int refreshRate = 0; + CFStringRef fmt; data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); if (!data) { return SDL_FALSE; } - data->moderef = moderef; + data->moderef = vidmode; - if (IS_SNOW_LEOPARD_OR_LATER()) { - CGDisplayModeRef vidmode = (CGDisplayModeRef) moderef; - CFStringRef fmt = CGDisplayModeCopyPixelEncoding(vidmode); - width = (long) CGDisplayModeGetWidth(vidmode); - height = (long) CGDisplayModeGetHeight(vidmode); - refreshRate = (long) (CGDisplayModeGetRefreshRate(vidmode) + 0.5); + fmt = CGDisplayModeCopyPixelEncoding(vidmode); + width = (int) CGDisplayModeGetWidth(vidmode); + height = (int) CGDisplayModeGetHeight(vidmode); + refreshRate = (int) (CGDisplayModeGetRefreshRate(vidmode) + 0.5); - if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bpp = 32; - } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bpp = 16; - } else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) { - bpp = 30; - } else { - bpp = 0; /* ignore 8-bit and such for now. */ - } - - CFRelease(fmt); + if (CFStringCompare(fmt, CFSTR(IO32BitDirectPixels), + kCFCompareCaseInsensitive) == kCFCompareEqualTo) { + bpp = 32; + } else if (CFStringCompare(fmt, CFSTR(IO16BitDirectPixels), + kCFCompareCaseInsensitive) == kCFCompareEqualTo) { + bpp = 16; + } else if (CFStringCompare(fmt, CFSTR(kIO30BitDirectPixels), + kCFCompareCaseInsensitive) == kCFCompareEqualTo) { + bpp = 30; + } else { + bpp = 0; /* ignore 8-bit and such for now. */ } - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (!IS_SNOW_LEOPARD_OR_LATER()) { - CFNumberRef number; - double refresh; - CFDictionaryRef vidmode = (CFDictionaryRef) moderef; - number = CFDictionaryGetValue(vidmode, kCGDisplayWidth); - CFNumberGetValue(number, kCFNumberLongType, &width); - number = CFDictionaryGetValue(vidmode, kCGDisplayHeight); - CFNumberGetValue(number, kCFNumberLongType, &height); - number = CFDictionaryGetValue(vidmode, kCGDisplayBitsPerPixel); - CFNumberGetValue(number, kCFNumberLongType, &bpp); - number = CFDictionaryGetValue(vidmode, kCGDisplayRefreshRate); - CFNumberGetValue(number, kCFNumberDoubleType, &refresh); - refreshRate = (long) (refresh + 0.5); - } - #endif + CFRelease(fmt); /* CGDisplayModeGetRefreshRate returns 0 for many non-CRT displays. */ if (refreshRate == 0 && link != NULL) { CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); if ((time.flags & kCVTimeIsIndefinite) == 0 && time.timeValue != 0) { - refreshRate = (long) ((time.timeScale / (double) time.timeValue) + 0.5); + refreshRate = (int) ((time.timeScale / (double) time.timeValue) + 0.5); } } @@ -203,22 +166,6 @@ GetDisplayMode(_THIS, const void *moderef, CVDisplayLinkRef link, SDL_DisplayMod return SDL_TRUE; } -static void -Cocoa_ReleaseDisplayMode(_THIS, const void *moderef) -{ - if (IS_SNOW_LEOPARD_OR_LATER()) { - CGDisplayModeRelease((CGDisplayModeRef) moderef); /* NULL is ok */ - } -} - -static void -Cocoa_ReleaseDisplayModeList(_THIS, CFArrayRef modelist) -{ - if (IS_SNOW_LEOPARD_OR_LATER()) { - CFRelease(modelist); /* NULL is ok */ - } -} - static const char * Cocoa_GetDisplayName(CGDirectDisplayID displayID) { @@ -261,7 +208,7 @@ Cocoa_InitModes(_THIS) SDL_VideoDisplay display; SDL_DisplayData *displaydata; SDL_DisplayMode mode; - const void *moderef = NULL; + CGDisplayModeRef moderef = NULL; CVDisplayLinkRef link = NULL; if (pass == 0) { @@ -278,15 +225,7 @@ Cocoa_InitModes(_THIS) continue; } - if (IS_SNOW_LEOPARD_OR_LATER()) { - moderef = CGDisplayCopyDisplayMode(displays[i]); - } - - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (!IS_SNOW_LEOPARD_OR_LATER()) { - moderef = CGDisplayCurrentMode(displays[i]); - } - #endif + moderef = CGDisplayCopyDisplayMode(displays[i]); if (!moderef) { continue; @@ -294,7 +233,7 @@ Cocoa_InitModes(_THIS) displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata)); if (!displaydata) { - Cocoa_ReleaseDisplayMode(_this, moderef); + CGDisplayModeRelease(moderef); continue; } displaydata->display = displays[i]; @@ -306,7 +245,7 @@ Cocoa_InitModes(_THIS) display.name = (char *)Cocoa_GetDisplayName(displays[i]); if (!GetDisplayMode(_this, moderef, link, &mode)) { CVDisplayLinkRelease(link); - Cocoa_ReleaseDisplayMode(_this, moderef); + CGDisplayModeRelease(moderef); SDL_free(display.name); SDL_free(displaydata); continue; @@ -338,21 +277,70 @@ Cocoa_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) return 0; } +int +Cocoa_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) +{ + SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; + const CGDirectDisplayID cgdisplay = displaydata->display; + NSArray *screens = [NSScreen screens]; + NSScreen *screen = nil; + + /* !!! FIXME: maybe track the NSScreen in SDL_DisplayData? */ + for (NSScreen *i in screens) { + const CGDirectDisplayID thisDisplay = (CGDirectDisplayID) [[[i deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; + if (thisDisplay == cgdisplay) { + screen = i; + break; + } + } + + SDL_assert(screen != nil); /* didn't find it?! */ + if (screen == nil) { + return -1; + } + + const CGRect cgrect = CGDisplayBounds(cgdisplay); + const NSRect frame = [screen visibleFrame]; + + // !!! FIXME: I assume -[NSScreen visibleFrame] is relative to the origin of the screen in question and not the whole desktop. + // !!! FIXME: The math vs CGDisplayBounds might be incorrect if that's not the case, though. Check this. + rect->x = (int)(cgrect.origin.x + frame.origin.x); + rect->y = (int)(cgrect.origin.y + frame.origin.y); + rect->w = (int)frame.size.width; + rect->h = (int)frame.size.height; + + return 0; +} + +int +Cocoa_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi) +{ + const float MM_IN_INCH = 25.4f; + + SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; + + CGSize displaySize = CGDisplayScreenSize(data->display); + int pixelWidth = (int) CGDisplayPixelsWide(data->display); + int pixelHeight = (int) CGDisplayPixelsHigh(data->display); + + if (ddpi) { + *ddpi = SDL_ComputeDiagonalDPI(pixelWidth, pixelHeight, displaySize.width / MM_IN_INCH, displaySize.height / MM_IN_INCH); + } + if (hdpi) { + *hdpi = pixelWidth * MM_IN_INCH / displaySize.width; + } + if (vdpi) { + *vdpi = pixelHeight * MM_IN_INCH / displaySize.height; + } + + return 0; +} + void Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display) { SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata; - CFArrayRef modes = NULL; - - if (IS_SNOW_LEOPARD_OR_LATER()) { - modes = CGDisplayCopyAllDisplayModes(data->display, NULL); - } - - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (!IS_SNOW_LEOPARD_OR_LATER()) { - modes = CGDisplayAvailableModes(data->display); - } - #endif + CFArrayRef modes = CGDisplayCopyAllDisplayModes(data->display, NULL); if (modes) { CVDisplayLinkRef link = NULL; @@ -362,37 +350,19 @@ Cocoa_GetDisplayModes(_THIS, SDL_VideoDisplay * display) CVDisplayLinkCreateWithCGDisplay(data->display, &link); for (i = 0; i < count; i++) { - const void *moderef = CFArrayGetValueAtIndex(modes, i); + CGDisplayModeRef moderef = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i); SDL_DisplayMode mode; if (GetDisplayMode(_this, moderef, link, &mode)) { - if (IS_SNOW_LEOPARD_OR_LATER()) { - CGDisplayModeRetain((CGDisplayModeRef) moderef); - } + CGDisplayModeRetain(moderef); SDL_AddDisplayMode(display, &mode); } } CVDisplayLinkRelease(link); - Cocoa_ReleaseDisplayModeList(_this, modes); + CFRelease(modes); } } -static CGError -Cocoa_SwitchMode(_THIS, CGDirectDisplayID display, const void *mode) -{ - if (IS_SNOW_LEOPARD_OR_LATER()) { - return CGDisplaySetDisplayMode(display, (CGDisplayModeRef) mode, NULL); - } - - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 - if (!IS_SNOW_LEOPARD_OR_LATER()) { - return CGDisplaySwitchToMode(display, (CFDictionaryRef) mode); - } - #endif - - return kCGErrorFailure; -} - int Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { @@ -408,7 +378,7 @@ Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) if (data == display->desktop_mode.driverdata) { /* Restoring desktop mode */ - Cocoa_SwitchMode(_this, displaydata->display, data->moderef); + CGDisplaySetDisplayMode(displaydata->display, data->moderef, NULL); if (CGDisplayIsMain(displaydata->display)) { CGReleaseAllDisplays(); @@ -433,7 +403,7 @@ Cocoa_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) } /* Do the physical switch */ - result = Cocoa_SwitchMode(_this, displaydata->display, data->moderef); + result = CGDisplaySetDisplayMode(displaydata->display, data->moderef, NULL); if (result != kCGErrorSuccess) { CG_SetError("CGDisplaySwitchToMode()", result); goto ERR_NO_SWITCH; @@ -478,11 +448,11 @@ Cocoa_QuitModes(_THIS) } mode = (SDL_DisplayModeData *) display->desktop_mode.driverdata; - Cocoa_ReleaseDisplayMode(_this, mode->moderef); + CGDisplayModeRelease(mode->moderef); for (j = 0; j < display->num_display_modes; j++) { mode = (SDL_DisplayModeData*) display->display_modes[j].driverdata; - Cocoa_ReleaseDisplayMode(_this, mode->moderef); + CGDisplayModeRelease(mode->moderef); } } diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m index c76833123..0a27549ae 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamouse.m @@ -226,13 +226,15 @@ Cocoa_WarpMouseGlobal(int x, int y) Cocoa_HandleMouseWarp(point.x, point.y); - /* According to the docs, this was deprecated in 10.6, but it's still - * around. The substitute requires a CGEventSource, but I'm not entirely - * sure how we'd procure the right one for this event. - */ - CGSetLocalEventsSuppressionInterval(0.0); CGWarpMouseCursorPosition(point); - CGSetLocalEventsSuppressionInterval(0.25); + + /* CGWarpMouse causes a short delay by default, which is preventable by + * Calling this directly after. CGSetLocalEventsSuppressionInterval can also + * prevent it, but it's deprecated as of OS X 10.6. + */ + if (!mouse->relative_mode) { + CGAssociateMouseAndMouseCursorPosition(YES); + } /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our * other implementations' APIs. Send what's appropriate. @@ -314,7 +316,7 @@ Cocoa_GetGlobalMouseState(int *x, int *y) for (NSScreen *screen in [NSScreen screens]) { NSRect frame = [screen frame]; - if (NSPointInRect(cocoaLocation, frame)) { + if (NSMouseInRect(cocoaLocation, frame, NO)) { *x = (int) cocoaLocation.x; *y = (int) ((frame.origin.y + frame.size.height) - cocoaLocation.y); break; @@ -396,7 +398,7 @@ Cocoa_HandleMouseEvent(_THIS, NSEvent *event) /* Ignore events that aren't inside the client area (i.e. title bar.) */ if ([event window]) { NSRect windowRect = [[[event window] contentView] frame]; - if (!NSPointInRect([event locationInWindow], windowRect)) { + if (!NSMouseInRect([event locationInWindow], windowRect, NO)) { return; } } @@ -419,8 +421,8 @@ Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event) { SDL_Mouse *mouse = SDL_GetMouse(); - float x = -[event deltaX]; - float y = [event deltaY]; + CGFloat x = -[event deltaX]; + CGFloat y = [event deltaY]; SDL_MouseWheelDirection direction = SDL_MOUSEWHEEL_NORMAL; if ([event respondsToSelector:@selector(isDirectionInvertedFromDevice)]) { @@ -430,14 +432,14 @@ Cocoa_HandleMouseWheel(SDL_Window *window, NSEvent *event) } if (x > 0) { - x += 0.9f; + x = SDL_ceil(x); } else if (x < 0) { - x -= 0.9f; + x = SDL_floor(x); } if (y > 0) { - y += 0.9f; + y = SDL_ceil(y); } else if (y < 0) { - y -= 0.9f; + y = SDL_floor(y); } SDL_SendMouseWheel(window, mouse->mouseID, (int)x, (int)y, direction); } diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamousetap.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamousetap.m index ed70f3ca3..48abbca9c 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoamousetap.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoamousetap.m @@ -32,8 +32,8 @@ #if SDL_MAC_NO_SANDBOX #include "SDL_keyboard.h" -#include "SDL_thread.h" #include "SDL_cocoavideo.h" +#include "../../thread/SDL_systhread.h" #include "../../events/SDL_mouse_c.h" @@ -96,7 +96,7 @@ Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event eventLocation = CGEventGetUnflippedLocation(event); windowRect = [nswindow contentRectForFrameRect:[nswindow frame]]; - if (!NSPointInRect(NSPointFromCGPoint(eventLocation), windowRect)) { + if (!NSMouseInRect(NSPointFromCGPoint(eventLocation), windowRect, NO)) { /* This is in CGs global screenspace coordinate system, which has a * flipped Y. @@ -109,15 +109,14 @@ Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event newLocation.x = NSMaxX(windowRect) - 1.0; } - if (eventLocation.y < NSMinY(windowRect)) { + if (eventLocation.y <= NSMinY(windowRect)) { newLocation.y -= (NSMinY(windowRect) - eventLocation.y + 1); - } else if (eventLocation.y >= NSMaxY(windowRect)) { - newLocation.y += (eventLocation.y - NSMaxY(windowRect) + 1); + } else if (eventLocation.y > NSMaxY(windowRect)) { + newLocation.y += (eventLocation.y - NSMaxY(windowRect)); } - CGSetLocalEventsSuppressionInterval(0); CGWarpMouseCursorPosition(newLocation); - CGSetLocalEventsSuppressionInterval(0.25); + CGAssociateMouseAndMouseCursorPosition(YES); if ((CGEventMaskBit(type) & movementEventsMask) == 0) { /* For click events, we just constrain the event to the window, so @@ -203,7 +202,7 @@ Cocoa_InitMouseEventTap(SDL_MouseData* driverdata) tapdata->runloopStartedSemaphore = SDL_CreateSemaphore(0); if (tapdata->runloopStartedSemaphore) { - tapdata->thread = SDL_CreateThread(&Cocoa_MouseTapThread, "Event Tap Loop", tapdata); + tapdata->thread = SDL_CreateThreadInternal(&Cocoa_MouseTapThread, "Event Tap Loop", 512 * 1024, tapdata); if (!tapdata->thread) { SDL_DestroySemaphore(tapdata->runloopStartedSemaphore); } diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaopengl.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaopengl.m index aa3609984..645e5ba45 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoaopengl.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoaopengl.m @@ -173,6 +173,8 @@ Cocoa_GL_CreateContext(_THIS, SDL_Window * window) return NULL; } + attr[i++] = NSOpenGLPFAAllowOfflineRenderers; + /* specify a profile if we're on Lion (10.7) or later. */ if (lion_or_later) { NSOpenGLPixelFormatAttribute profile = NSOpenGLProfileVersionLegacy; diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoashape.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoashape.m index cd5d97b70..fc8a2775c 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoashape.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoashape.m @@ -35,9 +35,7 @@ Cocoa_CreateShaper(SDL_Window* window) SDL_WindowData* windata = (SDL_WindowData*)window->driverdata; [windata->nswindow setOpaque:NO]; - if ([windata->nswindow respondsToSelector:@selector(setStyleMask:)]) { - [windata->nswindow setStyleMask:NSBorderlessWindowMask]; - } + [windata->nswindow setStyleMask:NSBorderlessWindowMask]; SDL_WindowShaper* result = result = malloc(sizeof(SDL_WindowShaper)); result->window = window; diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoavideo.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoavideo.m index b8f775ddb..e436e6521 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoavideo.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoavideo.m @@ -73,6 +73,8 @@ Cocoa_CreateDevice(int devindex) device->VideoInit = Cocoa_VideoInit; device->VideoQuit = Cocoa_VideoQuit; device->GetDisplayBounds = Cocoa_GetDisplayBounds; + device->GetDisplayUsableBounds = Cocoa_GetDisplayUsableBounds; + device->GetDisplayDPI = Cocoa_GetDisplayDPI; device->GetDisplayModes = Cocoa_GetDisplayModes; device->SetDisplayMode = Cocoa_SetDisplayMode; device->PumpEvents = Cocoa_PumpEvents; @@ -86,6 +88,7 @@ Cocoa_CreateDevice(int devindex) device->SetWindowSize = Cocoa_SetWindowSize; device->SetWindowMinimumSize = Cocoa_SetWindowMinimumSize; device->SetWindowMaximumSize = Cocoa_SetWindowMaximumSize; + device->SetWindowOpacity = Cocoa_SetWindowOpacity; device->ShowWindow = Cocoa_ShowWindow; device->HideWindow = Cocoa_HideWindow; device->RaiseWindow = Cocoa_RaiseWindow; @@ -93,6 +96,7 @@ Cocoa_CreateDevice(int devindex) device->MinimizeWindow = Cocoa_MinimizeWindow; device->RestoreWindow = Cocoa_RestoreWindow; device->SetWindowBordered = Cocoa_SetWindowBordered; + device->SetWindowResizable = Cocoa_SetWindowResizable; device->SetWindowFullscreen = Cocoa_SetWindowFullscreen; device->SetWindowGammaRamp = Cocoa_SetWindowGammaRamp; device->GetWindowGammaRamp = Cocoa_GetWindowGammaRamp; @@ -146,8 +150,7 @@ Cocoa_VideoInit(_THIS) Cocoa_InitKeyboard(_this); Cocoa_InitMouse(_this); - const char *hint = SDL_GetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES); - data->allow_spaces = ( (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && (!hint || (*hint != '0')) ); + data->allow_spaces = ((floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) && SDL_GetHintBoolean(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, SDL_TRUE)); /* The IOPM assertion API can disable the screensaver as of 10.7. */ data->screensaver_use_iopm = floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6; @@ -173,13 +176,7 @@ Cocoa_CreateImage(SDL_Surface * surface) int i; NSImage *img; - converted = SDL_ConvertSurfaceFormat(surface, -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - SDL_PIXELFORMAT_RGBA8888, -#else - SDL_PIXELFORMAT_ABGR8888, -#endif - 0); + converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGBA32, 0); if (!converted) { return nil; } diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.h b/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.h index 1037badfc..a32de8387 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.h +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.h @@ -125,6 +125,7 @@ extern void Cocoa_SetWindowPosition(_THIS, SDL_Window * window); extern void Cocoa_SetWindowSize(_THIS, SDL_Window * window); extern void Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window); extern void Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window); +extern int Cocoa_SetWindowOpacity(_THIS, SDL_Window * window, float opacity); extern void Cocoa_ShowWindow(_THIS, SDL_Window * window); extern void Cocoa_HideWindow(_THIS, SDL_Window * window); extern void Cocoa_RaiseWindow(_THIS, SDL_Window * window); @@ -132,6 +133,7 @@ extern void Cocoa_MaximizeWindow(_THIS, SDL_Window * window); extern void Cocoa_MinimizeWindow(_THIS, SDL_Window * window); extern void Cocoa_RestoreWindow(_THIS, SDL_Window * window); extern void Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); +extern void Cocoa_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable); extern void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); diff --git a/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.m b/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.m index a4da6cb2d..cfad54854 100644 --- a/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.m +++ b/Engine/lib/sdl/src/video/cocoa/SDL_cocoawindow.m @@ -80,20 +80,20 @@ - (void)sendEvent:(NSEvent *)event { - [super sendEvent:event]; + [super sendEvent:event]; - if ([event type] != NSLeftMouseUp) { - return; - } + if ([event type] != NSLeftMouseUp) { + return; + } - id delegate = [self delegate]; - if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) { - return; - } + id delegate = [self delegate]; + if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) { + return; + } - if ([delegate isMoving]) { - [delegate windowDidFinishMoving]; - } + if ([delegate isMoving]) { + [delegate windowDidFinishMoving]; + } } /* We'll respond to selectors by doing nothing so we don't beep. @@ -116,9 +116,12 @@ - (BOOL)performDragOperation:(id )sender { @autoreleasepool { + SDL_VideoDevice *_this = SDL_GetVideoDevice(); NSPasteboard *pasteboard = [sender draggingPasteboard]; NSArray *types = [NSArray arrayWithObject:NSFilenamesPboardType]; NSString *desiredType = [pasteboard availableTypeFromArray:types]; + SDL_Window *sdlwindow = nil; + if (desiredType == nil) { return NO; /* can't accept anything that's being dropped here. */ } @@ -132,13 +135,10 @@ NSArray *array = [pasteboard propertyListForType:@"NSFilenamesPboardType"]; for (NSString *path in array) { - NSURL *fileURL = [[NSURL fileURLWithPath:path] autorelease]; + NSURL *fileURL = [NSURL fileURLWithPath:path]; 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]; - } + [fileURL getResourceValue:&isAlias forKey:NSURLIsAliasFileKey error:nil]; /* If the URL is an alias, resolve it. */ if ([isAlias boolValue]) { @@ -157,11 +157,22 @@ } } - if (!SDL_SendDropFile([[fileURL path] UTF8String])) { + /* !!! FIXME: is there a better way to do this? */ + if (_this) { + for (sdlwindow = _this->windows; sdlwindow; sdlwindow = sdlwindow->next) { + NSWindow *nswindow = ((SDL_WindowData *) sdlwindow->driverdata)->nswindow; + if (nswindow == self) { + break; + } + } + } + + if (!SDL_SendDropFile(sdlwindow, [[fileURL path] UTF8String])) { return NO; } } + SDL_SendDropComplete(sdlwindow); return YES; }} @@ -196,17 +207,17 @@ ScheduleContextUpdates(SDL_WindowData *data) } } +/* !!! FIXME: this should use a hint callback. */ static int GetHintCtrlClickEmulateRightClick() { - const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK ); - return hint != NULL && *hint != '0'; + return SDL_GetHintBoolean(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, SDL_FALSE); } -static unsigned int +static NSUInteger GetWindowStyle(SDL_Window * window) { - unsigned int style; + NSUInteger style = 0; if (window->flags & SDL_WINDOW_FULLSCREEN) { style = NSBorderlessWindowMask; @@ -224,21 +235,17 @@ GetWindowStyle(SDL_Window * window) } static SDL_bool -SetWindowStyle(SDL_Window * window, unsigned int style) +SetWindowStyle(SDL_Window * window, NSUInteger style) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; NSWindow *nswindow = data->nswindow; - if (![nswindow respondsToSelector: @selector(setStyleMask:)]) { - return SDL_FALSE; - } - /* The view responder chain gets messed with during setStyleMask */ if ([[nswindow contentView] nextResponder] == data->listener) { [[nswindow contentView] setNextResponder:nil]; } - [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)style]; + [nswindow setStyleMask:style]; /* The view responder chain gets messed with during setStyleMask */ if ([[nswindow contentView] nextResponder] != data->listener) { @@ -302,9 +309,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) [view setNextResponder:self]; - if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) { - [view setAcceptsTouchEvents:YES]; - } + [view setAcceptsTouchEvents:YES]; } - (void)observeValueForKeyPath:(NSString *)keyPath @@ -589,12 +594,9 @@ SetWindowStyle(SDL_Window * window, unsigned int style) [NSMenu setMenuBarVisible:NO]; } - /* On pre-10.6, you might have the capslock key state wrong now because we can't check here. */ - if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_6) { - const unsigned int newflags = [NSEvent modifierFlags] & NSAlphaShiftKeyMask; - _data->videodata->modifierFlags = (_data->videodata->modifierFlags & ~NSAlphaShiftKeyMask) | newflags; - SDL_ToggleModState(KMOD_CAPS, newflags != 0); - } + const unsigned int newflags = [NSEvent modifierFlags] & NSAlphaShiftKeyMask; + _data->videodata->modifierFlags = (_data->videodata->modifierFlags & ~NSAlphaShiftKeyMask) | newflags; + SDL_ToggleModState(KMOD_CAPS, newflags != 0); } - (void)windowDidResignKey:(NSNotification *)aNotification @@ -820,23 +822,18 @@ SetWindowStyle(SDL_Window * window, unsigned int style) - (void)mouseDown:(NSEvent *)theEvent { int button; + int clicks; /* Ignore events that aren't inside the client area (i.e. title bar.) */ if ([theEvent window]) { NSRect windowRect = [[[theEvent window] contentView] frame]; - - /* add one to size, since NSPointInRect is exclusive of the bottom - edges, which mean it misses the top of the window by one pixel - (as the origin is the bottom left). */ - windowRect.size.width += 1; - windowRect.size.height += 1; - - if (!NSPointInRect([theEvent locationInWindow], windowRect)) { + if (!NSMouseInRect([theEvent locationInWindow], windowRect, NO)) { return; } } if ([self processHitTest:theEvent]) { + SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return; /* dragging, drop event. */ } @@ -858,10 +855,12 @@ SetWindowStyle(SDL_Window * window, unsigned int style) button = SDL_BUTTON_MIDDLE; break; default: - button = [theEvent buttonNumber] + 1; + button = (int) [theEvent buttonNumber] + 1; break; } - SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button); + + clicks = (int) [theEvent clickCount]; + SDL_SendMouseButtonClicks(_data->window, 0, SDL_PRESSED, button, clicks); } - (void)rightMouseDown:(NSEvent *)theEvent @@ -877,8 +876,10 @@ SetWindowStyle(SDL_Window * window, unsigned int style) - (void)mouseUp:(NSEvent *)theEvent { int button; + int clicks; if ([self processHitTest:theEvent]) { + SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return; /* stopped dragging, drop event. */ } @@ -898,10 +899,12 @@ SetWindowStyle(SDL_Window * window, unsigned int style) button = SDL_BUTTON_MIDDLE; break; default: - button = [theEvent buttonNumber] + 1; + button = (int) [theEvent buttonNumber] + 1; break; } - SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button); + + clicks = (int) [theEvent clickCount]; + SDL_SendMouseButtonClicks(_data->window, 0, SDL_RELEASED, button, clicks); } - (void)rightMouseUp:(NSEvent *)theEvent @@ -922,6 +925,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) int x, y; if ([self processHitTest:theEvent]) { + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return; /* dragging, drop event. */ } @@ -956,13 +960,8 @@ SetWindowStyle(SDL_Window * window, unsigned int style) cgpoint.x = window->x + x; cgpoint.y = window->y + y; - /* According to the docs, this was deprecated in 10.6, but it's still - * around. The substitute requires a CGEventSource, but I'm not entirely - * sure how we'd procure the right one for this event. - */ - CGSetLocalEventsSuppressionInterval(0.0); CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); - CGSetLocalEventsSuppressionInterval(0.25); + CGAssociateMouseAndMouseCursorPosition(YES); Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); #endif @@ -1075,6 +1074,7 @@ SetWindowStyle(SDL_Window * window, unsigned int style) - (void)rightMouseDown:(NSEvent *)theEvent; - (BOOL)mouseDownCanMoveWindow; - (void)drawRect:(NSRect)dirtyRect; +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent; @end @implementation SDLView @@ -1114,6 +1114,15 @@ SetWindowStyle(SDL_Window * window, unsigned int style) cursor:[NSCursor invisibleCursor]]; } } + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + if (SDL_GetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)) { + return SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE); + } else { + return SDL_GetHintBoolean("SDL_MAC_MOUSE_FOCUS_CLICKTHROUGH", SDL_FALSE); + } +} @end static int @@ -1157,7 +1166,7 @@ SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created } { - unsigned int style = [nswindow styleMask]; + unsigned long style = [nswindow styleMask]; if (style == NSBorderlessWindowMask) { window->flags |= SDL_WINDOW_BORDERLESS; @@ -1208,7 +1217,7 @@ Cocoa_CreateWindow(_THIS, SDL_Window * window) SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); NSRect rect; SDL_Rect bounds; - unsigned int style; + NSUInteger style; NSArray *screens = [NSScreen screens]; Cocoa_GetDisplayBounds(_this, display, &bounds); @@ -1263,7 +1272,7 @@ Cocoa_CreateWindow(_THIS, SDL_Window * window) } } - [nswindow setContentView: contentView]; + [nswindow setContentView:contentView]; [contentView release]; /* Allow files and folders to be dragged onto the window by users */ @@ -1470,27 +1479,6 @@ Cocoa_RestoreWindow(_THIS, SDL_Window * window) } }} -static NSWindow * -Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style) -{ - if (!data->created) { - /* Don't mess with other people's windows... */ - return nswindow; - } - - [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]; - - [nswindow close]; - - return data->nswindow; -} - void Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { @autoreleasepool @@ -1502,6 +1490,20 @@ Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) } }} +void +Cocoa_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) +{ @autoreleasepool +{ + /* Don't set this if we're in a space! + * The window will get permanently stuck if resizable is false. + * -flibit + */ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Cocoa_WindowListener *listener = data->listener; + if (![listener isInFullscreenSpace]) { + SetWindowStyle(window, GetWindowStyle(window)); + } +}} void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen) @@ -1532,11 +1534,7 @@ Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display rect.origin.y += (screenRect.size.height - rect.size.height); } - if ([nswindow respondsToSelector: @selector(setStyleMask:)]) { - [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask]; - } else { - nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask); - } + [nswindow setStyleMask:NSBorderlessWindowMask]; } else { rect.origin.x = window->windowed.x; rect.origin.y = window->windowed.y; @@ -1544,16 +1542,12 @@ Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display rect.size.height = window->windowed.h; ConvertNSRect([nswindow screen], fullscreen, &rect); - if ([nswindow respondsToSelector: @selector(setStyleMask:)]) { - [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)]; + [nswindow setStyleMask: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)); - } + /* 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]; } /* The view responder chain gets messed with during setStyleMask */ @@ -1767,6 +1761,14 @@ Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled) return 0; /* just succeed, the real work is done elsewhere. */ } +int +Cocoa_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + [data->nswindow setAlphaValue:opacity]; + return 0; +} + #endif /* SDL_VIDEO_DRIVER_COCOA */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_video.c b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_video.c index 5579759eb..d339dd78e 100644 --- a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_video.c +++ b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_video.c @@ -121,6 +121,7 @@ DirectFB_CreateDevice(int devindex) device->SetWindowIcon = DirectFB_SetWindowIcon; device->SetWindowPosition = DirectFB_SetWindowPosition; device->SetWindowSize = DirectFB_SetWindowSize; + device->SetWindowOpacity = DirectFB_SetWindowOpacity; device->ShowWindow = DirectFB_ShowWindow; device->HideWindow = DirectFB_HideWindow; device->RaiseWindow = DirectFB_RaiseWindow; diff --git a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.c b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.c index 3b8b45d44..40bbe6aee 100644 --- a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.c +++ b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.c @@ -529,4 +529,17 @@ DirectFB_AdjustWindowSurface(SDL_Window * window) return; } +int +DirectFB_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) +{ + const Uint8 alpha = (Uint8) ((unsigned int) (opacity * 255.0f)); + SDL_DFB_WINDOWDATA(window); + SDL_DFB_CHECKERR(windata->dfbwin->SetOpacity(windata->dfbwin, alpha)); + windata->opacity = alpha; + return 0; + +error: + return -1; +} + #endif /* SDL_VIDEO_DRIVER_DIRECTFB */ diff --git a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.h b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.h index 658cc8749..4b9970812 100644 --- a/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.h +++ b/Engine/lib/sdl/src/video/directfb/SDL_DirectFB_window.h @@ -75,6 +75,7 @@ extern SDL_bool DirectFB_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); extern void DirectFB_AdjustWindowSurface(SDL_Window * window); +extern int DirectFB_SetWindowOpacity(_THIS, SDL_Window * window, float opacity); #endif /* _SDL_directfb_window_h */ diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.c index 0f915c6f3..a4720e402 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.c @@ -217,16 +217,16 @@ static const SDL_Scancode emscripten_scancode_table[] = { /* 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, + /* 174 */ SDL_SCANCODE_VOLUMEDOWN, /*IE, Chrome*/ + /* 175 */ SDL_SCANCODE_VOLUMEUP, /*IE, Chrome*/ + /* 176 */ SDL_SCANCODE_AUDIONEXT, /*IE, Chrome*/ + /* 177 */ SDL_SCANCODE_AUDIOPREV, /*IE, Chrome*/ /* 178 */ SDL_SCANCODE_UNKNOWN, - /* 179 */ SDL_SCANCODE_UNKNOWN, + /* 179 */ SDL_SCANCODE_AUDIOPLAY, /*IE, Chrome*/ /* 180 */ SDL_SCANCODE_UNKNOWN, - /* 181 */ SDL_SCANCODE_UNKNOWN, - /* 182 */ SDL_SCANCODE_UNKNOWN, - /* 183 */ SDL_SCANCODE_UNKNOWN, + /* 181 */ SDL_SCANCODE_AUDIOMUTE, /*FX*/ + /* 182 */ SDL_SCANCODE_VOLUMEDOWN, /*FX*/ + /* 183 */ SDL_SCANCODE_VOLUMEUP, /*FX*/ /* 184 */ SDL_SCANCODE_UNKNOWN, /* 185 */ SDL_SCANCODE_UNKNOWN, /* 186 */ SDL_SCANCODE_SEMICOLON, /*IE, Chrome, D3E legacy*/ @@ -301,25 +301,34 @@ EM_BOOL Emscripten_HandleMouseMove(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData) { SDL_WindowData *window_data = userData; - int mx = mouseEvent->canvasX, my = mouseEvent->canvasY; + int mx, my; + static double residualx = 0, residualy = 0; EmscriptenPointerlockChangeEvent pointerlock_status; - /* check for pointer lock */ - emscripten_get_pointerlock_status(&pointerlock_status); + /* rescale (in case canvas is being scaled)*/ + double client_w, client_h, xscale, yscale; + emscripten_get_element_css_size(NULL, &client_w, &client_h); + xscale = window_data->window->w / client_w; + yscale = window_data->window->h / client_h; - if (pointerlock_status.isActive) { - mx = mouseEvent->movementX; - my = mouseEvent->movementY; + /* check for pointer lock */ + int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status); + int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS ? pointerlock_status.isActive : SDL_FALSE; + + if (isPointerLocked) { + residualx += mouseEvent->movementX * xscale; + residualy += mouseEvent->movementY * yscale; + /* Let slow sub-pixel motion accumulate. Don't lose it. */ + mx = residualx; + residualx -= mx; + my = residualy; + residualy -= my; + } else { + mx = mouseEvent->canvasX * xscale; + my = mouseEvent->canvasY * yscale; } - /* 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); + SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my); return 0; } @@ -341,16 +350,36 @@ Emscripten_HandleMouseButton(int eventType, const EmscriptenMouseEvent *mouseEve default: return 0; } - SDL_SendMouseButton(window_data->window, 0, eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED, sdl_button); - return 1; + + SDL_EventType sdl_event_type = (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN ? SDL_PRESSED : SDL_RELEASED); + SDL_SendMouseButton(window_data->window, 0, sdl_event_type, sdl_button); + return SDL_GetEventState(sdl_event_type) == SDL_ENABLE; } 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; + + int mx = mouseEvent->canvasX, my = mouseEvent->canvasY; + EmscriptenPointerlockChangeEvent pointerlock_status; + + /* check for pointer lock */ + int isPointerLockSupported = emscripten_get_pointerlock_status(&pointerlock_status); + int isPointerLocked = isPointerLockSupported == EMSCRIPTEN_RESULT_SUCCESS ? pointerlock_status.isActive : SDL_FALSE; + + if (!isPointerLocked) { + /* 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); + my = my * (window_data->window->h / client_h); + SDL_SendMouseMotion(window_data->window, 0, isPointerLocked, mx, my); + } + + SDL_SetMouseFocus(eventType == EMSCRIPTEN_EVENT_MOUSEENTER ? window_data->window : NULL); + return SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE; } EM_BOOL @@ -358,15 +387,22 @@ Emscripten_HandleWheel(int eventType, const EmscriptenWheelEvent *wheelEvent, vo { SDL_WindowData *window_data = userData; SDL_SendMouseWheel(window_data->window, 0, wheelEvent->deltaX, -wheelEvent->deltaY, SDL_MOUSEWHEEL_NORMAL); - return 1; + return SDL_GetEventState(SDL_MOUSEWHEEL) == SDL_ENABLE; } EM_BOOL Emscripten_HandleFocus(int eventType, const EmscriptenFocusEvent *wheelEvent, void *userData) { SDL_WindowData *window_data = userData; + /* If the user switches away while keys are pressed (such as + * via Alt+Tab), key release events won't be received. */ + if (eventType == EMSCRIPTEN_EVENT_BLUR) { + SDL_ResetKeyboard(); + } + + SDL_SendWindowEvent(window_data->window, eventType == EMSCRIPTEN_EVENT_FOCUS ? SDL_WINDOWEVENT_FOCUS_GAINED : SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); - return 1; + return SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE; } EM_BOOL @@ -374,12 +410,16 @@ Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, vo { SDL_WindowData *window_data = userData; int i; + double client_w, client_h; + int preventDefault = 0; SDL_TouchID deviceId = 1; if (SDL_AddTouch(deviceId, "") < 0) { return 0; } + emscripten_get_element_css_size(NULL, &client_w, &client_h); + for (i = 0; i < touchEvent->numTouches; i++) { SDL_FingerID id; float x, y; @@ -388,20 +428,44 @@ Emscripten_HandleTouch(int eventType, const EmscriptenTouchEvent *touchEvent, vo 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; + x = touchEvent->touches[i].canvasX / client_w; + y = touchEvent->touches[i].canvasY / client_h; - if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { - SDL_SendTouchMotion(deviceId, id, x, y, 1.0f); - } else if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) { + if (!window_data->finger_touching) { + window_data->finger_touching = SDL_TRUE; + window_data->first_finger = id; + SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y); + SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + } SDL_SendTouch(deviceId, id, SDL_TRUE, x, y, 1.0f); + + if (!preventDefault && SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) { + preventDefault = 1; + } + } else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) { + if ((window_data->finger_touching) && (window_data->first_finger == id)) { + SDL_SendMouseMotion(window_data->window, SDL_TOUCH_MOUSEID, 0, x, y); + } + SDL_SendTouchMotion(deviceId, id, x, y, 1.0f); + + if (!preventDefault && SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) { + preventDefault = 1; + } } else { + if ((window_data->finger_touching) && (window_data->first_finger == id)) { + SDL_SendMouseButton(window_data->window, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + window_data->finger_touching = SDL_FALSE; + } SDL_SendTouch(deviceId, id, SDL_FALSE, x, y, 1.0f); + + if (!preventDefault && SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) { + preventDefault = 1; + } } } - - return 1; + return preventDefault; } EM_BOOL @@ -431,16 +495,19 @@ Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, voi break; } } - SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? - SDL_PRESSED : SDL_RELEASED, scancode); + 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 + SDL_bool prevent_default = SDL_GetEventState(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_KEYDOWN : SDL_KEYUP) == SDL_ENABLE; + + /* if TEXTINPUT events are enabled we can't prevent keydown or we won't get keypress + * 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 */; + if (eventType == EMSCRIPTEN_EVENT_KEYDOWN && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE && keyEvent->keyCode != 8 /* backspace */ && keyEvent->keyCode != 9 /* tab */) + prevent_default = SDL_FALSE; + + return prevent_default; } EM_BOOL @@ -450,65 +517,24 @@ Emscripten_HandleKeyPress(int eventType, const EmscriptenKeyboardEvent *keyEvent if (Emscripten_ConvertUTF32toUTF8(keyEvent->charCode, text)) { SDL_SendKeyboardText(text); } - return 1; + return SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE; } 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); - } + if(!window_data->requested_fullscreen_mode) + window_data->window->flags |= SDL_WINDOW_FULLSCREEN; /*we didn't reqest fullscreen*/ } 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; } @@ -519,17 +545,11 @@ 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 + /* update pixel ratio */ + window_data->pixel_ratio = emscripten_get_device_pixel_ratio(); + + if(!(window_data->window->flags & FULLSCREEN_MASK)) { /* this will only work if the canvas size is set through css */ if(window_data->window->flags & SDL_WINDOW_RESIZABLE) @@ -555,6 +575,22 @@ Emscripten_HandleResize(int eventType, const EmscriptenUiEvent *uiEvent, void *u return 0; } +EM_BOOL +Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData) +{ + /*this is used during fullscreen changes*/ + SDL_WindowData *window_data = userData; + + if(window_data->fullscreen_resize) + { + double css_w, css_h; + emscripten_get_element_css_size(NULL, &css_w, &css_h); + SDL_SendWindowEvent(window_data->window, SDL_WINDOWEVENT_RESIZED, css_w, css_h); + } + + return 0; +} + EM_BOOL Emscripten_HandleVisibilityChange(int eventType, const EmscriptenVisibilityChangeEvent *visEvent, void *userData) { @@ -570,15 +606,15 @@ Emscripten_RegisterEventHandlers(SDL_WindowData *data) 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_mouseup_callback("#document", 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_focus_callback("#window", data, 0, Emscripten_HandleFocus); + emscripten_set_blur_callback("#window", data, 0, Emscripten_HandleFocus); emscripten_set_touchstart_callback("#canvas", data, 0, Emscripten_HandleTouch); emscripten_set_touchend_callback("#canvas", data, 0, Emscripten_HandleTouch); @@ -607,15 +643,15 @@ Emscripten_UnregisterEventHandlers(SDL_WindowData *data) 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_mouseup_callback("#document", 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_focus_callback("#window", NULL, 0, NULL); + emscripten_set_blur_callback("#window", NULL, 0, NULL); emscripten_set_touchstart_callback("#canvas", NULL, 0, NULL); emscripten_set_touchend_callback("#canvas", NULL, 0, NULL); diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.h b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.h index d5b65f854..089ff60da 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.h +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenevents.h @@ -30,6 +30,9 @@ Emscripten_RegisterEventHandlers(SDL_WindowData *data); extern void Emscripten_UnregisterEventHandlers(SDL_WindowData *data); + +extern int +Emscripten_HandleCanvasResize(int eventType, const void *reserved, void *userData); #endif /* _SDL_emscriptenevents_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c index a26e23ae6..8a6a465d9 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -69,15 +69,25 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec /* Send the data to the display */ EM_ASM_INT({ - //TODO: don't create context every update - var ctx = Module['canvas'].getContext('2d'); + var w = $0; + var h = $1; + var pixels = $2; - //library_sdl.js SDL_UnlockSurface - var image = ctx.createImageData($0, $1); - var data = image.data; - var src = $2 >> 2; + if (!Module['SDL2']) Module['SDL2'] = {}; + var SDL2 = Module['SDL2']; + if (SDL2.ctxCanvas !== Module['canvas']) { + SDL2.ctx = Module['createContext'](Module['canvas'], false, true); + SDL2.ctxCanvas = Module['canvas']; + } + if (SDL2.w !== w || SDL2.h !== h || SDL2.imageCtx !== SDL2.ctx) { + SDL2.image = SDL2.ctx.createImageData(w, h); + SDL2.w = w; + SDL2.h = h; + SDL2.imageCtx = SDL2.ctx; + } + var data = SDL2.image.data; + var src = pixels >> 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, @@ -90,26 +100,58 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec data[dst ] = val & 0xff; data[dst+1] = (val >> 8) & 0xff; data[dst+2] = (val >> 16) & 0xff; - data[dst+3] = isScreen ? 0xff : ((val >> 24) & 0xff); + data[dst+3] = 0xff; src++; dst += 4; } } else { - var data32 = new Uint32Array(data.buffer); + if (SDL2.data32Data !== data) { + SDL2.data32 = new Int32Array(data.buffer); + SDL2.data8 = new Uint8Array(data.buffer); + } + var data32 = SDL2.data32; 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; + // logically we need to do + // while (dst < num) { + // data32[dst++] = HEAP32[src++] | 0xff000000 + // } + // the following code is faster though, because + // .set() is almost free - easily 10x faster due to + // native memcpy efficiencies, and the remaining loop + // just stores, not load + store, so it is faster + data32.set(HEAP32.subarray(src, src + num)); + var data8 = SDL2.data8; + var i = 3; + var j = i + 4*num; + if (num % 8 == 0) { + // unrolling gives big speedups + while (i < j) { + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; + data8[i] = 0xff; + i = i + 4 | 0; } - } else { - while (dst < num) { - data32[dst++] = HEAP32[src++]; + } else { + while (i < j) { + data8[i] = 0xff; + i = i + 4 | 0; } } } - ctx.putImageData(image, 0, 0); + SDL2.ctx.putImageData(SDL2.image, 0, 0); return 0; }, surface->w, surface->h, surface->pixels); diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c index 2a68dd95c..512ad2220 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenmouse.c @@ -58,11 +58,13 @@ Emscripten_CreateDefaultCursor() 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) @@ -200,7 +202,9 @@ Emscripten_InitMouse() { SDL_Mouse* mouse = SDL_GetMouse(); +/* mouse->CreateCursor = Emscripten_CreateCursor; +*/ mouse->ShowCursor = Emscripten_ShowCursor; mouse->FreeCursor = Emscripten_FreeCursor; mouse->WarpMouse = Emscripten_WarpMouse; diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c index 302ca8793..847bb4cf8 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.c @@ -24,6 +24,7 @@ #include "SDL_video.h" #include "SDL_mouse.h" +#include "SDL_hints.h" #include "../SDL_sysvideo.h" #include "../SDL_pixels_c.h" #include "../SDL_egl_c.h" @@ -47,6 +48,7 @@ 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); +static void Emscripten_SetWindowTitle(_THIS, SDL_Window * window); /* Emscripten driver bootstrap functions */ @@ -75,6 +77,12 @@ Emscripten_CreateDevice(int devindex) return (0); } + /* Firefox sends blur event which would otherwise prevent full screen + * when the user clicks to allow full screen. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=1144964 + */ + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + /* Set the function pointers */ device->VideoInit = Emscripten_VideoInit; device->VideoQuit = Emscripten_VideoQuit; @@ -84,9 +92,9 @@ Emscripten_CreateDevice(int devindex) device->PumpEvents = Emscripten_PumpEvents; device->CreateWindow = Emscripten_CreateWindow; - /*device->CreateWindowFrom = Emscripten_CreateWindowFrom; + /*device->CreateWindowFrom = Emscripten_CreateWindowFrom;*/ device->SetWindowTitle = Emscripten_SetWindowTitle; - device->SetWindowIcon = Emscripten_SetWindowIcon; + /*device->SetWindowIcon = Emscripten_SetWindowIcon; device->SetWindowPosition = Emscripten_SetWindowPosition;*/ device->SetWindowSize = Emscripten_SetWindowSize; /*device->ShowWindow = Emscripten_ShowWindow; @@ -129,15 +137,17 @@ 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 = EM_ASM_INT_V({ + return screen.width; + }); - mode.w = css_w; - mode.h = css_h; + mode.h = EM_ASM_INT_V({ + return screen.height; + }); mode.refresh_rate = 0; mode.driverdata = NULL; @@ -199,7 +209,7 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window) emscripten_get_element_css_size(NULL, &css_w, &css_h); - wdata->external_size = css_w != scaled_w || css_h != scaled_h; + wdata->external_size = SDL_floor(css_w) != scaled_w || SDL_floor(css_h) != scaled_h; if ((window->flags & SDL_WINDOW_RESIZABLE) && wdata->external_size) { /* external css has resized us */ @@ -218,9 +228,6 @@ Emscripten_CreateWindow(_THIS, SDL_Window * window) } } - 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) { @@ -255,6 +262,8 @@ static void Emscripten_SetWindowSize(_THIS, SDL_Window * window) if (window->driverdata) { data = (SDL_WindowData *) window->driverdata; + /* update pixel ratio */ + data->pixel_ratio = emscripten_get_device_pixel_ratio(); emscripten_set_canvas_size(window->w * data->pixel_ratio, window->h * data->pixel_ratio); /*scale canvas down*/ @@ -290,30 +299,49 @@ Emscripten_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * di data = (SDL_WindowData *) window->driverdata; if(fullscreen) { + EmscriptenFullscreenStrategy strategy; + SDL_bool is_desktop_fullscreen = (window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP; + int res; + + strategy.scaleMode = is_desktop_fullscreen ? EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH : EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT; + + if(!is_desktop_fullscreen) { + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE; + } else if(window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF; + } else { + strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; + } + + strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; + + strategy.canvasResizedCallback = Emscripten_HandleCanvasResize; + strategy.canvasResizedCallbackUserData = data; + 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); + data->fullscreen_resize = is_desktop_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); + res = emscripten_request_fullscreen_strategy(NULL, 1, &strategy); + if(res != EMSCRIPTEN_RESULT_SUCCESS && res != EMSCRIPTEN_RESULT_DEFERRED) { + /* unset flags, fullscreen failed */ + window->flags &= ~(SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN); + } } else emscripten_exit_fullscreen(); } } +static void +Emscripten_SetWindowTitle(_THIS, SDL_Window * window) { + EM_ASM_INT({ + if (typeof Module['setWindowTitle'] !== 'undefined') { + Module['setWindowTitle'](Module['Pointer_stringify']($0)); + } + return 0; + }, window->title); +} + #endif /* SDL_VIDEO_DRIVER_EMSCRIPTEN */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.h b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.h index e824de34f..7618ab6cc 100644 --- a/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.h +++ b/Engine/lib/sdl/src/video/emscripten/SDL_emscriptenvideo.h @@ -24,6 +24,7 @@ #define _SDL_emscriptenvideo_h #include "../SDL_sysvideo.h" +#include "../../events/SDL_touch_c.h" #include #include @@ -37,14 +38,15 @@ typedef struct SDL_WindowData SDL_Window *window; SDL_Surface *surface; - int windowed_width; - int windowed_height; - float pixel_ratio; SDL_bool external_size; int requested_fullscreen_mode; + SDL_bool fullscreen_resize; + + SDL_bool finger_touching; /* for mapping touch events to mice */ + SDL_FingerID first_finger; } SDL_WindowData; #endif /* _SDL_emscriptenvideo_h */ diff --git a/Engine/lib/sdl/src/video/haiku/SDL_BWin.h b/Engine/lib/sdl/src/video/haiku/SDL_BWin.h index dade664c3..a353e1aca 100644 --- a/Engine/lib/sdl/src/video/haiku/SDL_BWin.h +++ b/Engine/lib/sdl/src/video/haiku/SDL_BWin.h @@ -56,6 +56,7 @@ enum WinCommands { BWIN_RESTORE_WINDOW, BWIN_SET_TITLE, BWIN_SET_BORDERED, + BWIN_SET_RESIZABLE, BWIN_FULLSCREEN }; @@ -336,16 +337,30 @@ class SDL_BWin:public BDirectWindow break; case B_KEY_DOWN: + { + int32 i = 0; + int8 byte; + int8 bytes[4] = { 0, 0, 0, 0 }; + while (i < 4 && msg->FindInt8("byte", i, &byte) == B_OK) { + bytes[i] = byte; + i++; + } + if (msg->FindInt32("key", &key) == B_OK) { + _KeyEvent((SDL_Scancode)key, &bytes[0], i, SDL_PRESSED); + } + } + break; + case B_UNMAPPED_KEY_DOWN: /* modifier keys are unmapped */ if (msg->FindInt32("key", &key) == B_OK) { - _KeyEvent((SDL_Scancode)key, SDL_PRESSED); + _KeyEvent((SDL_Scancode)key, NULL, 0, SDL_PRESSED); } break; case B_KEY_UP: case B_UNMAPPED_KEY_UP: /* modifier keys are unmapped */ if (msg->FindInt32("key", &key) == B_OK) { - _KeyEvent(key, SDL_RELEASED); + _KeyEvent(key, NULL, 0, SDL_RELEASED); } break; @@ -378,6 +393,9 @@ class SDL_BWin:public BDirectWindow case BWIN_SET_BORDERED: _SetBordered(message); break; + case BWIN_SET_RESIZABLE: + _SetResizable(message); + break; case BWIN_SHOW_WINDOW: Show(); break; @@ -508,13 +526,15 @@ private: _PostWindowEvent(msg); } - void _KeyEvent(int32 keyCode, int32 keyState) { + void _KeyEvent(int32 keyCode, const int8 *keyUtf8, const ssize_t & len, int32 keyState) { /* Create a message to pass along to the BeApp thread */ BMessage msg(BAPP_KEY); msg.AddInt32("key-state", keyState); msg.AddInt32("key-scancode", keyCode); + if (keyUtf8 != NULL) { + msg.AddData("key-utf8", B_INT8_TYPE, (const void*)keyUtf8, len); + } be_app->PostMessage(&msg); - /* Apparently SDL only uses the scancode */ } void _RepaintEvent() { @@ -568,6 +588,18 @@ private: SetLook(bEnabled ? B_BORDERED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK); } + void _SetResizable(BMessage *msg) { + bool bEnabled; + if(msg->FindBool("window-resizable", &bEnabled) != B_OK) { + return; + } + if (bEnabled) { + SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); + } else { + SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); + } + } + void _Restore() { if(IsMinimized()) { Minimize(false); diff --git a/Engine/lib/sdl/src/video/haiku/SDL_bvideo.cc b/Engine/lib/sdl/src/video/haiku/SDL_bvideo.cc index 8c243b7a0..8986c609c 100644 --- a/Engine/lib/sdl/src/video/haiku/SDL_bvideo.cc +++ b/Engine/lib/sdl/src/video/haiku/SDL_bvideo.cc @@ -81,6 +81,7 @@ BE_CreateDevice(int devindex) device->MinimizeWindow = BE_MinimizeWindow; device->RestoreWindow = BE_RestoreWindow; device->SetWindowBordered = BE_SetWindowBordered; + device->SetWindowResizable = BE_SetWindowResizable; device->SetWindowFullscreen = BE_SetWindowFullscreen; device->SetWindowGammaRamp = BE_SetWindowGammaRamp; device->GetWindowGammaRamp = BE_GetWindowGammaRamp; diff --git a/Engine/lib/sdl/src/video/haiku/SDL_bwindow.cc b/Engine/lib/sdl/src/video/haiku/SDL_bwindow.cc index 287eac965..a35471df5 100644 --- a/Engine/lib/sdl/src/video/haiku/SDL_bwindow.cc +++ b/Engine/lib/sdl/src/video/haiku/SDL_bwindow.cc @@ -145,6 +145,12 @@ void BE_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { _ToBeWin(window)->PostMessage(&msg); } +void BE_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) { + BMessage msg(BWIN_SET_RESIZABLE); + msg.AddBool("window-resizable", resizable != SDL_FALSE); + _ToBeWin(window)->PostMessage(&msg); +} + void BE_ShowWindow(_THIS, SDL_Window * window) { BMessage msg(BWIN_SHOW_WINDOW); _ToBeWin(window)->PostMessage(&msg); diff --git a/Engine/lib/sdl/src/video/haiku/SDL_bwindow.h b/Engine/lib/sdl/src/video/haiku/SDL_bwindow.h index f64530ab7..388443dac 100644 --- a/Engine/lib/sdl/src/video/haiku/SDL_bwindow.h +++ b/Engine/lib/sdl/src/video/haiku/SDL_bwindow.h @@ -39,6 +39,7 @@ extern void BE_MaximizeWindow(_THIS, SDL_Window * window); extern void BE_MinimizeWindow(_THIS, SDL_Window * window); extern void BE_RestoreWindow(_THIS, SDL_Window * window); extern void BE_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); +extern void BE_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable); extern void BE_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int BE_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int BE_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirdyn.c b/Engine/lib/sdl/src/video/mir/SDL_mirdyn.c index f9dfc0395..6bbe53759 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirdyn.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirdyn.c @@ -84,9 +84,8 @@ MIR_GetSym(const char *fnname, int *pHasModule) /* Define all the function pointers and wrappers... */ #define SDL_MIR_MODULE(modname) int SDL_MIR_HAVE_##modname = 0; #define SDL_MIR_SYM(rc,fn,params) SDL_DYNMIRFN_##fn MIR_##fn = NULL; +#define SDL_MIR_SYM_CONST(type,name) SDL_DYMMIRCONST_##name MIR_##name = NULL; #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM static int mir_load_refcount = 0; @@ -103,9 +102,8 @@ SDL_MIR_UnloadSymbols(void) /* set all the function pointers to NULL. */ #define SDL_MIR_MODULE(modname) SDL_MIR_HAVE_##modname = 0; #define SDL_MIR_SYM(rc,fn,params) MIR_##fn = NULL; +#define SDL_MIR_SYM_CONST(type,name) MIR_##name = NULL; #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM #ifdef SDL_VIDEO_DRIVER_MIR_DYNAMIC @@ -138,16 +136,12 @@ SDL_MIR_LoadSymbols(void) } #define SDL_MIR_MODULE(modname) SDL_MIR_HAVE_##modname = 1; /* default yes */ -#define SDL_MIR_SYM(rc,fn,params) #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM #define SDL_MIR_MODULE(modname) thismod = &SDL_MIR_HAVE_##modname; #define SDL_MIR_SYM(rc,fn,params) MIR_##fn = (SDL_DYNMIRFN_##fn) MIR_GetSym(#fn,thismod); +#define SDL_MIR_SYM_CONST(type,name) MIR_##name = *(SDL_DYMMIRCONST_##name*) MIR_GetSym(#name,thismod); #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM if ((SDL_MIR_HAVE_MIR_CLIENT) && (SDL_MIR_HAVE_XKBCOMMON)) { /* all required symbols loaded. */ @@ -162,9 +156,8 @@ SDL_MIR_LoadSymbols(void) #define SDL_MIR_MODULE(modname) SDL_MIR_HAVE_##modname = 1; /* default yes */ #define SDL_MIR_SYM(rc,fn,params) MIR_##fn = fn; +#define SDL_MIR_SYM_CONST(type,name) MIR_##name = name; #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM #endif } diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirdyn.h b/Engine/lib/sdl/src/video/mir/SDL_mirdyn.h index 48bf489c6..a3638cf05 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirdyn.h +++ b/Engine/lib/sdl/src/video/mir/SDL_mirdyn.h @@ -36,13 +36,13 @@ int SDL_MIR_LoadSymbols(void); void SDL_MIR_UnloadSymbols(void); /* Declare all the function pointers and wrappers... */ -#define SDL_MIR_MODULE(modname) #define SDL_MIR_SYM(rc,fn,params) \ typedef rc (*SDL_DYNMIRFN_##fn) params; \ extern SDL_DYNMIRFN_##fn MIR_##fn; +#define SDL_MIR_SYM_CONST(type, name) \ + typedef type SDL_DYMMIRCONST_##name; \ + extern SDL_DYMMIRCONST_##name MIR_##name; #include "SDL_mirsym.h" -#undef SDL_MIR_MODULE -#undef SDL_MIR_SYM #ifdef __cplusplus } diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirevents.c b/Engine/lib/sdl/src/video/mir/SDL_mirevents.c index 708f8ffde..e36986835 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirevents.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirevents.c @@ -53,73 +53,79 @@ HandleKeyText(int32_t key_code) } } -static void -CheckKeyboardFocus(SDL_Window* sdl_window) -{ - SDL_Window* keyboard_window = SDL_GetKeyboardFocus(); - - if (keyboard_window != sdl_window) - SDL_SetKeyboardFocus(sdl_window); -} - - /* FIXME Mir still needs to implement its IM API, for now we assume a single key press produces a character. */ static void -HandleKeyEvent(MirKeyEvent const ev, SDL_Window* window) +HandleKeyEvent(MirKeyboardEvent const* key_event, SDL_Window* window) { - uint32_t scancode = SDL_SCANCODE_UNKNOWN; - Uint8 key_state = ev.action == mir_key_action_up ? SDL_RELEASED : SDL_PRESSED; + xkb_keysym_t key_code; + Uint8 key_state; + int event_scancode; + uint32_t sdl_scancode = SDL_SCANCODE_UNKNOWN; - CheckKeyboardFocus(window); + MirKeyboardAction action = MIR_mir_keyboard_event_action(key_event); - if (ev.scan_code < SDL_arraysize(xfree86_scancode_table2)) - scancode = xfree86_scancode_table2[ev.scan_code]; + key_state = SDL_PRESSED; + key_code = MIR_mir_keyboard_event_key_code(key_event); + event_scancode = MIR_mir_keyboard_event_scan_code(key_event); - if (scancode != SDL_SCANCODE_UNKNOWN) - SDL_SendKeyboardKey(key_state, scancode); + if (action == mir_keyboard_action_up) + key_state = SDL_RELEASED; + + if (event_scancode < SDL_arraysize(xfree86_scancode_table2)) + sdl_scancode = xfree86_scancode_table2[event_scancode]; + + if (sdl_scancode != SDL_SCANCODE_UNKNOWN) + SDL_SendKeyboardKey(key_state, sdl_scancode); if (key_state == SDL_PRESSED) - HandleKeyText(ev.key_code); + HandleKeyText(key_code); } static void -HandleMouseButton(SDL_Window* sdl_window, Uint8 state, MirMotionButton button_state) +HandleMouseButton(SDL_Window* sdl_window, Uint8 state, MirPointerEvent const* pointer) { - static uint32_t last_sdl_button; - uint32_t sdl_button; + uint32_t sdl_button = SDL_BUTTON_LEFT; + MirPointerButton button_state = mir_pointer_button_primary; + + static uint32_t old_button_states = 0; + uint32_t new_button_states = MIR_mir_pointer_event_buttons(pointer); + + // XOR on our old button states vs our new states to get the newley pressed/released button + button_state = new_button_states ^ old_button_states; switch (button_state) { - case mir_motion_button_primary: + case mir_pointer_button_primary: sdl_button = SDL_BUTTON_LEFT; break; - case mir_motion_button_secondary: + case mir_pointer_button_secondary: sdl_button = SDL_BUTTON_RIGHT; break; - case mir_motion_button_tertiary: + case mir_pointer_button_tertiary: sdl_button = SDL_BUTTON_MIDDLE; break; - case mir_motion_button_forward: + case mir_pointer_button_forward: sdl_button = SDL_BUTTON_X1; break; - case mir_motion_button_back: + case mir_pointer_button_back: sdl_button = SDL_BUTTON_X2; break; default: - sdl_button = last_sdl_button; break; } - last_sdl_button = sdl_button; + old_button_states = new_button_states; + SDL_SendMouseButton(sdl_window, 0, state, sdl_button); } static void HandleMouseMotion(SDL_Window* sdl_window, int x, int y) { - SDL_SendMouseMotion(sdl_window, 0, 0, x, y); + SDL_Mouse* mouse = SDL_GetMouse(); + SDL_SendMouseMotion(sdl_window, 0, mouse->relative_mode, x, y); } static void @@ -148,71 +154,102 @@ AddTouchDevice(int device_id) } static void -HandleTouchEvent(MirMotionEvent const motion, int cord_index, SDL_Window* sdl_window) +HandleTouchEvent(MirTouchEvent const* touch, int device_id, SDL_Window* sdl_window) { - int device_id = motion.device_id; - int id = motion.pointer_coordinates[cord_index].id; + int i, point_count; + point_count = MIR_mir_touch_event_point_count(touch); - int width = sdl_window->w; - int height = sdl_window->h; - float x = motion.pointer_coordinates[cord_index].x; - float y = motion.pointer_coordinates[cord_index].y; + AddTouchDevice(device_id); - float n_x = x / width; - float n_y = y / height; - float pressure = motion.pointer_coordinates[cord_index].pressure; + for (i = 0; i < point_count; i++) { + int id = MIR_mir_touch_event_id(touch, i); - AddTouchDevice(motion.device_id); + int width = sdl_window->w; + int height = sdl_window->h; - switch (motion.action) { - case mir_motion_action_down: - case mir_motion_action_pointer_down: - HandleTouchPress(device_id, id, SDL_TRUE, n_x, n_y, pressure); - break; - case mir_motion_action_up: - case mir_motion_action_pointer_up: - HandleTouchPress(device_id, id, SDL_FALSE, n_x, n_y, pressure); - break; - case mir_motion_action_hover_move: - case mir_motion_action_move: - HandleTouchMotion(device_id, id, n_x, n_y, pressure); - break; - default: - break; + float x = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_x); + float y = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_y); + + float n_x = x / width; + float n_y = y / height; + + float pressure = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_pressure); + + switch (MIR_mir_touch_event_action(touch, i)) { + case mir_touch_action_up: + HandleTouchPress(device_id, id, SDL_FALSE, n_x, n_y, pressure); + break; + case mir_touch_action_down: + HandleTouchPress(device_id, id, SDL_TRUE, n_x, n_y, pressure); + break; + case mir_touch_action_change: + HandleTouchMotion(device_id, id, n_x, n_y, pressure); + break; + case mir_touch_actions: + break; + } } } static void -HandleMouseEvent(MirMotionEvent const motion, int cord_index, SDL_Window* sdl_window) +HandleMouseEvent(MirPointerEvent const* pointer, SDL_Window* sdl_window) { SDL_SetMouseFocus(sdl_window); - switch (motion.action) { - case mir_motion_action_down: - case mir_motion_action_pointer_down: - HandleMouseButton(sdl_window, SDL_PRESSED, motion.button_state); + switch (MIR_mir_pointer_event_action(pointer)) { + case mir_pointer_action_button_down: + HandleMouseButton(sdl_window, SDL_PRESSED, pointer); break; - case mir_motion_action_up: - case mir_motion_action_pointer_up: - HandleMouseButton(sdl_window, SDL_RELEASED, motion.button_state); + case mir_pointer_action_button_up: + HandleMouseButton(sdl_window, SDL_RELEASED, pointer); break; - case mir_motion_action_hover_move: - case mir_motion_action_move: - HandleMouseMotion(sdl_window, - motion.pointer_coordinates[cord_index].x, - motion.pointer_coordinates[cord_index].y); + case mir_pointer_action_motion: { + int x, y; + int hscroll, vscroll; + SDL_Mouse* mouse = SDL_GetMouse(); + x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_x); + y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_y); + + if (mouse) { + if (mouse->relative_mode) { + int relative_x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_x); + int relative_y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_y); + HandleMouseMotion(sdl_window, relative_x, relative_y); + } + else if (mouse->x != x || mouse->y != y) { + HandleMouseMotion(sdl_window, x, y); + } + } + + hscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_hscroll); + vscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_vscroll); + if (vscroll != 0 || hscroll != 0) + HandleMouseScroll(sdl_window, hscroll, vscroll); + } break; - case mir_motion_action_outside: + case mir_pointer_action_leave: SDL_SetMouseFocus(NULL); break; - case mir_motion_action_scroll: - HandleMouseScroll(sdl_window, - motion.pointer_coordinates[cord_index].hscroll, - motion.pointer_coordinates[cord_index].vscroll); + case mir_pointer_action_enter: + default: break; - case mir_motion_action_cancel: - case mir_motion_action_hover_enter: - case mir_motion_action_hover_exit: + } +} + +static void +MIR_HandleInput(MirInputEvent const* input_event, SDL_Window* window) +{ + switch (MIR_mir_input_event_get_type(input_event)) { + case (mir_input_event_type_key): + HandleKeyEvent(MIR_mir_input_event_get_keyboard_event(input_event), window); + break; + case (mir_input_event_type_pointer): + HandleMouseEvent(MIR_mir_input_event_get_pointer_event(input_event), window); + break; + case (mir_input_event_type_touch): + HandleTouchEvent(MIR_mir_input_event_get_touch_event(input_event), + MIR_mir_input_event_get_device_id(input_event), + window); break; default: break; @@ -220,32 +257,54 @@ HandleMouseEvent(MirMotionEvent const motion, int cord_index, SDL_Window* sdl_wi } static void -HandleMotionEvent(MirMotionEvent const motion, SDL_Window* sdl_window) +MIR_HandleResize(MirResizeEvent const* resize_event, SDL_Window* window) { - int cord_index; - for (cord_index = 0; cord_index < motion.pointer_count; cord_index++) { - if (motion.pointer_coordinates[cord_index].tool_type == mir_motion_tool_type_finger) { - HandleTouchEvent(motion, cord_index, sdl_window); + int new_w = MIR_mir_resize_event_get_width (resize_event); + int new_h = MIR_mir_resize_event_get_height(resize_event); + + int old_w = window->w; + int old_h = window->h; + + if (new_w != old_w || new_h != old_h) + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, new_w, new_h); +} + +static void +MIR_HandleSurface(MirSurfaceEvent const* surface_event, SDL_Window* window) +{ + MirSurfaceAttrib attrib = MIR_mir_surface_event_get_attribute(surface_event); + int value = MIR_mir_surface_event_get_attribute_value(surface_event); + + if (attrib == mir_surface_attrib_focus) { + if (value == mir_surface_focused) { + SDL_SetKeyboardFocus(window); } - else { - HandleMouseEvent(motion, cord_index, sdl_window); + else if (value == mir_surface_unfocused) { + SDL_SetKeyboardFocus(NULL); } } } void -MIR_HandleInput(MirSurface* surface, MirEvent const* ev, void* context) +MIR_HandleEvent(MirSurface* surface, MirEvent const* ev, void* context) { - SDL_Window* window = (SDL_Window*)context; - switch (ev->type) { - case (mir_event_type_key): - HandleKeyEvent(ev->key, window); - break; - case (mir_event_type_motion): - HandleMotionEvent(ev->motion, window); - break; - default: - break; + MirEventType event_type = MIR_mir_event_get_type(ev); + SDL_Window* window = (SDL_Window*)context; + + if (window) { + switch (event_type) { + case (mir_event_type_input): + MIR_HandleInput(MIR_mir_event_get_input_event(ev), window); + break; + case (mir_event_type_resize): + MIR_HandleResize(MIR_mir_event_get_resize_event(ev), window); + break; + case (mir_event_type_surface): + MIR_HandleSurface(MIR_mir_event_get_surface_event(ev), window); + break; + default: + break; + } } } diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirevents.h b/Engine/lib/sdl/src/video/mir/SDL_mirevents.h index 3e0d96625..121c4b365 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirevents.h +++ b/Engine/lib/sdl/src/video/mir/SDL_mirevents.h @@ -29,7 +29,7 @@ #include extern void -MIR_HandleInput(MirSurface* surface, MirEvent const* ev, void* context); +MIR_HandleEvent(MirSurface* surface, MirEvent const* ev, void* context); #endif /* _SDL_mirevents_h */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirframebuffer.c b/Engine/lib/sdl/src/video/mir/SDL_mirframebuffer.c index 53e6056ff..775bc0797 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirframebuffer.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirframebuffer.c @@ -33,39 +33,18 @@ #include "SDL_mirdyn.h" -static const Uint32 mir_pixel_format_to_sdl_format[] = { - SDL_PIXELFORMAT_UNKNOWN, /* mir_pixel_format_invalid */ - SDL_PIXELFORMAT_ABGR8888, /* mir_pixel_format_abgr_8888 */ - SDL_PIXELFORMAT_BGR888, /* mir_pixel_format_xbgr_8888 */ - SDL_PIXELFORMAT_ARGB8888, /* mir_pixel_format_argb_8888 */ - SDL_PIXELFORMAT_RGB888, /* mir_pixel_format_xrgb_8888 */ - SDL_PIXELFORMAT_BGR24 /* mir_pixel_format_bgr_888 */ -}; - -Uint32 -MIR_GetSDLPixelFormat(MirPixelFormat format) -{ - return mir_pixel_format_to_sdl_format[format]; -} - int MIR_CreateWindowFramebuffer(_THIS, SDL_Window* window, Uint32* format, void** pixels, int* pitch) { MIR_Data* mir_data = _this->driverdata; - MIR_Window* mir_window; - MirSurfaceParameters surfaceparm; mir_data->software = SDL_TRUE; if (MIR_CreateWindow(_this, window) < 0) return SDL_SetError("Failed to created a mir window."); - mir_window = window->driverdata; - - MIR_mir_surface_get_parameters(mir_window->surface, &surfaceparm); - - *format = MIR_GetSDLPixelFormat(surfaceparm.pixel_format); + *format = MIR_GetSDLPixelFormat(mir_data->pixel_format); if (*format == SDL_PIXELFORMAT_UNKNOWN) return SDL_SetError("Unknown pixel format"); @@ -75,12 +54,6 @@ MIR_CreateWindowFramebuffer(_THIS, SDL_Window* window, Uint32* format, if (*pixels == NULL) return SDL_OutOfMemory(); - mir_window->surface = MIR_mir_connection_create_surface_sync(mir_data->connection, &surfaceparm); - if (!MIR_mir_surface_is_valid(mir_window->surface)) { - const char* error = MIR_mir_surface_get_error_message(mir_window->surface); - return SDL_SetError("Failed to created a mir surface: %s", error); - } - return 0; } @@ -91,12 +64,14 @@ MIR_UpdateWindowFramebuffer(_THIS, SDL_Window* window, MIR_Window* mir_window = window->driverdata; MirGraphicsRegion region; + MirBufferStream* bs; int i, j, x, y, w, h, start; int bytes_per_pixel, bytes_per_row, s_stride, d_stride; char* s_dest; char* pixels; - MIR_mir_surface_get_graphics_region(mir_window->surface, ®ion); + bs = MIR_mir_surface_get_buffer_stream(mir_window->surface); + MIR_mir_buffer_stream_get_graphics_region(bs, ®ion); s_dest = region.vaddr; pixels = (char*)window->surface->pixels; @@ -138,13 +113,13 @@ MIR_UpdateWindowFramebuffer(_THIS, SDL_Window* window, bytes_per_row = bytes_per_pixel * w; for (j = 0; j < h; j++) { - memcpy(s_dest, pixels, bytes_per_row); + SDL_memcpy(s_dest, pixels, bytes_per_row); pixels += s_stride; s_dest += d_stride; } } - MIR_mir_surface_swap_buffers_sync(mir_window->surface); + MIR_mir_buffer_stream_swap_buffers_sync(bs); return 0; } diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirmouse.c b/Engine/lib/sdl/src/video/mir/SDL_mirmouse.c index bb8dc6c4e..1a22b28e8 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirmouse.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirmouse.c @@ -27,13 +27,22 @@ #if SDL_VIDEO_DRIVER_MIR -#include "SDL_mirmouse.h" - #include "../../events/SDL_mouse_c.h" +#include "../SDL_sysvideo.h" #include "SDL_assert.h" #include "SDL_mirdyn.h" +#include "SDL_mirvideo.h" +#include "SDL_mirmouse.h" +#include "SDL_mirwindow.h" + +typedef struct +{ + MirCursorConfiguration* conf; + MirBufferStream* stream; +} MIR_Cursor; + static SDL_Cursor* MIR_CreateDefaultCursor() { @@ -41,6 +50,18 @@ MIR_CreateDefaultCursor() cursor = SDL_calloc(1, sizeof(SDL_Cursor)); if (cursor) { + + MIR_Cursor* mir_cursor = SDL_calloc(1, sizeof(MIR_Cursor)); + if (mir_cursor) { + mir_cursor->conf = NULL; + mir_cursor->stream = NULL; + cursor->driverdata = mir_cursor; + } + else { + SDL_OutOfMemory(); + SDL_free(cursor); + cursor = NULL; + } } else { SDL_OutOfMemory(); @@ -49,58 +70,168 @@ MIR_CreateDefaultCursor() return cursor; } -static SDL_Cursor* -MIR_CreateCursor(SDL_Surface* sruface, int hot_x, int hot_y) +static void +CopySurfacePixelsToMirStream(SDL_Surface* surface, MirBufferStream* stream) { - return MIR_CreateDefaultCursor(); + char* dest, *pixels; + int i, s_w, s_h, r_stride, p_stride, bytes_per_pixel, bytes_per_row; + + MirGraphicsRegion region; + MIR_mir_buffer_stream_get_graphics_region(stream, ®ion); + + s_w = surface->w; + s_h = surface->h; + + bytes_per_pixel = surface->format->BytesPerPixel; + bytes_per_row = bytes_per_pixel * s_w; + + dest = region.vaddr; + pixels = (char*)surface->pixels; + + r_stride = region.stride; + p_stride = surface->pitch; + + for (i = 0; i < s_h; i++) + { + SDL_memcpy(dest, pixels, bytes_per_row); + dest += r_stride; + pixels += p_stride; + } +} + +static SDL_Cursor* +MIR_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) +{ + MirCursorConfiguration* conf; + MirBufferStream* stream; + + int s_w = surface->w; + int s_h = surface->h; + + MIR_Data* mir_data = (MIR_Data*)SDL_GetVideoDevice()->driverdata; + SDL_Cursor* cursor = MIR_CreateDefaultCursor(); + MIR_Cursor* mir_cursor; + + if (!cursor) { + return NULL; + } + + mir_cursor = (MIR_Cursor*)cursor->driverdata; + + stream = MIR_mir_connection_create_buffer_stream_sync(mir_data->connection, + s_w, s_h, mir_data->pixel_format, + mir_buffer_usage_software); + + conf = MIR_mir_cursor_configuration_from_buffer_stream(stream, hot_x, hot_y); + + CopySurfacePixelsToMirStream(surface, stream); + MIR_mir_buffer_stream_swap_buffers_sync(stream); + + mir_cursor->conf = conf; + mir_cursor->stream = stream; + + return cursor; } static SDL_Cursor* MIR_CreateSystemCursor(SDL_SystemCursor id) { + char const* cursor_name = NULL; + SDL_Cursor* cursor = MIR_CreateDefaultCursor(); + MIR_Cursor* mir_cursor = (MIR_Cursor*)cursor->driverdata; + + if (!cursor) { + return NULL; + } + switch(id) { case SDL_SYSTEM_CURSOR_ARROW: + cursor_name = MIR_mir_arrow_cursor_name; break; case SDL_SYSTEM_CURSOR_IBEAM: + cursor_name = MIR_mir_caret_cursor_name; break; case SDL_SYSTEM_CURSOR_WAIT: + cursor_name = MIR_mir_busy_cursor_name; break; case SDL_SYSTEM_CURSOR_CROSSHAIR: + /* Unsupported */ + cursor_name = MIR_mir_arrow_cursor_name; break; case SDL_SYSTEM_CURSOR_WAITARROW: + cursor_name = MIR_mir_busy_cursor_name; break; case SDL_SYSTEM_CURSOR_SIZENWSE: + cursor_name = MIR_mir_omnidirectional_resize_cursor_name; break; case SDL_SYSTEM_CURSOR_SIZENESW: + cursor_name = MIR_mir_omnidirectional_resize_cursor_name; break; case SDL_SYSTEM_CURSOR_SIZEWE: + cursor_name = MIR_mir_horizontal_resize_cursor_name; break; case SDL_SYSTEM_CURSOR_SIZENS: + cursor_name = MIR_mir_vertical_resize_cursor_name; break; case SDL_SYSTEM_CURSOR_SIZEALL: + cursor_name = MIR_mir_omnidirectional_resize_cursor_name; break; case SDL_SYSTEM_CURSOR_NO: + /* Unsupported */ + cursor_name = MIR_mir_closed_hand_cursor_name; break; case SDL_SYSTEM_CURSOR_HAND: + cursor_name = MIR_mir_open_hand_cursor_name; break; default: SDL_assert(0); return NULL; } - return MIR_CreateDefaultCursor(); + mir_cursor->conf = MIR_mir_cursor_configuration_from_name(cursor_name); + + return cursor; } static void MIR_FreeCursor(SDL_Cursor* cursor) { - if (cursor) - SDL_free(cursor); + if (cursor) { + + if (cursor->driverdata) { + MIR_Cursor* mir_cursor = (MIR_Cursor*)cursor->driverdata; + + if (mir_cursor->conf) + MIR_mir_cursor_configuration_destroy(mir_cursor->conf); + if (mir_cursor->stream) + MIR_mir_buffer_stream_release_sync(mir_cursor->stream); + + SDL_free(mir_cursor); + } + + SDL_free(cursor); + } } static int MIR_ShowCursor(SDL_Cursor* cursor) { + MIR_Data* mir_data = (MIR_Data*)SDL_GetVideoDevice()->driverdata; + MIR_Window* mir_window = mir_data->current_window; + + if (cursor && cursor->driverdata) { + if (mir_window && MIR_mir_surface_is_valid(mir_window->surface)) { + MIR_Cursor* mir_cursor = (MIR_Cursor*)cursor->driverdata; + + if (mir_cursor->conf) { + MIR_mir_surface_configure_cursor(mir_window->surface, mir_cursor->conf); + } + } + } + else if(mir_window && MIR_mir_surface_is_valid(mir_window->surface)) { + MIR_mir_surface_configure_cursor(mir_window->surface, NULL); + } + return 0; } @@ -119,7 +250,7 @@ MIR_WarpMouseGlobal(int x, int y) static int MIR_SetRelativeMouseMode(SDL_bool enabled) { - return SDL_Unsupported(); + return 0; } /* TODO Actually implement the cursor, need to wait for mir support */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirsym.h b/Engine/lib/sdl/src/video/mir/SDL_mirsym.h index d0aaf70a3..4f97ed96c 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirsym.h +++ b/Engine/lib/sdl/src/video/mir/SDL_mirsym.h @@ -21,29 +21,122 @@ /* *INDENT-OFF* */ +#ifndef SDL_MIR_MODULE +#define SDL_MIR_MODULE(modname) +#endif + +#ifndef SDL_MIR_SYM +#define SDL_MIR_SYM(rc,fn,params) +#endif + +#ifndef SDL_MIR_SYM_CONST +#define SDL_MIR_SYM_CONST(type, name) +#endif + SDL_MIR_MODULE(MIR_CLIENT) -SDL_MIR_SYM(MirDisplayConfiguration*,mir_connection_create_display_config,(MirConnection *connection)) -SDL_MIR_SYM(MirSurface *,mir_connection_create_surface_sync,(MirConnection *connection, MirSurfaceParameters const *params)) +SDL_MIR_SYM(MirSurface *,mir_surface_create_sync,(MirSurfaceSpec* spec)) +SDL_MIR_SYM(MirEGLNativeWindowType,mir_buffer_stream_get_egl_native_window,(MirBufferStream *surface)) +SDL_MIR_SYM(void,mir_buffer_stream_get_graphics_region,(MirBufferStream *stream, MirGraphicsRegion *graphics_region)) +SDL_MIR_SYM(void,mir_buffer_stream_swap_buffers_sync,(MirBufferStream *stream)) +SDL_MIR_SYM(void,mir_surface_set_event_handler,(MirSurface *surface, mir_surface_event_callback callback, void* context)) +SDL_MIR_SYM(MirSurfaceSpec*,mir_connection_create_spec_for_normal_surface,(MirConnection *connection, int width, int height, MirPixelFormat format)) +SDL_MIR_SYM(MirSurfaceSpec*,mir_connection_create_spec_for_changes,(MirConnection *connection)) +SDL_MIR_SYM(void,mir_surface_spec_set_buffer_usage,(MirSurfaceSpec *spec, MirBufferUsage usage)) +SDL_MIR_SYM(void,mir_surface_spec_set_name,(MirSurfaceSpec *spec, char const *name)) +SDL_MIR_SYM(void,mir_surface_spec_release,(MirSurfaceSpec *spec)) +SDL_MIR_SYM(void,mir_surface_spec_set_width,(MirSurfaceSpec *spec, unsigned width)) +SDL_MIR_SYM(void,mir_surface_spec_set_height,(MirSurfaceSpec *spec, unsigned height)) +SDL_MIR_SYM(void,mir_surface_spec_set_min_width,(MirSurfaceSpec *spec, unsigned min_width)) +SDL_MIR_SYM(void,mir_surface_spec_set_min_height,(MirSurfaceSpec *spec, unsigned min_height)) +SDL_MIR_SYM(void,mir_surface_spec_set_max_width,(MirSurfaceSpec *spec, unsigned max_width)) +SDL_MIR_SYM(void,mir_surface_spec_set_max_height,(MirSurfaceSpec *spec, unsigned max_height)) +SDL_MIR_SYM(void,mir_surface_spec_set_type,(MirSurfaceSpec *spec, MirSurfaceType type)) +SDL_MIR_SYM(void,mir_surface_spec_set_state,(MirSurfaceSpec *spec, MirSurfaceState state)) +SDL_MIR_SYM(void,mir_surface_spec_set_pointer_confinement,(MirSurfaceSpec *spec, MirPointerConfinementState state)) +SDL_MIR_SYM(void,mir_surface_apply_spec,(MirSurface *surface, MirSurfaceSpec *spec)) +SDL_MIR_SYM(void,mir_surface_get_parameters,(MirSurface *surface, MirSurfaceParameters *params)) +SDL_MIR_SYM(MirBufferStream*,mir_surface_get_buffer_stream,(MirSurface *surface)) +SDL_MIR_SYM(MirCursorConfiguration*,mir_cursor_configuration_from_buffer_stream,(MirBufferStream const* stream, int hot_x, int hot_y)) +SDL_MIR_SYM(MirBufferStream*,mir_connection_create_buffer_stream_sync,(MirConnection *connection, int w, int h, MirPixelFormat format, MirBufferUsage usage)) +SDL_MIR_SYM(MirKeyboardAction,mir_keyboard_event_action,(MirKeyboardEvent const *event)) +SDL_MIR_SYM(xkb_keysym_t,mir_keyboard_event_key_code,(MirKeyboardEvent const *event)) +SDL_MIR_SYM(int,mir_keyboard_event_scan_code,(MirKeyboardEvent const *event)) +SDL_MIR_SYM(bool,mir_pointer_event_button_state,(MirPointerEvent const *event, MirPointerButton button)) +SDL_MIR_SYM(MirPointerButtons,mir_pointer_event_buttons,(MirPointerEvent const *event)) +SDL_MIR_SYM(MirInputDeviceId,mir_input_event_get_device_id,(MirInputEvent const* ev)) +SDL_MIR_SYM(MirTouchId,mir_touch_event_id,(MirTouchEvent const *event, size_t touch_index)) +SDL_MIR_SYM(float,mir_touch_event_axis_value,(MirTouchEvent const *event, size_t touch_index, MirTouchAxis axis)) +SDL_MIR_SYM(MirTouchAction,mir_touch_event_action,(MirTouchEvent const *event, size_t touch_index)) +SDL_MIR_SYM(MirPointerAction,mir_pointer_event_action,(MirPointerEvent const *event)) +SDL_MIR_SYM(float,mir_pointer_event_axis_value,(MirPointerEvent const *event, MirPointerAxis)) +SDL_MIR_SYM(MirEventType,mir_event_get_type,(MirEvent const *event)) +SDL_MIR_SYM(MirInputEventType,mir_input_event_get_type,(MirInputEvent const *event)) +SDL_MIR_SYM(MirInputEvent const*,mir_event_get_input_event,(MirEvent const *event)) +SDL_MIR_SYM(MirResizeEvent const*,mir_event_get_resize_event,(MirEvent const *event)) +SDL_MIR_SYM(MirKeyboardEvent const*,mir_input_event_get_keyboard_event,(MirInputEvent const *event)) +SDL_MIR_SYM(MirPointerEvent const*,mir_input_event_get_pointer_event,(MirInputEvent const *event)) +SDL_MIR_SYM(MirTouchEvent const*,mir_input_event_get_touch_event,(MirInputEvent const *event)) +SDL_MIR_SYM(MirSurfaceEvent const*,mir_event_get_surface_event,(MirEvent const *event)) +SDL_MIR_SYM(unsigned int,mir_touch_event_point_count,(MirTouchEvent const *event)) 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(MirBool,mir_connection_is_valid,(MirConnection *connection)) +SDL_MIR_SYM(bool,mir_connection_is_valid,(MirConnection *connection)) SDL_MIR_SYM(void,mir_connection_release,(MirConnection *connection)) +SDL_MIR_SYM(MirPixelFormat,mir_connection_get_egl_pixel_format,(MirConnection* connection, void* egldisplay, void* eglconfig)) 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)) -SDL_MIR_SYM(MirEGLNativeWindowType,mir_surface_get_egl_native_window,(MirSurface *surface)) 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(MirBool,mir_surface_is_valid,(MirSurface *surface)) +SDL_MIR_SYM(bool,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_SYM(void,mir_buffer_stream_release_sync,(MirBufferStream *stream)) +SDL_MIR_SYM(MirCursorConfiguration*,mir_cursor_configuration_from_name,(char const* cursor_name)) +SDL_MIR_SYM(MirWaitHandle*,mir_surface_configure_cursor,(MirSurface* surface, MirCursorConfiguration const* conf)) +SDL_MIR_SYM(void,mir_cursor_configuration_destroy,(MirCursorConfiguration* conf)) +SDL_MIR_SYM(int,mir_resize_event_get_width,(MirResizeEvent const* resize_event)) +SDL_MIR_SYM(int,mir_resize_event_get_height,(MirResizeEvent const* resize_event)) +SDL_MIR_SYM(char const*,mir_connection_get_error_message,(MirConnection* connection)) +SDL_MIR_SYM(MirSurfaceAttrib,mir_surface_event_get_attribute,(MirSurfaceEvent const* surface_event)) +SDL_MIR_SYM(int,mir_surface_event_get_attribute_value,(MirSurfaceEvent const* surface_event)) +SDL_MIR_SYM(void,mir_wait_for,(MirWaitHandle* handle)) +SDL_MIR_SYM(MirDisplayConfig*,mir_connection_create_display_configuration,(MirConnection* connection)) +SDL_MIR_SYM(void,mir_display_config_release,(MirDisplayConfig* config)) +SDL_MIR_SYM(int,mir_display_config_get_num_outputs,(MirDisplayConfig const* config)) +SDL_MIR_SYM(MirOutput*,mir_display_config_get_mutable_output,(MirDisplayConfig* config, size_t index)) +SDL_MIR_SYM(int,mir_output_get_num_modes,(MirOutput const* output)) +SDL_MIR_SYM(MirPixelFormat,mir_output_get_current_pixel_format,(MirOutput const* output)) +SDL_MIR_SYM(int,mir_output_get_position_x,(MirOutput const* output)) +SDL_MIR_SYM(int,mir_output_get_position_y,(MirOutput const* output)) +SDL_MIR_SYM(bool,mir_output_is_enabled,(MirOutput const* output)) +SDL_MIR_SYM(MirOutputConnectionState,mir_output_get_connection_state,(MirOutput const* output)) +SDL_MIR_SYM(size_t,mir_output_get_preferred_mode_index,(MirOutput const* output)) +SDL_MIR_SYM(MirOutputType,mir_output_get_type,(MirOutput const* output)) +SDL_MIR_SYM(char const*,mir_output_type_name,(MirOutputType type)) +SDL_MIR_SYM(void,mir_output_set_current_mode,(MirOutput* output, MirOutputMode const* mode)) +SDL_MIR_SYM(MirOutputMode const*,mir_output_get_mode,(MirOutput const* output, size_t index)) +SDL_MIR_SYM(int,mir_output_mode_get_width,(MirOutputMode const* mode)) +SDL_MIR_SYM(int,mir_output_mode_get_height,(MirOutputMode const* mode)) +SDL_MIR_SYM(double,mir_output_mode_get_refresh_rate,(MirOutputMode const* mode)) +SDL_MIR_SYM(MirOutputGammaSupported,mir_output_is_gamma_supported,(MirOutput const* output)) +SDL_MIR_SYM(uint32_t,mir_output_get_gamma_size,(MirOutput const* output)) +SDL_MIR_SYM(void,mir_output_get_gamma,(MirOutput const* output, uint16_t* red, uint16_t* green, uint16_t* blue, uint32_t size)) +SDL_MIR_SYM(void,mir_output_set_gamma,(MirOutput* output, uint16_t const* red, uint16_t const* green, uint16_t const* blue, uint32_t size)) + +SDL_MIR_SYM_CONST(char const*,mir_omnidirectional_resize_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_busy_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_arrow_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_caret_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_vertical_resize_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_horizontal_resize_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_open_hand_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_closed_hand_cursor_name) +SDL_MIR_SYM_CONST(char const*,mir_disabled_cursor_name) SDL_MIR_MODULE(XKBCOMMON) SDL_MIR_SYM(int,xkb_keysym_to_utf8,(xkb_keysym_t keysym, char *buffer, size_t size)) +#undef SDL_MIR_MODULE +#undef SDL_MIR_SYM +#undef SDL_MIR_SYM_CONST + /* *INDENT-ON* */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirvideo.c b/Engine/lib/sdl/src/video/mir/SDL_mirvideo.c index b6160fd92..6a8f9e482 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirvideo.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirvideo.c @@ -27,18 +27,37 @@ #if SDL_VIDEO_DRIVER_MIR +#include "SDL_mirwindow.h" #include "SDL_video.h" #include "SDL_mirframebuffer.h" #include "SDL_mirmouse.h" #include "SDL_miropengl.h" #include "SDL_mirvideo.h" -#include "SDL_mirwindow.h" #include "SDL_mirdyn.h" #define MIR_DRIVER_NAME "mir" +static const Uint32 mir_pixel_format_to_sdl_format[] = { + SDL_PIXELFORMAT_UNKNOWN, /* mir_pixel_format_invalid */ + SDL_PIXELFORMAT_ABGR8888, /* mir_pixel_format_abgr_8888 */ + SDL_PIXELFORMAT_BGR888, /* mir_pixel_format_xbgr_8888 */ + SDL_PIXELFORMAT_ARGB8888, /* mir_pixel_format_argb_8888 */ + SDL_PIXELFORMAT_RGB888, /* mir_pixel_format_xrgb_8888 */ + SDL_PIXELFORMAT_BGR24, /* mir_pixel_format_bgr_888 */ + SDL_PIXELFORMAT_RGB24, /* mir_pixel_format_rgb_888 */ + SDL_PIXELFORMAT_RGB565, /* mir_pixel_format_rgb_565 */ + SDL_PIXELFORMAT_RGBA5551, /* mir_pixel_format_rgba_5551 */ + SDL_PIXELFORMAT_RGBA4444 /* mir_pixel_format_rgba_4444 */ +}; + +Uint32 +MIR_GetSDLPixelFormat(MirPixelFormat format) +{ + return mir_pixel_format_to_sdl_format[format]; +} + static int MIR_VideoInit(_THIS); @@ -94,7 +113,7 @@ MIR_DeleteDevice(SDL_VideoDevice* device) SDL_MIR_UnloadSymbols(); } -void +static void MIR_PumpEvents(_THIS) { } @@ -146,29 +165,30 @@ MIR_CreateDevice(int device_index) device->GL_GetProcAddress = MIR_GL_GetProcAddress; /* mirwindow */ - device->CreateWindow = MIR_CreateWindow; - device->DestroyWindow = MIR_DestroyWindow; - device->GetWindowWMInfo = MIR_GetWindowWMInfo; - device->SetWindowFullscreen = MIR_SetWindowFullscreen; - device->MaximizeWindow = MIR_MaximizeWindow; - device->MinimizeWindow = MIR_MinimizeWindow; - device->RestoreWindow = MIR_RestoreWindow; + device->CreateWindow = MIR_CreateWindow; + device->DestroyWindow = MIR_DestroyWindow; + device->GetWindowWMInfo = MIR_GetWindowWMInfo; + device->SetWindowFullscreen = MIR_SetWindowFullscreen; + device->MaximizeWindow = MIR_MaximizeWindow; + device->MinimizeWindow = MIR_MinimizeWindow; + device->RestoreWindow = MIR_RestoreWindow; + device->ShowWindow = MIR_RestoreWindow; + device->HideWindow = MIR_HideWindow; + device->SetWindowSize = MIR_SetWindowSize; + device->SetWindowMinimumSize = MIR_SetWindowMinimumSize; + device->SetWindowMaximumSize = MIR_SetWindowMaximumSize; + device->SetWindowTitle = MIR_SetWindowTitle; + device->SetWindowGrab = MIR_SetWindowGrab; + device->SetWindowGammaRamp = MIR_SetWindowGammaRamp; + device->GetWindowGammaRamp = MIR_GetWindowGammaRamp; device->CreateWindowFrom = NULL; - device->SetWindowTitle = NULL; device->SetWindowIcon = NULL; - device->SetWindowPosition = NULL; - device->SetWindowSize = NULL; - device->SetWindowMinimumSize = NULL; - device->SetWindowMaximumSize = NULL; - device->ShowWindow = NULL; - device->HideWindow = NULL; device->RaiseWindow = NULL; device->SetWindowBordered = NULL; - device->SetWindowGammaRamp = NULL; - device->GetWindowGammaRamp = NULL; - device->SetWindowGrab = NULL; + device->SetWindowResizable = NULL; device->OnWindowEnter = NULL; + device->SetWindowPosition = NULL; /* mirframebuffer */ device->CreateWindowFramebuffer = MIR_CreateWindowFramebuffer; @@ -206,77 +226,88 @@ VideoBootStrap MIR_bootstrap = { MIR_Available, MIR_CreateDevice }; -static void -MIR_SetCurrentDisplayMode(MirDisplayOutput const* out, SDL_VideoDisplay* display) +static SDL_DisplayMode +MIR_ConvertModeToSDLMode(MirOutputMode const* mode, MirPixelFormat format) { - SDL_DisplayMode mode = { - .format = SDL_PIXELFORMAT_RGB888, - .w = out->modes[out->current_mode].horizontal_resolution, - .h = out->modes[out->current_mode].vertical_resolution, - .refresh_rate = out->modes[out->current_mode].refresh_rate, - .driverdata = NULL + SDL_DisplayMode sdl_mode = { + .format = MIR_GetSDLPixelFormat(format), + .w = MIR_mir_output_mode_get_width(mode), + .h = MIR_mir_output_mode_get_height(mode), + .refresh_rate = MIR_mir_output_mode_get_refresh_rate(mode), + .driverdata = NULL }; - display->desktop_mode = mode; - display->current_mode = mode; + return sdl_mode; } static void -MIR_AddAllModesFromDisplay(MirDisplayOutput const* out, SDL_VideoDisplay* display) +MIR_AddModeToDisplay(SDL_VideoDisplay* display, MirOutputMode const* mode, MirPixelFormat format) { - int n_mode; - for (n_mode = 0; n_mode < out->num_modes; ++n_mode) { - SDL_DisplayMode mode = { - .format = SDL_PIXELFORMAT_RGB888, - .w = out->modes[n_mode].horizontal_resolution, - .h = out->modes[n_mode].vertical_resolution, - .refresh_rate = out->modes[n_mode].refresh_rate, - .driverdata = NULL - }; + SDL_DisplayMode sdl_mode = MIR_ConvertModeToSDLMode(mode, format); + SDL_AddDisplayMode(display, &sdl_mode); +} - SDL_AddDisplayMode(display, &mode); +static void +MIR_InitDisplayFromOutput(_THIS, MirOutput* output) +{ + SDL_VideoDisplay display; + int m; + + MirPixelFormat format = MIR_mir_output_get_current_pixel_format(output); + int num_modes = MIR_mir_output_get_num_modes(output); + SDL_DisplayMode current_mode = MIR_ConvertModeToSDLMode(mir_output_get_current_mode(output), format); + + SDL_zero(display); + + // Unfortunate cast, but SDL_AddVideoDisplay will strdup this pointer so its read-only in this case. + display.name = (char*)MIR_mir_output_type_name(MIR_mir_output_get_type(output)); + + for (m = 0; m < num_modes; m++) { + MirOutputMode const* mode = MIR_mir_output_get_mode(output, m); + MIR_AddModeToDisplay(&display, mode, format); } + + display.desktop_mode = current_mode; + display.current_mode = current_mode; + + display.driverdata = output; + SDL_AddVideoDisplay(&display); } static void MIR_InitDisplays(_THIS) { MIR_Data* mir_data = _this->driverdata; + int num_outputs = MIR_mir_display_config_get_num_outputs(mir_data->display_config); int d; - MirDisplayConfiguration* display_config = MIR_mir_connection_create_display_config(mir_data->connection); + for (d = 0; d < num_outputs; d++) { + MirOutput* output = MIR_mir_display_config_get_mutable_output(mir_data->display_config, d); + SDL_bool enabled = MIR_mir_output_is_enabled(output); + MirOutputConnectionState state = MIR_mir_output_get_connection_state(output); - for (d = 0; d < display_config->num_outputs; d++) { - MirDisplayOutput const* out = display_config->outputs + d; - - SDL_VideoDisplay display; - SDL_zero(display); - - if (out->used && - out->connected && - out->num_modes && - out->current_mode < out->num_modes) { - - MIR_SetCurrentDisplayMode(out, &display); - MIR_AddAllModesFromDisplay(out, &display); - - SDL_AddVideoDisplay(&display); + if (enabled && state == mir_output_connection_state_connected) { + MIR_InitDisplayFromOutput(_this, output); } } - - MIR_mir_display_config_destroy(display_config); } -int +static int MIR_VideoInit(_THIS) { MIR_Data* mir_data = _this->driverdata; - mir_data->connection = MIR_mir_connect_sync(NULL, __PRETTY_FUNCTION__); - mir_data->software = SDL_FALSE; + mir_data->connection = MIR_mir_connect_sync(NULL, __PRETTY_FUNCTION__); + mir_data->current_window = NULL; + mir_data->software = SDL_FALSE; + mir_data->pixel_format = mir_pixel_format_invalid; - if (!MIR_mir_connection_is_valid(mir_data->connection)) - return SDL_SetError("Failed to connect to the Mir Server"); + if (!MIR_mir_connection_is_valid(mir_data->connection)) { + return SDL_SetError("Failed to connect to the mir server: %s", + MIR_mir_connection_get_error_message(mir_data->connection)); + } + + mir_data->display_config = MIR_mir_connection_create_display_configuration(mir_data->connection); MIR_InitDisplays(_this); MIR_InitMouse(); @@ -284,11 +315,27 @@ MIR_VideoInit(_THIS) return 0; } -void +static void +MIR_CleanUpDisplayConfig(_THIS) +{ + MIR_Data* mir_data = _this->driverdata; + int i; + + // SDL_VideoQuit frees the display driverdata, we own it not them + for (i = 0; i < _this->num_displays; ++i) { + _this->displays[i].driverdata = NULL; + } + + MIR_mir_display_config_release(mir_data->display_config); +} + +static void MIR_VideoQuit(_THIS) { MIR_Data* mir_data = _this->driverdata; + MIR_CleanUpDisplayConfig(_this); + MIR_FiniMouse(); MIR_GL_DeleteContext(_this, NULL); @@ -303,40 +350,48 @@ MIR_VideoQuit(_THIS) static int MIR_GetDisplayBounds(_THIS, SDL_VideoDisplay* display, SDL_Rect* rect) { - MIR_Data* mir_data = _this->driverdata; - int d; + MirOutput const* output = display->driverdata; - MirDisplayConfiguration* display_config = MIR_mir_connection_create_display_config(mir_data->connection); - - for (d = 0; d < display_config->num_outputs; d++) { - MirDisplayOutput const* out = display_config->outputs + d; - - if (out->used && - out->connected && - out->num_modes && - out->current_mode < out->num_modes) { - - rect->x = out->position_x; - rect->y = out->position_y; - rect->w = out->modes->horizontal_resolution; - rect->h = out->modes->vertical_resolution; - } - } - - MIR_mir_display_config_destroy(display_config); + rect->x = MIR_mir_output_get_position_x(output); + rect->y = MIR_mir_output_get_position_y(output); + rect->w = display->current_mode.w; + rect->h = display->current_mode.h; return 0; } static void -MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* sdl_display) +MIR_GetDisplayModes(_THIS, SDL_VideoDisplay* display) { } static int -MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* sdl_display, SDL_DisplayMode* mode) +MIR_SetDisplayMode(_THIS, SDL_VideoDisplay* display, SDL_DisplayMode* mode) { - return 0; + int m; + MirOutput* output = display->driverdata; + int num_modes = MIR_mir_output_get_num_modes(output); + Uint32 sdl_format = MIR_GetSDLPixelFormat( + MIR_mir_output_get_current_pixel_format(output)); + + for (m = 0; m < num_modes; m++) { + MirOutputMode const* mir_mode = MIR_mir_output_get_mode(output, m); + int width = MIR_mir_output_mode_get_width(mir_mode); + int height = MIR_mir_output_mode_get_height(mir_mode); + double refresh_rate = MIR_mir_output_mode_get_refresh_rate(mir_mode); + + if (mode->format == sdl_format && + mode->w == width && + mode->h == height && + mode->refresh_rate == refresh_rate) { + + // FIXME Currently wont actually *set* anything. Need to wait for applying display changes + MIR_mir_output_set_current_mode(output, mir_mode); + return 0; + } + } + + return -1; } #endif /* SDL_VIDEO_DRIVER_MIR */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirvideo.h b/Engine/lib/sdl/src/video/mir/SDL_mirvideo.h index c5ef4758d..71ef4ecc1 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirvideo.h +++ b/Engine/lib/sdl/src/video/mir/SDL_mirvideo.h @@ -29,13 +29,20 @@ #include #include +typedef struct MIR_Window MIR_Window; + typedef struct { - MirConnection* connection; - SDL_bool software; - + MirConnection* connection; + MirDisplayConfig* display_config; + MIR_Window* current_window; + SDL_bool software; + MirPixelFormat pixel_format; } MIR_Data; +extern Uint32 +MIR_GetSDLPixelFormat(MirPixelFormat format); + #endif /* _SDL_mirvideo_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirwindow.c b/Engine/lib/sdl/src/video/mir/SDL_mirwindow.c index 0eb54be01..1bf9016a0 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirwindow.c +++ b/Engine/lib/sdl/src/video/mir/SDL_mirwindow.c @@ -29,6 +29,7 @@ #include "../SDL_egl_c.h" #include "../SDL_sysvideo.h" +#include "../../events/SDL_keyboard_c.h" #include "SDL_mirevents.h" #include "SDL_mirwindow.h" @@ -55,7 +56,7 @@ FindValidPixelFormat(MIR_Data* mir_data) MirPixelFormat formats[pf_size]; MIR_mir_connection_get_available_surface_formats(mir_data->connection, formats, - pf_size, &valid_formats); + pf_size, &valid_formats); for (f = 0; f < valid_formats; f++) { MirPixelFormat cur_pf = formats[f]; @@ -77,21 +78,10 @@ MIR_CreateWindow(_THIS, SDL_Window* window) { MIR_Window* mir_window; MIR_Data* mir_data; + MirPixelFormat pixel_format; + MirBufferUsage buffer_usage; - MirSurfaceParameters surfaceparm = - { - .name = "MirSurface", - .width = window->w, - .height = window->h, - .pixel_format = mir_pixel_format_invalid, - .buffer_usage = mir_buffer_usage_hardware, - .output_id = mir_display_output_id_invalid - }; - - MirEventDelegate delegate = { - MIR_HandleInput, - window - }; + MirSurfaceSpec* spec; mir_window = SDL_calloc(1, sizeof(MIR_Window)); if (!mir_window) @@ -100,9 +90,6 @@ MIR_CreateWindow(_THIS, SDL_Window* window) mir_data = _this->driverdata; window->driverdata = mir_window; - if (mir_data->software) - surfaceparm.buffer_usage = mir_buffer_usage_software; - if (window->x == SDL_WINDOWPOS_UNDEFINED) window->x = 0; @@ -112,20 +99,49 @@ MIR_CreateWindow(_THIS, SDL_Window* window) mir_window->mir_data = mir_data; mir_window->sdl_window = window; - surfaceparm.pixel_format = FindValidPixelFormat(mir_data); - if (surfaceparm.pixel_format == mir_pixel_format_invalid) { + if (window->flags & SDL_WINDOW_OPENGL) { + pixel_format = MIR_mir_connection_get_egl_pixel_format(mir_data->connection, + _this->egl_data->egl_display, + _this->egl_data->egl_config); + } + else { + pixel_format = FindValidPixelFormat(mir_data); + } + + mir_data->pixel_format = pixel_format; + if (pixel_format == mir_pixel_format_invalid) { return SDL_SetError("Failed to find a valid pixel format."); } - mir_window->surface = MIR_mir_connection_create_surface_sync(mir_data->connection, &surfaceparm); + buffer_usage = mir_buffer_usage_hardware; + if (mir_data->software) + buffer_usage = mir_buffer_usage_software; + + spec = MIR_mir_connection_create_spec_for_normal_surface(mir_data->connection, + window->w, + window->h, + pixel_format); + + MIR_mir_surface_spec_set_buffer_usage(spec, buffer_usage); + MIR_mir_surface_spec_set_name(spec, "Mir surface"); + + if (window->flags & SDL_WINDOW_INPUT_FOCUS) + SDL_SetKeyboardFocus(window); + + mir_window->surface = MIR_mir_surface_create_sync(spec); + MIR_mir_surface_set_event_handler(mir_window->surface, MIR_HandleEvent, window); + + MIR_mir_surface_spec_release(spec); + if (!MIR_mir_surface_is_valid(mir_window->surface)) { - const char* error = MIR_mir_surface_get_error_message(mir_window->surface); - return SDL_SetError("Failed to created a mir surface: %s", error); + return SDL_SetError("Failed to created a mir surface: %s", + MIR_mir_surface_get_error_message(mir_window->surface)); } if (window->flags & SDL_WINDOW_OPENGL) { EGLNativeWindowType egl_native_window = - (EGLNativeWindowType)MIR_mir_surface_get_egl_native_window(mir_window->surface); + (EGLNativeWindowType)MIR_mir_buffer_stream_get_egl_native_window( + MIR_mir_surface_get_buffer_stream(mir_window->surface)); mir_window->egl_surface = SDL_EGL_CreateSurface(_this, egl_native_window); @@ -138,7 +154,7 @@ MIR_CreateWindow(_THIS, SDL_Window* window) mir_window->egl_surface = EGL_NO_SURFACE; } - MIR_mir_surface_set_event_handler(mir_window->surface, &delegate); + mir_data->current_window = mir_window; return 0; } @@ -146,13 +162,15 @@ MIR_CreateWindow(_THIS, SDL_Window* window) void MIR_DestroyWindow(_THIS, SDL_Window* window) { - MIR_Data* mir_data = _this->driverdata; + MIR_Data* mir_data = _this->driverdata; MIR_Window* mir_window = window->driverdata; if (mir_data) { SDL_EGL_DestroySurface(_this, mir_window->egl_surface); MIR_mir_surface_release_sync(mir_window->surface); + mir_data->current_window = NULL; + SDL_free(mir_window); } window->driverdata = NULL; @@ -180,49 +198,223 @@ MIR_SetWindowFullscreen(_THIS, SDL_Window* window, SDL_VideoDisplay* display, SDL_bool fullscreen) { + MIR_Data* mir_data = _this->driverdata; MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; + MirSurfaceState state; if (IsSurfaceValid(mir_window) < 0) return; if (fullscreen) { - MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_fullscreen); + state = mir_surface_state_fullscreen; } else { - MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_restored); + state = mir_surface_state_restored; } + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_state(spec, state); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); } void MIR_MaximizeWindow(_THIS, SDL_Window* window) { + MIR_Data* mir_data = _this->driverdata; MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_maximized); + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_state(spec, mir_surface_state_maximized); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); } void MIR_MinimizeWindow(_THIS, SDL_Window* window) { + MIR_Data* mir_data = _this->driverdata; MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_minimized); + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_state(spec, mir_surface_state_minimized); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); } void MIR_RestoreWindow(_THIS, SDL_Window * window) { + MIR_Data* mir_data = _this->driverdata; MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; if (IsSurfaceValid(mir_window) < 0) return; - MIR_mir_surface_set_state(mir_window->surface, mir_surface_state_restored); + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_state(spec, mir_surface_state_restored); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_HideWindow(_THIS, SDL_Window* window) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; + + if (IsSurfaceValid(mir_window) < 0) + return; + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_state(spec, mir_surface_state_hidden); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_SetWindowSize(_THIS, SDL_Window* window) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; + + if (IsSurfaceValid(mir_window) < 0) + return; + + /* You cannot set the x/y of a mir window! So only update w/h */ + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_width (spec, window->w); + MIR_mir_surface_spec_set_height(spec, window->h); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_SetWindowMinimumSize(_THIS, SDL_Window* window) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; + + if (IsSurfaceValid(mir_window) < 0) + return; + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_min_width (spec, window->min_w); + MIR_mir_surface_spec_set_min_height(spec, window->min_h); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_SetWindowMaximumSize(_THIS, SDL_Window* window) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + MirSurfaceSpec* spec; + + if (IsSurfaceValid(mir_window) < 0) + return; + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_max_width (spec, window->max_w); + MIR_mir_surface_spec_set_max_height(spec, window->max_h); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_SetWindowTitle(_THIS, SDL_Window* window) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + char const* title = window->title ? window->title : ""; + MirSurfaceSpec* spec; + + if (IsSurfaceValid(mir_window) < 0) + return; + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_name(spec, title); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +void +MIR_SetWindowGrab(_THIS, SDL_Window* window, SDL_bool grabbed) +{ + MIR_Data* mir_data = _this->driverdata; + MIR_Window* mir_window = window->driverdata; + MirPointerConfinementState confined = mir_pointer_unconfined; + MirSurfaceSpec* spec; + + if (grabbed) + confined = mir_pointer_confined_to_surface; + + spec = MIR_mir_connection_create_spec_for_changes(mir_data->connection); + MIR_mir_surface_spec_set_pointer_confinement(spec, confined); + + MIR_mir_surface_apply_spec(mir_window->surface, spec); + MIR_mir_surface_spec_release(spec); +} + +int +MIR_SetWindowGammaRamp(_THIS, SDL_Window* window, Uint16 const* ramp) +{ + MirOutput* output = SDL_GetDisplayForWindow(window)->driverdata; + Uint32 ramp_size = 256; + + // FIXME Need to apply the changes to the output, once that public API function is around + if (MIR_mir_output_is_gamma_supported(output) == mir_output_gamma_supported) { + MIR_mir_output_set_gamma(output, + ramp + ramp_size * 0, + ramp + ramp_size * 1, + ramp + ramp_size * 2, + ramp_size); + return 0; + } + + return -1; +} + +int +MIR_GetWindowGammaRamp(_THIS, SDL_Window* window, Uint16* ramp) +{ + MirOutput* output = SDL_GetDisplayForWindow(window)->driverdata; + Uint32 ramp_size = 256; + + if (MIR_mir_output_is_gamma_supported(output) == mir_output_gamma_supported) { + if (MIR_mir_output_get_gamma_size(output) == ramp_size) { + MIR_mir_output_get_gamma(output, + ramp + ramp_size * 0, + ramp + ramp_size * 1, + ramp + ramp_size * 2, + ramp_size); + return 0; + } + } + + return -1; } #endif /* SDL_VIDEO_DRIVER_MIR */ diff --git a/Engine/lib/sdl/src/video/mir/SDL_mirwindow.h b/Engine/lib/sdl/src/video/mir/SDL_mirwindow.h index c21fc9292..c4084aa4e 100644 --- a/Engine/lib/sdl/src/video/mir/SDL_mirwindow.h +++ b/Engine/lib/sdl/src/video/mir/SDL_mirwindow.h @@ -31,13 +31,13 @@ #include "SDL_mirvideo.h" -typedef struct { +struct MIR_Window { SDL_Window* sdl_window; - MIR_Data* mir_data; + MIR_Data* mir_data; MirSurface* surface; - EGLSurface egl_surface; -} MIR_Window; + EGLSurface egl_surface; +}; extern int @@ -60,9 +60,33 @@ MIR_MinimizeWindow(_THIS, SDL_Window* window); extern void MIR_RestoreWindow(_THIS, SDL_Window* window); +extern void +MIR_HideWindow(_THIS, SDL_Window* window); + extern SDL_bool MIR_GetWindowWMInfo(_THIS, SDL_Window* window, SDL_SysWMinfo* info); +extern void +MIR_SetWindowSize(_THIS, SDL_Window* window); + +extern void +MIR_SetWindowMinimumSize(_THIS, SDL_Window* window); + +extern void +MIR_SetWindowMaximumSize(_THIS, SDL_Window* window); + +extern void +MIR_SetWindowTitle(_THIS, SDL_Window* window); + +extern void +MIR_SetWindowGrab(_THIS, SDL_Window* window, SDL_bool grabbed); + +extern int +MIR_SetWindowGammaRamp(_THIS, SDL_Window* window, Uint16 const* ramp); + +extern int +MIR_GetWindowGammaRamp(_THIS, SDL_Window* window, Uint16* ramp); + #endif /* _SDL_mirwindow_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/pandora/SDL_pandora.c b/Engine/lib/sdl/src/video/pandora/SDL_pandora.c index d1c35a705..7afa54306 100644 --- a/Engine/lib/sdl/src/video/pandora/SDL_pandora.c +++ b/Engine/lib/sdl/src/video/pandora/SDL_pandora.c @@ -41,8 +41,6 @@ static NativeWindowType hNativeWnd = 0; /* A handle to the window we will create. */ #endif -static SDL_bool PND_initialized = SDL_FALSE; - static int PND_available(void) { @@ -52,11 +50,11 @@ PND_available(void) static void PND_destroy(SDL_VideoDevice * device) { - SDL_VideoData *phdata = (SDL_VideoData *) device->driverdata; - if (device->driverdata != NULL) { + SDL_free(device->driverdata); device->driverdata = NULL; } + SDL_free(device); } static SDL_VideoDevice * @@ -93,9 +91,8 @@ PND_create() phdata->egl_initialized = SDL_TRUE; - /* Setup amount of available displays and current display */ + /* Setup amount of available displays */ device->num_displays = 0; - device->current_display = 0; /* Set device free function */ device->free = PND_destroy; @@ -204,10 +201,6 @@ PND_createwindow(_THIS, SDL_Window * window) SDL_WindowData *wdata; - uint32_t winargc = 0; - int32_t status; - - /* Allocate window internal data */ wdata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); if (wdata == NULL) { @@ -292,7 +285,7 @@ PND_restorewindow(_THIS, SDL_Window * window) { } void -PND_setwindowgrab(_THIS, SDL_Window * window) +PND_setwindowgrab(_THIS, SDL_Window * window, SDL_bool grabbed) { } void @@ -326,8 +319,6 @@ PND_getwindowwminfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) int PND_gl_loadlibrary(_THIS, const char *path) { - SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; - /* Check if OpenGL ES library is specified for GF driver */ if (path == NULL) { path = SDL_getenv("SDL_OPENGL_LIBRARY"); @@ -365,7 +356,6 @@ PND_gl_loadlibrary(_THIS, const char *path) void * PND_gl_getprocaddres(_THIS, const char *proc) { - SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; void *function_address; /* Try to get function address through the egl interface */ @@ -409,10 +399,7 @@ PND_gl_createcontext(_THIS, SDL_Window * window) { SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata; - SDL_DisplayData *didata = - (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; EGLBoolean status; - int32_t gfstatus; EGLint configs; uint32_t attr_pos; EGLint attr_value; @@ -629,12 +616,12 @@ PND_gl_createcontext(_THIS, SDL_Window * window) hNativeWnd = (NativeWindowType)malloc(16*1024); if(!hNativeWnd) - printf( "Error : Wiz framebuffer allocatation failed\n" ); + printf( "Error: Wiz framebuffer allocatation failed\n" ); else - printf( "SDL13: Wiz framebuffer allocated: %X\n", hNativeWnd ); + printf( "SDL: Wiz framebuffer allocated: %X\n", hNativeWnd ); } else { - printf( "SDL13: Wiz framebuffer already allocated: %X\n", hNativeWnd ); + printf( "SDL: Wiz framebuffer already allocated: %X\n", hNativeWnd ); } wdata->gles_surface = @@ -792,9 +779,6 @@ PND_gl_swapwindow(_THIS, SDL_Window * window) { SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata; - SDL_DisplayData *didata = - (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; - if (phdata->egl_initialized != SDL_TRUE) { SDL_SetError("PND: GLES initialization failed, no OpenGL ES support"); @@ -838,7 +822,7 @@ PND_gl_deletecontext(_THIS, SDL_GLContext context) { free(hNativeWnd); hNativeWnd = 0; - printf( "SDL13: Wiz framebuffer released\n" ); + printf( "SDL: Wiz framebuffer released\n" ); } #endif diff --git a/Engine/lib/sdl/src/video/pandora/SDL_pandora.h b/Engine/lib/sdl/src/video/pandora/SDL_pandora.h index b95cd10b1..859b7ee5d 100644 --- a/Engine/lib/sdl/src/video/pandora/SDL_pandora.h +++ b/Engine/lib/sdl/src/video/pandora/SDL_pandora.h @@ -77,7 +77,7 @@ void PND_raisewindow(_THIS, SDL_Window * window); void PND_maximizewindow(_THIS, SDL_Window * window); void PND_minimizewindow(_THIS, SDL_Window * window); void PND_restorewindow(_THIS, SDL_Window * window); -void PND_setwindowgrab(_THIS, SDL_Window * window); +void PND_setwindowgrab(_THIS, SDL_Window * window, SDL_bool grabbed); void PND_destroywindow(_THIS, SDL_Window * window); /* Window manager function */ diff --git a/Engine/lib/sdl/src/video/psp/SDL_pspevents.c b/Engine/lib/sdl/src/video/psp/SDL_pspevents.c index c1a095dbb..71267272d 100644 --- a/Engine/lib/sdl/src/video/psp/SDL_pspevents.c +++ b/Engine/lib/sdl/src/video/psp/SDL_pspevents.c @@ -31,8 +31,8 @@ #include "../../events/SDL_keyboard_c.h" #include "SDL_pspvideo.h" #include "SDL_pspevents_c.h" -#include "SDL_thread.h" #include "SDL_keyboard.h" +#include "../../thread/SDL_systhread.h" #include #ifdef PSPIRKEYB @@ -264,7 +264,7 @@ void PSP_EventInit(_THIS) return; } running = 1; - if((thread = SDL_CreateThread(EventUpdate, "PSPInputThread",NULL)) == NULL) { + if((thread = SDL_CreateThreadInternal(EventUpdate, "PSPInputThread", 4096, NULL)) == NULL) { SDL_SetError("Can't create input thread\n"); return; } diff --git a/Engine/lib/sdl/src/video/psp/SDL_pspvideo.c b/Engine/lib/sdl/src/video/psp/SDL_pspvideo.c index 955666877..381e4899e 100644 --- a/Engine/lib/sdl/src/video/psp/SDL_pspvideo.c +++ b/Engine/lib/sdl/src/video/psp/SDL_pspvideo.c @@ -92,6 +92,7 @@ PSP_Create() if (gldata == NULL) { SDL_OutOfMemory(); SDL_free(device); + SDL_free(phdata); return NULL; } device->gl_data = gldata; @@ -101,7 +102,7 @@ PSP_Create() phdata->egl_initialized = SDL_TRUE; - /* Setup amount of available displays and current display */ + /* Setup amount of available displays */ device->num_displays = 0; /* Set device free function */ @@ -234,7 +235,7 @@ PSP_CreateWindow(_THIS, SDL_Window * window) int PSP_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) { - return -1; + return SDL_Unsupported(); } void diff --git a/Engine/lib/sdl/src/video/raspberry/SDL_rpimouse.c b/Engine/lib/sdl/src/video/raspberry/SDL_rpimouse.c index 0d1482c04..ae9bdfd5c 100644 --- a/Engine/lib/sdl/src/video/raspberry/SDL_rpimouse.c +++ b/Engine/lib/sdl/src/video/raspberry/SDL_rpimouse.c @@ -24,6 +24,7 @@ #include "SDL_assert.h" #include "SDL_surface.h" +#include "SDL_hints.h" #include "SDL_rpivideo.h" #include "SDL_rpimouse.h" @@ -70,7 +71,16 @@ RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) SDL_assert(surface->pitch == surface->w * 4); cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); + if (cursor == NULL) { + SDL_OutOfMemory(); + return NULL; + } curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata)); + if (curdata == NULL) { + SDL_OutOfMemory(); + SDL_free(cursor); + return NULL; + } curdata->hot_x = hot_x; curdata->hot_y = hot_y; @@ -78,17 +88,17 @@ RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) curdata->h = surface->h; /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */ - curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy ); + curdata->resource = vc_dispmanx_resource_create(VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy); SDL_assert(curdata->resource); - vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h); + vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h); /* A note from Weston: * vc_dispmanx_resource_write_data() ignores ifmt, * rect.x, rect.width, and uses stride only for computing * the size of the transfer as rect.height * stride. * Therefore we can only write rows starting at x=0. */ - ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect ); - SDL_assert ( ret == DISPMANX_SUCCESS ); + ret = vc_dispmanx_resource_write_data(curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect); + SDL_assert (ret == DISPMANX_SUCCESS); cursor->driverdata = curdata; @@ -108,7 +118,9 @@ RPI_ShowCursor(SDL_Cursor * cursor) SDL_VideoDisplay *display; SDL_DisplayData *data; VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/, 0 /* mask */ }; - + uint32_t layer = SDL_RPI_MOUSELAYER; + const char *env; + mouse = SDL_GetMouse(); if (mouse == NULL) { return -1; @@ -117,15 +129,15 @@ RPI_ShowCursor(SDL_Cursor * cursor) if (cursor == NULL) { /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */ - if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) { + if (mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) { curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata; if (curdata->element > DISPMANX_NO_HANDLE) { - update = vc_dispmanx_update_start( 10 ); - SDL_assert( update ); - ret = vc_dispmanx_element_remove( update, curdata->element ); - SDL_assert( ret == DISPMANX_SUCCESS ); - ret = vc_dispmanx_update_submit_sync( update ); - SDL_assert( ret == DISPMANX_SUCCESS ); + update = vc_dispmanx_update_start(10); + SDL_assert(update); + ret = vc_dispmanx_element_remove(update, curdata->element); + SDL_assert(ret == DISPMANX_SUCCESS); + ret = vc_dispmanx_update_submit_sync(update); + SDL_assert(ret == DISPMANX_SUCCESS); curdata->element = DISPMANX_NO_HANDLE; } } @@ -152,25 +164,30 @@ RPI_ShowCursor(SDL_Cursor * cursor) } if (curdata->element == DISPMANX_NO_HANDLE) { - vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 ); - vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h); + vc_dispmanx_rect_set(&src_rect, 0, 0, curdata->w << 16, curdata->h << 16); + vc_dispmanx_rect_set(&dst_rect, 0, 0, curdata->w, curdata->h); - update = vc_dispmanx_update_start( 10 ); - SDL_assert( update ); + update = vc_dispmanx_update_start(10); + SDL_assert(update); - curdata->element = vc_dispmanx_element_add( update, + env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER); + if (env) { + layer = SDL_atoi(env) + 1; + } + + curdata->element = vc_dispmanx_element_add(update, data->dispman_display, - SDL_RPI_MOUSELAYER, // layer + layer, &dst_rect, curdata->resource, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, DISPMANX_NO_HANDLE, // clamp - VC_IMAGE_ROT0 ); - SDL_assert( curdata->element > DISPMANX_NO_HANDLE); - ret = vc_dispmanx_update_submit_sync( update ); - SDL_assert( ret == DISPMANX_SUCCESS ); + VC_IMAGE_ROT0); + SDL_assert(curdata->element > DISPMANX_NO_HANDLE); + ret = vc_dispmanx_update_submit_sync(update); + SDL_assert(ret == DISPMANX_SUCCESS); } return 0; @@ -189,17 +206,17 @@ RPI_FreeCursor(SDL_Cursor * cursor) if (curdata != NULL) { if (curdata->element != DISPMANX_NO_HANDLE) { - update = vc_dispmanx_update_start( 10 ); - SDL_assert( update ); - ret = vc_dispmanx_element_remove( update, curdata->element ); - SDL_assert( ret == DISPMANX_SUCCESS ); - ret = vc_dispmanx_update_submit_sync( update ); - SDL_assert( ret == DISPMANX_SUCCESS ); + update = vc_dispmanx_update_start(10); + SDL_assert(update); + ret = vc_dispmanx_element_remove(update, curdata->element); + SDL_assert(ret == DISPMANX_SUCCESS); + ret = vc_dispmanx_update_submit_sync(update); + SDL_assert(ret == DISPMANX_SUCCESS); } if (curdata->resource != DISPMANX_NO_HANDLE) { - ret = vc_dispmanx_resource_delete( curdata->resource ); - SDL_assert( ret == DISPMANX_SUCCESS ); + ret = vc_dispmanx_resource_delete(curdata->resource); + SDL_assert(ret == DISPMANX_SUCCESS); } SDL_free(cursor->driverdata); @@ -221,35 +238,54 @@ RPI_WarpMouseGlobal(int x, int y) { RPI_CursorData *curdata; DISPMANX_UPDATE_HANDLE_T update; + int ret; VC_RECT_T dst_rect; + VC_RECT_T src_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); - ret = vc_dispmanx_element_change_attributes( - update, - curdata->element, - ELEMENT_CHANGE_DEST_RECT, - 0, - 0, - &dst_rect, - NULL, - DISPMANX_NO_HANDLE, - DISPMANX_NO_ROTATE); - SDL_assert( ret == DISPMANX_SUCCESS ); - /* 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; - } - } + if (mouse == NULL || mouse->cur_cursor == NULL || mouse->cur_cursor->driverdata == NULL) { + return 0; + } - return -1; /* !!! FIXME: this should SDL_SetError() somewhere. */ + curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata; + if (curdata->element == DISPMANX_NO_HANDLE) { + return 0; + } + + update = vc_dispmanx_update_start(10); + if (!update) { + return 0; + } + + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = curdata->w << 16; + src_rect.height = curdata->h << 16; + dst_rect.x = x; + dst_rect.y = y; + dst_rect.width = curdata->w; + dst_rect.height = curdata->h; + + ret = vc_dispmanx_element_change_attributes( + update, + curdata->element, + 0, + 0, + 0, + &dst_rect, + &src_rect, + DISPMANX_NO_HANDLE, + DISPMANX_NO_ROTATE); + if (ret != DISPMANX_SUCCESS) { + return SDL_SetError("vc_dispmanx_element_change_attributes() failed"); + } + + /* Submit asynchronously, otherwise the peformance suffers a lot */ + ret = vc_dispmanx_update_submit(update, 0, NULL); + if (ret != DISPMANX_SUCCESS) { + return SDL_SetError("vc_dispmanx_update_submit() failed"); + } + return 0; } void diff --git a/Engine/lib/sdl/src/video/raspberry/SDL_rpivideo.c b/Engine/lib/sdl/src/video/raspberry/SDL_rpivideo.c index 539c88c9b..67dc77b1c 100644 --- a/Engine/lib/sdl/src/video/raspberry/SDL_rpivideo.c +++ b/Engine/lib/sdl/src/video/raspberry/SDL_rpivideo.c @@ -38,6 +38,7 @@ #include "SDL_events.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_keyboard_c.h" +#include "SDL_hints.h" #ifdef SDL_INPUT_LINUXEV #include "../../core/linux/SDL_evdev.h" @@ -88,7 +89,7 @@ RPI_Create() device->driverdata = phdata; - /* Setup amount of available displays and current display */ + /* Setup amount of available displays */ device->num_displays = 0; /* Set device free function */ @@ -221,6 +222,8 @@ RPI_CreateWindow(_THIS, SDL_Window * window) VC_RECT_T src_rect; VC_DISPMANX_ALPHA_T dispman_alpha; DISPMANX_UPDATE_HANDLE_T dispman_update; + uint32_t layer = SDL_RPI_VIDEOLAYER; + const char *env; /* Disable alpha, otherwise the app looks composed with whatever dispman is showing (X11, console,etc) */ dispman_alpha.flags = DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS; @@ -253,11 +256,25 @@ RPI_CreateWindow(_THIS, SDL_Window * window) src_rect.width = window->w << 16; src_rect.height = window->h << 16; + env = SDL_GetHint(SDL_HINT_RPI_VIDEO_LAYER); + if (env) { + layer = SDL_atoi(env); + } + dispman_update = vc_dispmanx_update_start( 0 ); - wdata->dispman_window.element = vc_dispmanx_element_add ( dispman_update, displaydata->dispman_display, SDL_RPI_VIDEOLAYER /* layer */, &dst_rect, 0/*src*/, &src_rect, DISPMANX_PROTECTION_NONE, &dispman_alpha /*alpha*/, 0/*clamp*/, 0/*transform*/); + wdata->dispman_window.element = vc_dispmanx_element_add (dispman_update, + displaydata->dispman_display, + layer /* layer */, + &dst_rect, + 0 /*src*/, + &src_rect, + DISPMANX_PROTECTION_NONE, + &dispman_alpha /*alpha*/, + 0 /*clamp*/, + 0 /*transform*/); wdata->dispman_window.width = window->w; wdata->dispman_window.height = window->h; - vc_dispmanx_update_submit_sync( dispman_update ); + vc_dispmanx_update_submit_sync(dispman_update); if (!_this->egl_data) { if (SDL_GL_LoadLibrary(NULL) < 0) { diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.h index 1879f0b3a..edf09f50f 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.h +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.h @@ -24,8 +24,8 @@ @interface SDLLaunchScreenController : UIViewController - (instancetype)init; +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; - (void)loadView; -- (NSUInteger)supportedInterfaceOrientations; @end diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.m index 971b438b0..c94c78a41 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitappdelegate.m @@ -76,6 +76,7 @@ SDL_IdleTimerDisabledChanged(void *userdata, const char *name, const char *oldVa [UIApplication sharedApplication].idleTimerDisabled = disable; } +#if !TARGET_OS_TV /* Load a launch image using the old UILaunchImageFile-era naming rules. */ static UIImage * SDL_LoadLaunchImageNamed(NSString *name, int screenh) @@ -114,17 +115,31 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) return image; } +#endif /* !TARGET_OS_TV */ + +@interface SDLLaunchScreenController () + +#if !TARGET_OS_TV +- (NSUInteger)supportedInterfaceOrientations; +#endif + +@end @implementation SDLLaunchScreenController - (instancetype)init +{ + return [self initWithNibName:nil bundle:[NSBundle mainBundle]]; +} + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (!(self = [super initWithNibName:nil bundle:nil])) { return nil; } - NSBundle *bundle = [NSBundle mainBundle]; - NSString *screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; + NSString *screenname = nibNameOrNil; + NSBundle *bundle = nibBundleOrNil; BOOL atleastiOS8 = UIKit_IsSystemVersionAtLeast(8.0); /* Launch screens were added in iOS 8. Otherwise we use launch images. */ @@ -141,27 +156,28 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) if (!self.view) { NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; - UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; NSString *imagename = nil; UIImage *image = nil; int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); +#if !TARGET_OS_TV + UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; + /* We always want portrait-oriented size, to match UILaunchImageSize. */ if (screenw > screenh) { int width = screenw; screenw = screenh; screenh = width; } +#endif /* 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"]; + NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"]; + NSString *sizestring = dict[@"UILaunchImageSize"]; /* Ignore this image if the current version is too low. */ if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) { @@ -176,6 +192,10 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) } } +#if !TARGET_OS_TV + UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; + NSString *orientstring = dict[@"UILaunchImageOrientation"]; + if (orientstring) { if ([orientstring isEqualToString:@"PortraitUpsideDown"]) { orientmask = UIInterfaceOrientationMaskPortraitUpsideDown; @@ -192,6 +212,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) if ((orientmask & (1 << curorient)) == 0) { continue; } +#endif imagename = dict[@"UILaunchImageName"]; } @@ -199,7 +220,9 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) if (imagename) { image = [UIImage imageNamed:imagename]; } - } else { + } +#if !TARGET_OS_TV + else { imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; if (imagename) { @@ -210,11 +233,13 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) image = SDL_LoadLaunchImageNamed(@"Default", screenh); } } +#endif if (image) { UIImageView *view = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIImageOrientation imageorient = UIImageOrientationUp; +#if !TARGET_OS_TV /* Bugs observed / workaround tested in iOS 8.3, 7.1, and 6.1. */ if (UIInterfaceOrientationIsLandscape(curorient)) { if (atleastiOS8 && image.size.width < image.size.height) { @@ -238,6 +263,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) } } } +#endif /* Create the properly oriented image. */ view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient]; @@ -254,6 +280,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) /* Do nothing. */ } +#if !TARGET_OS_TV - (BOOL)shouldAutorotate { /* If YES, the launch image will be incorrectly rotated in some cases. */ @@ -267,6 +294,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) * the ones set here (it will cause an exception in that case.) */ return UIInterfaceOrientationMaskAll; } +#endif /* !TARGET_OS_TV */ @end @@ -333,7 +361,6 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSBundle *bundle = [NSBundle mainBundle]; - NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; #if SDL_IPHONE_LAUNCHSCREEN /* The normal launch screen is displayed until didFinishLaunching returns, @@ -342,9 +369,32 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is * called), so we show the launch screen programmatically until the first * time events are pumped. */ - UIViewController *viewcontroller = [[SDLLaunchScreenController alloc] init]; + UIViewController *vc = nil; + NSString *screenname = nil; - if (viewcontroller.view) { + /* tvOS only uses a plain launch image. */ +#if !TARGET_OS_TV + screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; + + if (screenname && UIKit_IsSystemVersionAtLeast(8.0)) { + @try { + /* The launch storyboard is actually a nib in some older versions of + * Xcode. We'll try to load it as a storyboard first, as it's more + * modern. */ + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle]; + vc = [storyboard instantiateInitialViewController]; + } + @catch (NSException *exception) { + /* Do nothing (there's more code to execute below). */ + } + } +#endif + + if (vc == nil) { + vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle]; + } + + if (vc.view) { launchWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; /* We don't want the launch window immediately hidden when a real SDL @@ -355,7 +405,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) * other windows when possible. */ launchWindow.hidden = NO; - launchWindow.rootViewController = viewcontroller; + launchWindow.rootViewController = vc; } #endif @@ -382,6 +432,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) SDL_SendAppEvent(SDL_APP_LOWMEMORY); } +#if !TARGET_OS_TV - (void)application:(UIApplication *)application didChangeStatusBarOrientation:(UIInterfaceOrientation)oldStatusBarOrientation { BOOL isLandscape = UIInterfaceOrientationIsLandscape(application.statusBarOrientation); @@ -409,6 +460,7 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) } } } +#endif - (void)applicationWillResignActive:(UIApplication*)application { @@ -447,16 +499,34 @@ SDL_LoadLaunchImageNamed(NSString *name, int screenh) } } -- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation +- (void)sendDropFileForURL:(NSURL *)url { NSURL *fileURL = url.filePathURL; if (fileURL != nil) { - SDL_SendDropFile([fileURL.path UTF8String]); + SDL_SendDropFile(NULL, fileURL.path.UTF8String); } else { - SDL_SendDropFile([url.absoluteString UTF8String]); + SDL_SendDropFile(NULL, url.absoluteString.UTF8String); } + SDL_SendDropComplete(NULL); +} + +#if TARGET_OS_TV +/* TODO: Use this on iOS 9+ as well? */ +- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options +{ + /* TODO: Handle options */ + [self sendDropFileForURL:url]; return YES; } +#endif /* TARGET_OS_TV */ + +#if !TARGET_OS_TV +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation +{ + [self sendDropFileForURL:url]; + return YES; +} +#endif /* !TARGET_OS_TV */ @end diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.h new file mode 100644 index 000000000..7d1c35f99 --- /dev/null +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_uikitclipboard_h +#define _SDL_uikitclipboard_h + +#include "../SDL_sysvideo.h" + +extern int UIKit_SetClipboardText(_THIS, const char *text); +extern char *UIKit_GetClipboardText(_THIS); +extern SDL_bool UIKit_HasClipboardText(_THIS); + +extern void UIKit_InitClipboard(_THIS); +extern void UIKit_QuitClipboard(_THIS); + +#endif /* _SDL_uikitclipboard_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.m new file mode 100644 index 000000000..050d5885f --- /dev/null +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitclipboard.m @@ -0,0 +1,111 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_UIKIT + +#include "SDL_uikitvideo.h" +#include "../../events/SDL_clipboardevents_c.h" + +#import + +int +UIKit_SetClipboardText(_THIS, const char *text) +{ +#if TARGET_OS_TV + return SDL_SetError("The clipboard is not available on tvOS"); +#else + @autoreleasepool { + [UIPasteboard generalPasteboard].string = @(text); + return 0; + } +#endif +} + +char * +UIKit_GetClipboardText(_THIS) +{ +#if TARGET_OS_TV + return SDL_strdup(""); // Unsupported. +#else + @autoreleasepool { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + NSString *string = pasteboard.string; + + if (string != nil) { + return SDL_strdup(string.UTF8String); + } else { + return SDL_strdup(""); + } + } +#endif +} + +SDL_bool +UIKit_HasClipboardText(_THIS) +{ + @autoreleasepool { +#if !TARGET_OS_TV + if ([UIPasteboard generalPasteboard].string != nil) { + return SDL_TRUE; + } +#endif + return SDL_FALSE; + } +} + +void +UIKit_InitClipboard(_THIS) +{ +#if !TARGET_OS_TV + @autoreleasepool { + SDL_VideoData *data = (__bridge SDL_VideoData *) _this->driverdata; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + id observer = [center addObserverForName:UIPasteboardChangedNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + SDL_SendClipboardUpdate(); + }]; + + data.pasteboardObserver = observer; + } +#endif +} + +void +UIKit_QuitClipboard(_THIS) +{ + @autoreleasepool { + SDL_VideoData *data = (__bridge SDL_VideoData *) _this->driverdata; + + if (data.pasteboardObserver != nil) { + [[NSNotificationCenter defaultCenter] removeObserver:data.pasteboardObserver]; + } + + data.pasteboardObserver = nil; + } +} + +#endif /* SDL_VIDEO_DRIVER_UIKIT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitevents.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitevents.m index 1d7044d88..7083e204b 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitevents.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitevents.m @@ -26,6 +26,7 @@ #include "SDL_uikitvideo.h" #include "SDL_uikitevents.h" +#include "SDL_uikitopengles.h" #import @@ -62,6 +63,9 @@ UIKit_PumpEvents(_THIS) do { result = CFRunLoopRunInMode((CFStringRef)UITrackingRunLoopMode, seconds, TRUE); } while(result == kCFRunLoopRunHandledSource); + + /* See the comment in the function definition. */ + UIKit_GL_RestoreCurrentContext(); } #endif /* SDL_VIDEO_DRIVER_UIKIT */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.h index 027cf7aa0..b936df616 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.h +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.h @@ -43,6 +43,7 @@ extern int UIKit_InitModes(_THIS); extern void UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display); extern int UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); extern void UIKit_QuitModes(_THIS); +extern int UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); #endif /* _SDL_uikitmodes_h */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.m index 98d031484..cd3b8d08e 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitmodes.m @@ -156,9 +156,12 @@ UIKit_AddDisplay(UIScreen *uiscreen) SDL_bool UIKit_IsDisplayLandscape(UIScreen *uiscreen) { +#if !TARGET_OS_TV if (uiscreen == [UIScreen mainScreen]) { return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); - } else { + } else +#endif /* !TARGET_OS_TV */ + { CGSize size = uiscreen.bounds.size; return (size.width > size.height); } @@ -187,6 +190,14 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) SDL_bool isLandscape = UIKit_IsDisplayLandscape(data.uiscreen); SDL_bool addRotation = (data.uiscreen == [UIScreen mainScreen]); CGFloat scale = data.uiscreen.scale; + NSArray *availableModes = nil; + +#if TARGET_OS_TV + addRotation = SDL_FALSE; + availableModes = @[data.uiscreen.currentMode]; +#else + availableModes = data.uiscreen.availableModes; +#endif #ifdef __IPHONE_8_0 /* The UIScreenMode of an iPhone 6 Plus should be 1080x1920 rather than @@ -196,7 +207,7 @@ UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display) } #endif - for (UIScreenMode *uimode in data.uiscreen.availableModes) { + for (UIScreenMode *uimode in 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); @@ -219,9 +230,11 @@ UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) { @autoreleasepool { SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; - SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata; +#if !TARGET_OS_TV + SDL_DisplayModeData *modedata = (__bridge SDL_DisplayModeData *)mode->driverdata; [data.uiscreen setCurrentMode:modedata.uiscreenmode]; +#endif if (data.uiscreen == [UIScreen mainScreen]) { /* [UIApplication setStatusBarOrientation:] no longer works reliably @@ -242,6 +255,36 @@ UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) return 0; } +int +UIKit_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) +{ + @autoreleasepool { + int displayIndex = (int) (display - _this->displays); + SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; + + /* the default function iterates displays to make a fake offset, + as if all the displays were side-by-side, which is fine for iOS. */ + if (SDL_GetDisplayBounds(displayIndex, rect) < 0) { + return -1; + } + + CGRect frame = data.uiscreen.bounds; + +#if !TARGET_OS_TV + if (!UIKit_IsSystemVersionAtLeast(7.0)) { + frame = [data.uiscreen applicationFrame]; + } +#endif + + rect->x += frame.origin.x; + rect->y += frame.origin.y; + rect->w = frame.size.width; + rect->h = frame.size.height; + } + + return 0; +} + void UIKit_QuitModes(_THIS) { diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.h index 10697610d..b52e42913 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.h +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.h @@ -33,6 +33,8 @@ extern void UIKit_GL_DeleteContext(_THIS, SDL_GLContext context); extern void *UIKit_GL_GetProcAddress(_THIS, const char *proc); extern int UIKit_GL_LoadLibrary(_THIS, const char *path); +extern void UIKit_GL_RestoreCurrentContext(); + #endif /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.m index a2ea4ab67..461ff9b80 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitopengles.m @@ -140,10 +140,19 @@ UIKit_GL_CreateContext(_THIS, SDL_Window * window) EAGLSharegroup *sharegroup = nil; CGFloat scale = 1.0; int samples = 0; + int major = _this->gl_config.major_version; + int minor = _this->gl_config.minor_version; /* The EAGLRenderingAPI enum values currently map 1:1 to major GLES * versions. */ - EAGLRenderingAPI api = _this->gl_config.major_version; + EAGLRenderingAPI api = major; + + /* iOS currently doesn't support GLES >3.0. iOS 6 also only supports up + * to GLES 2.0. */ + if (major > 3 || (major == 3 && (minor > 0 || !UIKit_IsSystemVersionAtLeast(7.0)))) { + SDL_SetError("OpenGL ES %d.%d context could not be created", major, minor); + return NULL; + } if (_this->gl_config.multisamplebuffers > 0) { samples = _this->gl_config.multisamplesamples; @@ -217,6 +226,24 @@ UIKit_GL_DeleteContext(_THIS, SDL_GLContext context) } } +void +UIKit_GL_RestoreCurrentContext() +{ + @autoreleasepool { + /* Some iOS system functionality (such as Dictation on the on-screen + keyboard) uses its own OpenGL ES context but doesn't restore the + previous one when it's done. This is a workaround to make sure the + expected SDL-created OpenGL ES context is active after the OS is + finished running its own code for the frame. If this isn't done, the + app may crash or have other nasty symptoms when Dictation is used. + */ + EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); + if (context != NULL && [EAGLContext currentContext] != context) { + [EAGLContext setCurrentContext:context]; + } + } +} + #endif /* SDL_VIDEO_DRIVER_UIKIT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitopenglview.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitopenglview.m index 60c247e6a..aae7ee8f2 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitopenglview.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitopenglview.m @@ -239,7 +239,7 @@ if (msaaRenderbuffer != 0) { glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderbuffer); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, backingWidth, backingHeight); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, colorBufferFormat, backingWidth, backingHeight); } if (depthRenderbuffer != 0) { diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.h index 3fbaf92f1..aafb714d7 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.h +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.h @@ -21,14 +21,25 @@ #ifndef _SDL_uikitvideo_h #define _SDL_uikitvideo_h +#include "../SDL_sysvideo.h" + +#ifdef __OBJC__ + #include -#include "../SDL_sysvideo.h" +@interface SDL_VideoData : NSObject + +@property (nonatomic) id pasteboardObserver; + +@end + +CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); + +#endif /* __OBJC__ */ void UIKit_SuspendScreenSaver(_THIS); -BOOL UIKit_IsSystemVersionAtLeast(double version); -CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen); +SDL_bool UIKit_IsSystemVersionAtLeast(double version); #endif /* _SDL_uikitvideo_h */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.m index 4f3c7dc43..88d461751 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitvideo.m @@ -36,9 +36,14 @@ #include "SDL_uikitmodes.h" #include "SDL_uikitwindow.h" #include "SDL_uikitopengles.h" +#include "SDL_uikitclipboard.h" #define UIKITVID_DRIVER_NAME "uikit" +@implementation SDL_VideoData + +@end + /* Initialization/Query functions */ static int UIKit_VideoInit(_THIS); static void UIKit_VideoQuit(_THIS); @@ -53,60 +58,75 @@ UIKit_Available(void) static void UIKit_DeleteDevice(SDL_VideoDevice * device) { - SDL_free(device); + @autoreleasepool { + CFRelease(device->driverdata); + SDL_free(device); + } } static SDL_VideoDevice * UIKit_CreateDevice(int devindex) { - SDL_VideoDevice *device; + @autoreleasepool { + SDL_VideoDevice *device; + SDL_VideoData *data; - /* Initialize all variables that we clean on shutdown */ - device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); - if (!device) { - SDL_free(device); - SDL_OutOfMemory(); - return (0); + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (device) { + data = [SDL_VideoData new]; + } else { + SDL_free(device); + SDL_OutOfMemory(); + return (0); + } + + device->driverdata = (void *) CFBridgingRetain(data); + + /* Set the function pointers */ + device->VideoInit = UIKit_VideoInit; + device->VideoQuit = UIKit_VideoQuit; + 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; + device->GetDisplayUsableBounds = UIKit_GetDisplayUsableBounds; + + #if SDL_IPHONE_KEYBOARD + device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport; + device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard; + device->HideScreenKeyboard = UIKit_HideScreenKeyboard; + device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown; + device->SetTextInputRect = UIKit_SetTextInputRect; + #endif + + device->SetClipboardText = UIKit_SetClipboardText; + device->GetClipboardText = UIKit_GetClipboardText; + device->HasClipboardText = UIKit_HasClipboardText; + + /* OpenGL (ES) functions */ + 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->free = UIKit_DeleteDevice; + + device->gl_config.accelerated = 1; + + return device; } - - /* Set the function pointers */ - device->VideoInit = UIKit_VideoInit; - device->VideoQuit = UIKit_VideoQuit; - 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; - -#if SDL_IPHONE_KEYBOARD - device->HasScreenKeyboardSupport = UIKit_HasScreenKeyboardSupport; - device->ShowScreenKeyboard = UIKit_ShowScreenKeyboard; - device->HideScreenKeyboard = UIKit_HideScreenKeyboard; - device->IsScreenKeyboardShown = UIKit_IsScreenKeyboardShown; - device->SetTextInputRect = UIKit_SetTextInputRect; -#endif - - /* OpenGL (ES) functions */ - 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->free = UIKit_DeleteDevice; - - device->gl_config.accelerated = 1; - - return device; } VideoBootStrap UIKIT_bootstrap = { @@ -138,7 +158,7 @@ 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) { + if (!SDL_GetHintBoolean(SDL_HINT_IDLE_TIMER_DISABLED, SDL_FALSE)) { UIApplication *app = [UIApplication sharedApplication]; /* Prevent the display from dimming and going to sleep. */ @@ -147,7 +167,7 @@ UIKit_SuspendScreenSaver(_THIS) } } -BOOL +SDL_bool UIKit_IsSystemVersionAtLeast(double version) { return [[UIDevice currentDevice].systemVersion doubleValue] >= version; @@ -156,6 +176,7 @@ UIKit_IsSystemVersionAtLeast(double version) CGRect UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) { +#if !TARGET_OS_TV && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0) BOOL hasiOS7 = UIKit_IsSystemVersionAtLeast(7.0); if (hasiOS7 || (window->flags & (SDL_WINDOW_BORDERLESS|SDL_WINDOW_FULLSCREEN))) { @@ -164,6 +185,9 @@ UIKit_ComputeViewFrame(SDL_Window *window, UIScreen *screen) } else { return screen.applicationFrame; } +#else + return screen.bounds; +#endif } /* diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitview.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitview.m index 1ccda98ff..c7d9f51d9 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitview.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitview.m @@ -45,7 +45,9 @@ self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.autoresizesSubviews = YES; +#if !TARGET_OS_TV self.multipleTouchEnabled = YES; +#endif touchId = 1; SDL_AddTouch(touchId, ""); @@ -141,12 +143,13 @@ if (!firstFingerDown) { CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO]; + int clicks = (int) touch.tapCount; /* send mouse moved event */ SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); /* send mouse down event */ - SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT); + SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT, clicks); firstFingerDown = touch; } @@ -164,7 +167,8 @@ if (touch == firstFingerDown) { /* send mouse up */ - SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT); + int clicks = (int) touch.tapCount; + SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT, clicks); firstFingerDown = nil; } @@ -197,6 +201,69 @@ } } +#if TARGET_OS_TV || defined(__IPHONE_9_1) +- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype +{ + switch (presstype) { + case UIPressTypeUpArrow: + return SDL_SCANCODE_UP; + case UIPressTypeDownArrow: + return SDL_SCANCODE_DOWN; + case UIPressTypeLeftArrow: + return SDL_SCANCODE_LEFT; + case UIPressTypeRightArrow: + return SDL_SCANCODE_RIGHT; + case UIPressTypeSelect: + /* HIG says: "primary button behavior" */ + return SDL_SCANCODE_SELECT; + case UIPressTypeMenu: + /* HIG says: "returns to previous screen" */ + return SDL_SCANCODE_MENU; + case UIPressTypePlayPause: + /* HIG says: "secondary button behavior" */ + return SDL_SCANCODE_PAUSE; + default: + return SDL_SCANCODE_UNKNOWN; + } +} + +- (void)pressesBegan:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + for (UIPress *press in presses) { + SDL_Scancode scancode = [self scancodeFromPressType:press.type]; + SDL_SendKeyboardKey(SDL_PRESSED, scancode); + } + + [super pressesBegan:presses withEvent:event]; +} + +- (void)pressesEnded:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + for (UIPress *press in presses) { + SDL_Scancode scancode = [self scancodeFromPressType:press.type]; + SDL_SendKeyboardKey(SDL_RELEASED, scancode); + } + + [super pressesEnded:presses withEvent:event]; +} + +- (void)pressesCancelled:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + for (UIPress *press in presses) { + SDL_Scancode scancode = [self scancodeFromPressType:press.type]; + SDL_SendKeyboardKey(SDL_RELEASED, scancode); + } + + [super pressesCancelled:presses withEvent:event]; +} + +- (void)pressesChanged:(NSSet *)presses withEvent:(UIPressesEvent *)event +{ + /* This is only called when the force of a press changes. */ + [super pressesChanged:presses withEvent:event]; +} +#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */ + @end #endif /* SDL_VIDEO_DRIVER_UIKIT */ diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.h b/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.h index c78396802..860852441 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.h +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.h @@ -1,23 +1,24 @@ /* - Simple DirectMedia Layer - Copyright (C) 1997-2016 Sam Lantinga + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga - 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. + 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: + 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. - */ + 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" #import @@ -25,10 +26,17 @@ #include "SDL_touch.h" -#if SDL_IPHONE_KEYBOARD -@interface SDL_uikitviewcontroller : UIViewController +#if TARGET_OS_TV +#import +#define SDLRootViewController GCEventViewController #else -@interface SDL_uikitviewcontroller : UIViewController +#define SDLRootViewController UIViewController +#endif + +#if SDL_IPHONE_KEYBOARD +@interface SDL_uikitviewcontroller : SDLRootViewController +#else +@interface SDL_uikitviewcontroller : SDLRootViewController #endif @property (nonatomic, assign) SDL_Window *window; @@ -46,8 +54,11 @@ - (void)loadView; - (void)viewDidLayoutSubviews; + +#if !TARGET_OS_TV - (NSUInteger)supportedInterfaceOrientations; - (BOOL)prefersStatusBarHidden; +#endif #if SDL_IPHONE_KEYBOARD - (void)showKeyboard; diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.m index 58cdf1ac5..e6e903ee4 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitviewcontroller.m @@ -33,11 +33,23 @@ #include "SDL_uikitvideo.h" #include "SDL_uikitmodes.h" #include "SDL_uikitwindow.h" +#include "SDL_uikitopengles.h" #if SDL_IPHONE_KEYBOARD #include "keyinfotable.h" #endif +#if TARGET_OS_TV +static void +SDL_AppleTVControllerUIHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + @autoreleasepool { + SDL_uikitviewcontroller *viewcontroller = (__bridge SDL_uikitviewcontroller *) userdata; + viewcontroller.controllerUserInteractionEnabled = hint && (*hint != '0'); + } +} +#endif + @implementation SDL_uikitviewcontroller { CADisplayLink *displayLink; int animationInterval; @@ -59,6 +71,12 @@ #if SDL_IPHONE_KEYBOARD [self initKeyboard]; #endif + +#if TARGET_OS_TV + SDL_AddHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS, + SDL_AppleTVControllerUIHintChanged, + (__bridge void *) self); +#endif } return self; } @@ -68,6 +86,12 @@ #if SDL_IPHONE_KEYBOARD [self deinitKeyboard]; #endif + +#if TARGET_OS_TV + SDL_DelHintCallback(SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS, + SDL_AppleTVControllerUIHintChanged, + (__bridge void *) self); +#endif } - (void)setAnimationCallback:(int)interval @@ -102,6 +126,9 @@ { /* Don't run the game loop while a messagebox is up */ if (!UIKit_ShowingMessageBox()) { + /* See the comment in the function definition. */ + UIKit_GL_RestoreCurrentContext(); + animationCallback(animationCallbackParam); } } @@ -120,6 +147,7 @@ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); } +#if !TARGET_OS_TV - (NSUInteger)supportedInterfaceOrientations { return UIKit_GetSupportedOrientations(window); @@ -134,6 +162,7 @@ { return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0; } +#endif /* ---- Keyboard related functionality below this line ---- @@ -164,9 +193,11 @@ textField.hidden = YES; keyboardVisible = NO; +#if !TARGET_OS_TV NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; +#endif } - (void)setView:(UIView *)view @@ -182,9 +213,11 @@ - (void)deinitKeyboard { +#if !TARGET_OS_TV NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [center removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +#endif } /* reveal onscreen virtual keyboard */ @@ -205,6 +238,7 @@ - (void)keyboardWillShow:(NSNotification *)notification { +#if !TARGET_OS_TV CGRect kbrect = [[notification userInfo][UIKeyboardFrameBeginUserInfoKey] CGRectValue]; /* The keyboard rect is in the coordinate space of the screen/window, but we @@ -212,10 +246,12 @@ kbrect = [self.view convertRect:kbrect fromView:nil]; [self setKeyboardHeight:(int)kbrect.size.height]; +#endif } - (void)keyboardWillHide:(NSNotification *)notification { + SDL_StopTextInput(); [self setKeyboardHeight:0]; } diff --git a/Engine/lib/sdl/src/video/uikit/SDL_uikitwindow.m b/Engine/lib/sdl/src/video/uikit/SDL_uikitwindow.m index c5f385b8c..35c549b43 100644 --- a/Engine/lib/sdl/src/video/uikit/SDL_uikitwindow.m +++ b/Engine/lib/sdl/src/video/uikit/SDL_uikitwindow.m @@ -99,14 +99,13 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo /* 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 { + if (displaydata.uiscreen != [UIScreen mainScreen]) { 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 !TARGET_OS_TV if (displaydata.uiscreen == [UIScreen mainScreen]) { NSUInteger orients = UIKit_GetSupportedOrientations(window); BOOL supportsLandscape = (orients & UIInterfaceOrientationMaskLandscape) != 0; @@ -119,6 +118,7 @@ static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bo height = temp; } } +#endif /* !TARGET_OS_TV */ window->x = 0; window->y = 0; @@ -152,7 +152,6 @@ UIKit_CreateWindow(_THIS, SDL_Window *window) @autoreleasepool { SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); SDL_DisplayData *data = (__bridge SDL_DisplayData *) display->driverdata; - const CGSize origsize = data.uiscreen.currentMode.size; /* SDL currently puts this window at the start of display's linked list. We rely on this. */ SDL_assert(_this->windows == window); @@ -165,6 +164,8 @@ UIKit_CreateWindow(_THIS, SDL_Window *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 !TARGET_OS_TV + const CGSize origsize = data.uiscreen.currentMode.size; if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) { if (display->num_display_modes == 0) { _this->GetDisplayModes(_this, display); @@ -197,6 +198,7 @@ UIKit_CreateWindow(_THIS, SDL_Window *window) [UIApplication sharedApplication].statusBarHidden = NO; } } +#endif /* !TARGET_OS_TV */ /* ignore the size user requested, and make a fullscreen window */ /* !!! FIXME: can we have a smaller view? */ @@ -258,6 +260,7 @@ UIKit_UpdateWindowBorder(_THIS, SDL_Window * window) SDL_WindowData *data = (__bridge SDL_WindowData *) window->driverdata; SDL_uikitviewcontroller *viewcontroller = data.viewcontroller; +#if !TARGET_OS_TV if (data.uiwindow.screen == [UIScreen mainScreen]) { if (window->flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS)) { [UIApplication sharedApplication].statusBarHidden = YES; @@ -273,6 +276,7 @@ UIKit_UpdateWindowBorder(_THIS, SDL_Window * window) /* Update the view's frame to account for the status bar change. */ viewcontroller.view.frame = UIKit_ComputeViewFrame(window, data.uiwindow.screen); +#endif /* !TARGET_OS_TV */ #ifdef SDL_IPHONE_KEYBOARD /* Make sure the view is offset correctly when the keyboard is visible. */ @@ -363,6 +367,7 @@ UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) } } +#if !TARGET_OS_TV NSUInteger UIKit_GetSupportedOrientations(SDL_Window * window) { @@ -428,6 +433,7 @@ UIKit_GetSupportedOrientations(SDL_Window * window) return orientationMask; } +#endif /* !TARGET_OS_TV */ int SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam) diff --git a/Engine/lib/sdl/src/video/vivante/SDL_vivantevideo.c b/Engine/lib/sdl/src/video/vivante/SDL_vivantevideo.c index fe4ea089d..0372de5c3 100644 --- a/Engine/lib/sdl/src/video/vivante/SDL_vivantevideo.c +++ b/Engine/lib/sdl/src/video/vivante/SDL_vivantevideo.c @@ -77,7 +77,7 @@ VIVANTE_Create() device->driverdata = data; - /* Setup amount of available displays and current display */ + /* Setup amount of available displays */ device->num_displays = 0; /* Set device free function */ @@ -366,12 +366,13 @@ VIVANTE_HideWindow(_THIS, SDL_Window * window) SDL_bool VIVANTE_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) { -/* SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_DisplayData *displaydata = SDL_GetDisplayDriverData(0); if (info->version.major == SDL_MAJOR_VERSION && info->version.minor == SDL_MINOR_VERSION) { info->subsystem = SDL_SYSWM_VIVANTE; + info->info.vivante.display = displaydata->native_display; info->info.vivante.window = data->native_window; return SDL_TRUE; } else { @@ -379,9 +380,6 @@ VIVANTE_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info) SDL_MAJOR_VERSION, SDL_MINOR_VERSION); return SDL_FALSE; } -*/ - SDL_Unsupported(); - return SDL_FALSE; } /*****************************************************************************/ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.c b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.c index bc1d06e46..14674fbe2 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.c @@ -94,9 +94,6 @@ WAYLAND_GetSym(const char *fnname, int *pHasModule) #define SDL_WAYLAND_SYM(rc,fn,params) SDL_DYNWAYLANDFN_##fn WAYLAND_##fn = NULL; #define SDL_WAYLAND_INTERFACE(iface) const struct wl_interface *WAYLAND_##iface = NULL; #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE static int wayland_load_refcount = 0; @@ -115,9 +112,6 @@ SDL_WAYLAND_UnloadSymbols(void) #define SDL_WAYLAND_SYM(rc,fn,params) WAYLAND_##fn = NULL; #define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = NULL; #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE #ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @@ -150,20 +144,12 @@ SDL_WAYLAND_LoadSymbols(void) } #define SDL_WAYLAND_MODULE(modname) SDL_WAYLAND_HAVE_##modname = 1; /* default yes */ -#define SDL_WAYLAND_SYM(rc,fn,params) -#define SDL_WAYLAND_INTERFACE(iface) #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE #define SDL_WAYLAND_MODULE(modname) thismod = &SDL_WAYLAND_HAVE_##modname; #define SDL_WAYLAND_SYM(rc,fn,params) WAYLAND_##fn = (SDL_DYNWAYLANDFN_##fn) WAYLAND_GetSym(#fn,thismod); #define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = (struct wl_interface *) WAYLAND_GetSym(#iface,thismod); #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT) { /* all required symbols loaded. */ @@ -180,9 +166,6 @@ SDL_WAYLAND_LoadSymbols(void) #define SDL_WAYLAND_SYM(rc,fn,params) WAYLAND_##fn = fn; #define SDL_WAYLAND_INTERFACE(iface) WAYLAND_##iface = &iface; #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE #endif } diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h index b3ff9d8e9..f1f652566 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylanddyn.h @@ -53,10 +53,7 @@ void SDL_WAYLAND_UnloadSymbols(void); extern SDL_DYNWAYLANDFN_##fn WAYLAND_##fn; #define SDL_WAYLAND_INTERFACE(iface) extern const struct wl_interface *WAYLAND_##iface; #include "SDL_waylandsym.h" -#undef SDL_WAYLAND_MODULE -#undef SDL_WAYLAND_SYM -#undef SDL_WAYLAND_INTERFACE - + #ifdef __cplusplus } @@ -79,6 +76,7 @@ void SDL_WAYLAND_UnloadSymbols(void); #define wl_proxy_get_user_data (*WAYLAND_wl_proxy_get_user_data) #define wl_proxy_add_listener (*WAYLAND_wl_proxy_add_listener) #define wl_proxy_marshal_constructor (*WAYLAND_wl_proxy_marshal_constructor) +#define wl_proxy_marshal_constructor_versioned (*WAYLAND_wl_proxy_marshal_constructor_versioned) #define wl_seat_interface (*WAYLAND_wl_seat_interface) #define wl_surface_interface (*WAYLAND_wl_surface_interface) @@ -96,7 +94,8 @@ void SDL_WAYLAND_UnloadSymbols(void); #endif /* SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC */ -#include "wayland-client.h" +#include "wayland-client-core.h" +#include "wayland-client-protocol.h" #include "wayland-egl.h" #endif /* !defined _SDL_waylanddyn_h */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c index 53b0ac907..2443aef7a 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents.c @@ -25,6 +25,7 @@ #include "SDL_stdinc.h" #include "SDL_assert.h" +#include "SDL_log.h" #include "../../events/SDL_sysevents.h" #include "../../events/SDL_events_c.h" @@ -36,11 +37,13 @@ #include "SDL_waylanddyn.h" +#include "pointer-constraints-unstable-v1-client-protocol.h" +#include "relative-pointer-unstable-v1-client-protocol.h" + #include #include #include #include -#include #include #include @@ -49,13 +52,17 @@ struct SDL_WaylandInput { struct wl_seat *seat; struct wl_pointer *pointer; struct wl_keyboard *keyboard; + struct zwp_relative_pointer_v1 *relative_pointer; SDL_WindowData *pointer_focus; SDL_WindowData *keyboard_focus; /* Last motion location */ wl_fixed_t sx_w; wl_fixed_t sy_w; - + + double dx_frac; + double dy_frac; + struct { struct xkb_keymap *keymap; struct xkb_state *state; @@ -171,10 +178,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) } static void -pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, - uint32_t time, uint32_t button, uint32_t state_w) +pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) { - struct SDL_WaylandInput *input = data; SDL_WindowData *window = input->pointer_focus; enum wl_pointer_button_state state = state_w; uint32_t sdl_button; @@ -183,7 +189,7 @@ 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)) { + if (ProcessHitTest(input, serial)) { return; /* don't pass this event on to app. */ } break; @@ -209,10 +215,18 @@ pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, } static void -pointer_handle_axis(void *data, struct wl_pointer *pointer, - uint32_t time, uint32_t axis, wl_fixed_t value) +pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial, + uint32_t time, uint32_t button, uint32_t state_w) { struct SDL_WaylandInput *input = data; + + pointer_handle_button_common(input, serial, time, button, state_w); +} + +static void +pointer_handle_axis_common(struct SDL_WaylandInput *input, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ SDL_WindowData *window = input->pointer_focus; enum wl_pointer_axis a = axis; int x, y; @@ -235,6 +249,15 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer, } } +static void +pointer_handle_axis(void *data, struct wl_pointer *pointer, + uint32_t time, uint32_t axis, wl_fixed_t value) +{ + struct SDL_WaylandInput *input = data; + + pointer_handle_axis_common(input, time, axis, value); +} + static const struct wl_pointer_listener pointer_listener = { pointer_handle_enter, pointer_handle_leave, @@ -302,9 +325,9 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, window = wl_surface_get_user_data(surface); - input->keyboard_focus = window; - window->keyboard_device = input; if (window) { + input->keyboard_focus = window; + window->keyboard_device = input; SDL_SetKeyboardFocus(window->sdlwindow); } } @@ -454,6 +477,164 @@ void Wayland_display_destroy_input(SDL_VideoData *d) d->input = NULL; } +void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id) +{ + d->relative_pointer_manager = + wl_registry_bind(d->registry, id, + &zwp_relative_pointer_manager_v1_interface, 1); +} + +void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d) +{ + if (d->relative_pointer_manager) + zwp_relative_pointer_manager_v1_destroy(d->relative_pointer_manager); +} + +void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id) +{ + d->pointer_constraints = + wl_registry_bind(d->registry, id, + &zwp_pointer_constraints_v1_interface, 1); +} + +void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d) +{ + if (d->pointer_constraints) + zwp_pointer_constraints_v1_destroy(d->pointer_constraints); +} + +static void +relative_pointer_handle_relative_motion(void *data, + struct zwp_relative_pointer_v1 *pointer, + uint32_t time_hi, + uint32_t time_lo, + wl_fixed_t dx_w, + wl_fixed_t dy_w, + wl_fixed_t dx_unaccel_w, + wl_fixed_t dy_unaccel_w) +{ + struct SDL_WaylandInput *input = data; + SDL_VideoData *d = input->display; + SDL_WindowData *window = input->pointer_focus; + double dx_unaccel; + double dy_unaccel; + double dx; + double dy; + + dx_unaccel = wl_fixed_to_double(dx_unaccel_w); + dy_unaccel = wl_fixed_to_double(dy_unaccel_w); + + /* Add left over fraction from last event. */ + dx_unaccel += input->dx_frac; + dy_unaccel += input->dy_frac; + + input->dx_frac = modf(dx_unaccel, &dx); + input->dy_frac = modf(dy_unaccel, &dy); + + if (input->pointer_focus && d->relative_mouse_mode) { + SDL_SendMouseMotion(window->sdlwindow, 0, 1, (int)dx, (int)dy); + } +} + +static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = { + relative_pointer_handle_relative_motion, +}; + +static void +locked_pointer_locked(void *data, + struct zwp_locked_pointer_v1 *locked_pointer) +{ +} + +static void +locked_pointer_unlocked(void *data, + struct zwp_locked_pointer_v1 *locked_pointer) +{ +} + +static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { + locked_pointer_locked, + locked_pointer_unlocked, +}; + +static void +lock_pointer_to_window(SDL_Window *window, + struct SDL_WaylandInput *input) +{ + SDL_WindowData *w = window->driverdata; + SDL_VideoData *d = input->display; + struct zwp_locked_pointer_v1 *locked_pointer; + + if (w->locked_pointer) + return; + + locked_pointer = + zwp_pointer_constraints_v1_lock_pointer(d->pointer_constraints, + w->surface, + input->pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_add_listener(locked_pointer, + &locked_pointer_listener, + window); + + w->locked_pointer = locked_pointer; +} + +int Wayland_input_lock_pointer(struct SDL_WaylandInput *input) +{ + SDL_VideoDevice *vd = SDL_GetVideoDevice(); + SDL_VideoData *d = input->display; + SDL_Window *window; + struct zwp_relative_pointer_v1 *relative_pointer; + + if (!d->relative_pointer_manager) + return -1; + + if (!d->pointer_constraints) + return -1; + + if (!input->relative_pointer) { + relative_pointer = + zwp_relative_pointer_manager_v1_get_relative_pointer( + d->relative_pointer_manager, + input->pointer); + zwp_relative_pointer_v1_add_listener(relative_pointer, + &relative_pointer_listener, + input); + input->relative_pointer = relative_pointer; + } + + for (window = vd->windows; window; window = window->next) + lock_pointer_to_window(window, input); + + d->relative_mouse_mode = 1; + + return 0; +} + +int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input) +{ + SDL_VideoDevice *vd = SDL_GetVideoDevice(); + SDL_VideoData *d = input->display; + SDL_Window *window; + SDL_WindowData *w; + + for (window = vd->windows; window; window = window->next) { + w = window->driverdata; + if (w->locked_pointer) + zwp_locked_pointer_v1_destroy(w->locked_pointer); + w->locked_pointer = NULL; + } + + zwp_relative_pointer_v1_destroy(input->relative_pointer); + input->relative_pointer = NULL; + + d->relative_mouse_mode = 0; + + return 0; +} + #endif /* SDL_VIDEO_DRIVER_WAYLAND */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h index 62b163bf6..56d12ec27 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandevents_c.h @@ -32,6 +32,15 @@ extern void Wayland_PumpEvents(_THIS); extern void Wayland_display_add_input(SDL_VideoData *d, uint32_t id); extern void Wayland_display_destroy_input(SDL_VideoData *d); +extern void Wayland_display_add_pointer_constraints(SDL_VideoData *d, uint32_t id); +extern void Wayland_display_destroy_pointer_constraints(SDL_VideoData *d); + +extern int Wayland_input_lock_pointer(struct SDL_WaylandInput *input); +extern int Wayland_input_unlock_pointer(struct SDL_WaylandInput *input); + +extern void Wayland_display_add_relative_pointer_manager(SDL_VideoData *d, uint32_t id); +extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d); + #endif /* _SDL_waylandevents_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandmouse.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandmouse.c index b810f7784..8dfc9eea3 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandmouse.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandmouse.c @@ -27,7 +27,6 @@ #define _GNU_SOURCE #endif -#include #include #include #include @@ -70,7 +69,6 @@ wayland_create_tmp_file(off_t size) xdg_path = SDL_getenv("XDG_RUNTIME_DIR"); if (!xdg_path) { - errno = ENOENT; return -1; } @@ -116,8 +114,7 @@ create_buffer_from_shm(Wayland_CursorData *d, shm_fd = wayland_create_tmp_file(size); if (shm_fd < 0) { - fprintf(stderr, "creating mouse cursor buffer failed!\n"); - return -1; + return SDL_SetError("Creating mouse cursor buffer failed."); } d->shm_data = mmap(NULL, @@ -128,8 +125,8 @@ create_buffer_from_shm(Wayland_CursorData *d, 0); if (d->shm_data == MAP_FAILED) { d->shm_data = NULL; - fprintf (stderr, "mmap () failed\n"); close (shm_fd); + return SDL_SetError("mmap() failed."); } shm_pool = wl_shm_create_pool(data->shm, shm_fd, size); @@ -159,6 +156,11 @@ Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) SDL_VideoDevice *vd = SDL_GetVideoDevice (); SDL_VideoData *wd = (SDL_VideoData *) vd->driverdata; Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData)); + if (!data) { + SDL_OutOfMemory(); + free(cursor); + return NULL; + } cursor->driverdata = (void *) data; /* Assume ARGB8888 */ @@ -169,7 +171,7 @@ Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) if (create_buffer_from_shm (data, surface->w, surface->h, - WL_SHM_FORMAT_XRGB8888) < 0) + WL_SHM_FORMAT_ARGB8888) < 0) { free (cursor->driverdata); free (cursor); @@ -187,6 +189,8 @@ Wayland_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) data->hot_y = hot_y; data->w = surface->w; data->h = surface->h; + } else { + SDL_OutOfMemory(); } return cursor; @@ -200,6 +204,11 @@ CreateCursorFromWlCursor(SDL_VideoData *d, struct wl_cursor *wlcursor) cursor = calloc(1, sizeof (*cursor)); if (cursor) { Wayland_CursorData *data = calloc (1, sizeof (Wayland_CursorData)); + if (!data) { + SDL_OutOfMemory(); + free(cursor); + return NULL; + } cursor->driverdata = (void *) data; data->buffer = WAYLAND_wl_cursor_image_get_buffer(wlcursor->images[0]); @@ -322,13 +331,13 @@ Wayland_ShowCursor(SDL_Cursor *cursor) { Wayland_CursorData *data = cursor->driverdata; - wl_surface_attach(data->surface, data->buffer, 0, 0); - wl_surface_damage(data->surface, 0, 0, data->w, data->h); - wl_surface_commit(data->surface); wl_pointer_set_cursor (pointer, 0, data->surface, data->hot_x, data->hot_y); + wl_surface_attach(data->surface, data->buffer, 0, 0); + wl_surface_damage(data->surface, 0, 0, data->w, data->h); + wl_surface_commit(data->surface); } else { @@ -356,7 +365,13 @@ Wayland_WarpMouseGlobal(int x, int y) static int Wayland_SetRelativeMouseMode(SDL_bool enabled) { - return SDL_Unsupported(); + SDL_VideoDevice *vd = SDL_GetVideoDevice(); + SDL_VideoData *data = (SDL_VideoData *) vd->driverdata; + + if (enabled) + return Wayland_input_lock_pointer(data->input); + else + return Wayland_input_unlock_pointer(data->input); } void diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h index b093d9db1..aea3cb129 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandsym.h @@ -21,6 +21,18 @@ /* *INDENT-OFF* */ +#ifndef SDL_WAYLAND_MODULE +#define SDL_WAYLAND_MODULE(modname) +#endif + +#ifndef SDL_WAYLAND_SYM +#define SDL_WAYLAND_SYM(rc,fn,params) +#endif + +#ifndef SDL_WAYLAND_INTERFACE +#define SDL_WAYLAND_INTERFACE(iface) +#endif + SDL_WAYLAND_MODULE(WAYLAND_CLIENT) SDL_WAYLAND_SYM(void, wl_proxy_marshal, (struct wl_proxy *, uint32_t, ...)) SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_create, (struct wl_proxy *, const struct wl_interface *)) @@ -55,6 +67,9 @@ SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *)) SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_4) SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy *, uint32_t opcode, const struct wl_interface *interface, ...)) +SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10) +SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...)) + SDL_WAYLAND_INTERFACE(wl_seat_interface) SDL_WAYLAND_INTERFACE(wl_surface_interface) SDL_WAYLAND_INTERFACE(wl_shm_pool_interface) @@ -99,8 +114,10 @@ SDL_WAYLAND_SYM(enum xkb_state_component, xkb_state_update_mask, (struct xkb_sta xkb_layout_index_t latched_layout,\ xkb_layout_index_t locked_layout) ) +#undef SDL_WAYLAND_MODULE +#undef SDL_WAYLAND_SYM +#undef SDL_WAYLAND_INTERFACE /* *INDENT-ON* */ /* vi: set ts=4 sw=4 expandtab: */ -//SDL_WAYLAND_SYM(ret, fn, params) diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c index b47ec29be..554b0ecad 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.c @@ -35,6 +35,8 @@ #include "SDL_waylandmouse.h" #include "SDL_waylandtouch.h" +#include +#include #include #include @@ -55,6 +57,56 @@ Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); static void Wayland_VideoQuit(_THIS); +/* Find out what class name we should use + * Based on src/video/x11/SDL_x11video.c */ +static char * +get_classname() +{ + char *spot; +#if defined(__LINUX__) || defined(__FREEBSD__) + char procfile[1024]; + char linkfile[1024]; + int linksize; +#endif + + /* First allow environment variable override */ + spot = SDL_getenv("SDL_VIDEO_WAYLAND_WMCLASS"); + if (spot) { + return SDL_strdup(spot); + } else { + /* Fallback to the "old" envvar */ + spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS"); + if (spot) { + return SDL_strdup(spot); + } + } + + /* Next look at the application's executable name */ +#if defined(__LINUX__) || defined(__FREEBSD__) +#if defined(__LINUX__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid()); +#elif defined(__FREEBSD__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file", + getpid()); +#else +#error Where can we find the executable name? +#endif + linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1); + if (linksize > 0) { + linkfile[linksize] = '\0'; + spot = SDL_strrchr(linkfile, '/'); + if (spot) { + return SDL_strdup(spot + 1); + } else { + return SDL_strdup(linkfile); + } + } +#endif /* __LINUX__ || __FREEBSD__ */ + + /* Finally use the default we've used forever */ + return SDL_strdup("SDL_App"); +} + /* Wayland driver bootstrap functions */ static int Wayland_Available(void) @@ -117,7 +169,10 @@ Wayland_CreateDevice(int devindex) device->CreateWindow = Wayland_CreateWindow; device->ShowWindow = Wayland_ShowWindow; device->SetWindowFullscreen = Wayland_SetWindowFullscreen; + device->MaximizeWindow = Wayland_MaximizeWindow; + device->RestoreWindow = Wayland_RestoreWindow; device->SetWindowSize = Wayland_SetWindowSize; + device->SetWindowTitle = Wayland_SetWindowTitle; device->DestroyWindow = Wayland_DestroyWindow; device->SetWindowHitTest = Wayland_SetWindowHitTest; @@ -145,7 +200,7 @@ display_handle_geometry(void *data, { SDL_VideoDisplay *display = data; - display->name = strdup(model); + display->name = SDL_strdup(model); display->driverdata = output; } @@ -253,8 +308,10 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } else if (strcmp(interface, "wl_shm") == 0) { 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"); - + } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) { + Wayland_display_add_relative_pointer_manager(d, id); + } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) { + Wayland_display_add_pointer_constraints(d, id); #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (strcmp(interface, "qt_touch_extension") == 0) { Wayland_touch_create(d, id); @@ -283,6 +340,11 @@ Wayland_VideoInit(_THIS) _this->driverdata = data; + data->xkb_context = WAYLAND_xkb_context_new(0); + if (!data->xkb_context) { + return SDL_SetError("Failed to create XKB context"); + } + data->display = WAYLAND_wl_display_connect(NULL); if (data->display == NULL) { return SDL_SetError("Failed to connect to a Wayland display"); @@ -301,13 +363,11 @@ Wayland_VideoInit(_THIS) // 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) { - return SDL_SetError("Failed to create XKB context"); - } - Wayland_InitMouse(); + /* Get the surface class name, usually the name of the application */ + data->classname = get_classname(); + WAYLAND_wl_display_flush(data->display); return 0; @@ -341,6 +401,8 @@ Wayland_VideoQuit(_THIS) } Wayland_display_destroy_input(data); + Wayland_display_destroy_pointer_constraints(data); + Wayland_display_destroy_relative_pointer_manager(data); if (data->xkb_context) { WAYLAND_xkb_context_unref(data->xkb_context); @@ -376,6 +438,7 @@ Wayland_VideoQuit(_THIS) WAYLAND_wl_display_disconnect(data->display); } + SDL_free(data->classname); free(data); _this->driverdata = NULL; } diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h index 8111bf153..ccd7ecf92 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandvideo.h @@ -42,9 +42,10 @@ typedef struct { struct wl_compositor *compositor; struct wl_shm *shm; struct wl_cursor_theme *cursor_theme; - struct wl_cursor *default_cursor; struct wl_pointer *pointer; struct wl_shell *shell; + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; + struct zwp_pointer_constraints_v1 *pointer_constraints; EGLDisplay edpy; EGLContext context; @@ -58,6 +59,10 @@ typedef struct { struct qt_surface_extension *surface_extension; struct qt_windowmanager *windowmanager; #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + + char *classname; + + int relative_mouse_mode; } SDL_VideoData; #endif /* _SDL_waylandvideo_h */ diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c index b59759a7c..85fca8de6 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.c @@ -26,6 +26,7 @@ #include "../SDL_sysvideo.h" #include "../../events/SDL_windowevents_c.h" #include "../SDL_egl_c.h" +#include "SDL_waylandevents_c.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" @@ -46,6 +47,33 @@ handle_configure(void *data, struct wl_shell_surface *shell_surface, SDL_Window *window = wind->sdlwindow; struct wl_region *region; + /* wl_shell_surface spec states that this is a suggestion. + Ignore if less than or greater than max/min size. */ + + if (width == 0 || height == 0) { + return; + } + + if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { + if ((window->flags & SDL_WINDOW_RESIZABLE)) { + if (window->max_w > 0) { + width = SDL_min(width, window->max_w); + } + width = SDL_max(width, window->min_w); + + if (window->max_h > 0) { + height = SDL_min(height, window->max_h); + } + height = SDL_max(height, window->min_h); + } else { + return; + } + } + + if (width == window->w && height == window->h) { + return; + } + window->w = width; window->h = height; WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0); @@ -145,6 +173,26 @@ Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display ); } +void +Wayland_RestoreWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *wind = window->driverdata; + + wl_shell_surface_set_toplevel(wind->shell_surface); + + WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display ); +} + +void +Wayland_MaximizeWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *wind = window->driverdata; + + wl_shell_surface_set_maximized(wind->shell_surface, NULL); + + WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display ); +} + int Wayland_CreateWindow(_THIS, SDL_Window *window) { SDL_WindowData *data; @@ -178,6 +226,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) wl_surface_set_user_data(data->surface, data); data->shell_surface = wl_shell_get_shell_surface(c->shell, data->surface); + wl_shell_surface_set_class (data->shell_surface, c->classname); #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH if (c->surface_extension) { data->extended_surface = qt_surface_extension_get_extended_surface( @@ -214,6 +263,10 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) wl_surface_set_opaque_region(data->surface, region); wl_region_destroy(region); + if (c->relative_mouse_mode) { + Wayland_input_lock_pointer(c->input); + } + WAYLAND_wl_display_flush(c->display); return 0; @@ -233,6 +286,17 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) wl_region_destroy(region); } +void Wayland_SetWindowTitle(_THIS, SDL_Window * window) +{ + SDL_WindowData *wind = window->driverdata; + + if (window->title != NULL) { + wl_shell_surface_set_title(wind->shell_surface, window->title); + } + + WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display ); +} + void Wayland_DestroyWindow(_THIS, SDL_Window *window) { SDL_VideoData *data = _this->driverdata; diff --git a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h index 053b1281f..319a573dc 100644 --- a/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h +++ b/Engine/lib/sdl/src/video/wayland/SDL_waylandwindow.h @@ -39,6 +39,7 @@ typedef struct { struct wl_egl_window *egl_window; struct SDL_WaylandInput *keyboard_device; EGLSurface egl_surface; + struct zwp_locked_pointer_v1 *locked_pointer; #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct qt_extended_surface *extended_surface; @@ -49,8 +50,11 @@ extern void Wayland_ShowWindow(_THIS, SDL_Window *window); extern void Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen); +extern void Wayland_MaximizeWindow(_THIS, SDL_Window * window); +extern void Wayland_RestoreWindow(_THIS, SDL_Window * window); extern int Wayland_CreateWindow(_THIS, SDL_Window *window); extern void Wayland_SetWindowSize(_THIS, SDL_Window * window); +extern void Wayland_SetWindowTitle(_THIS, SDL_Window * window); extern void Wayland_DestroyWindow(_THIS, SDL_Window *window); extern SDL_bool diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c b/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c index 61420894f..02768fb68 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsevents.c @@ -198,13 +198,26 @@ WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam) return code; } +static SDL_bool +WIN_ShouldIgnoreFocusClick() +{ + return !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE); +} void 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; - WIN_UpdateClipCursor(data->window); + if (data->focus_click_pending & SDL_BUTTON(button)) { + /* Ignore the button click for activation */ + if (!bwParamMousePressed) { + data->focus_click_pending &= ~SDL_BUTTON(button); + if (!data->focus_click_pending) { + WIN_UpdateClipCursor(data->window); + } + } + if (WIN_ShouldIgnoreFocusClick()) { + return; + } } if (bwParamMousePressed && !bSDLMousePressed) { @@ -326,17 +339,7 @@ WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text) 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; + return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE); } LRESULT CALLBACK @@ -398,8 +401,24 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) minimized = HIWORD(wParam); if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) { - data->focus_click_pending = (GetAsyncKeyState(VK_LBUTTON) != 0); - + if (LOWORD(wParam) == WA_CLICKACTIVE) { + if (GetAsyncKeyState(VK_LBUTTON)) { + data->focus_click_pending |= SDL_BUTTON_LMASK; + } + if (GetAsyncKeyState(VK_RBUTTON)) { + data->focus_click_pending |= SDL_BUTTON_RMASK; + } + if (GetAsyncKeyState(VK_MBUTTON)) { + data->focus_click_pending |= SDL_BUTTON_MMASK; + } + if (GetAsyncKeyState(VK_XBUTTON1)) { + data->focus_click_pending |= SDL_BUTTON_X1MASK; + } + if (GetAsyncKeyState(VK_XBUTTON2)) { + data->focus_click_pending |= SDL_BUTTON_X2MASK; + } + } + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0); if (SDL_GetKeyboardFocus() != data->window) { SDL_SetKeyboardFocus(data->window); @@ -423,6 +442,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (SDL_GetKeyboardFocus() == data->window) { SDL_SetKeyboardFocus(NULL); + WIN_ResetDeadKeys(); } ClipCursor(NULL); @@ -737,6 +757,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; #endif /* WM_GETMINMAXINFO */ + case WM_WINDOWPOSCHANGING: + + if (data->expected_resize) { + returnCode = 0; + } + break; + case WM_WINDOWPOSCHANGED: { RECT rect; @@ -763,6 +790,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) h = rect.bottom - rect.top; SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, h); + + /* Forces a WM_PAINT event */ + InvalidateRect(hwnd, NULL, FALSE); } break; @@ -907,12 +937,13 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) if (buffer) { if (DragQueryFile(drop, i, buffer, size)) { char *file = WIN_StringToUTF8(buffer); - SDL_SendDropFile(file); + SDL_SendDropFile(data->window, file); SDL_free(file); } SDL_stack_free(buffer); } } + SDL_SendDropComplete(data->window); DragFinish(drop); return 0; } @@ -927,15 +958,17 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) const SDL_Point point = { (int) winpoint.x, (int) winpoint.y }; const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data); switch (rc) { - case SDL_HITTEST_DRAGGABLE: return HTCAPTION; - case SDL_HITTEST_RESIZE_TOPLEFT: return HTTOPLEFT; - case SDL_HITTEST_RESIZE_TOP: return HTTOP; - case SDL_HITTEST_RESIZE_TOPRIGHT: return HTTOPRIGHT; - case SDL_HITTEST_RESIZE_RIGHT: return HTRIGHT; - case SDL_HITTEST_RESIZE_BOTTOMRIGHT: return HTBOTTOMRIGHT; - case SDL_HITTEST_RESIZE_BOTTOM: return HTBOTTOM; - case SDL_HITTEST_RESIZE_BOTTOMLEFT: return HTBOTTOMLEFT; - case SDL_HITTEST_RESIZE_LEFT: return HTLEFT; + #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; } + case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION); + case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT); + case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP); + case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT); + case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT); + case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT); + case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM); + case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT); + case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT); + #undef POST_HIT_TEST case SDL_HITTEST_NORMAL: return HTCLIENT; } } @@ -1012,7 +1045,8 @@ HINSTANCE SDL_Instance = NULL; int SDL_RegisterApp(char *name, Uint32 style, void *hInst) { - WNDCLASS class; + WNDCLASSEX wcex; + TCHAR path[MAX_PATH]; /* Only do this once... */ if (app_registered) { @@ -1034,19 +1068,24 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst) } /* Register the application class */ - class.hCursor = NULL; - class.hIcon = - LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0, - LR_DEFAULTCOLOR); - class.lpszMenuName = NULL; - class.lpszClassName = SDL_Appname; - class.hbrBackground = NULL; - class.hInstance = SDL_Instance; - class.style = SDL_Appstyle; - class.lpfnWndProc = WIN_WindowProc; - class.cbWndExtra = 0; - class.cbClsExtra = 0; - if (!RegisterClass(&class)) { + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.hCursor = NULL; + wcex.hIcon = NULL; + wcex.hIconSm = NULL; + wcex.lpszMenuName = NULL; + wcex.lpszClassName = SDL_Appname; + wcex.style = SDL_Appstyle; + wcex.hbrBackground = NULL; + wcex.lpfnWndProc = WIN_WindowProc; + wcex.hInstance = SDL_Instance; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + + /* Use the first icon as a default icon, like in the Explorer */ + GetModuleFileName(SDL_Instance, path, MAX_PATH); + ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1); + + if (!RegisterClassEx(&wcex)) { return SDL_SetError("Couldn't register application class"); } @@ -1058,7 +1097,7 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst) void SDL_UnregisterApp() { - WNDCLASS class; + WNDCLASSEX wcex; /* SDL_RegisterApp might not have been called before */ if (!app_registered) { @@ -1067,8 +1106,10 @@ SDL_UnregisterApp() --app_registered; if (app_registered == 0) { /* Check for any registered window classes. */ - if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) { + if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) { UnregisterClass(SDL_Appname, SDL_Instance); + if (wcex.hIcon) DestroyIcon(wcex.hIcon); + if (wcex.hIconSm) DestroyIcon(wcex.hIconSm); } SDL_free(SDL_Appname); SDL_Appname = NULL; diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.c b/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.c index d3e16c8bf..8271b0421 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.c @@ -157,11 +157,47 @@ WIN_QuitKeyboard(_THIS) #endif } +void +WIN_ResetDeadKeys() +{ + /* + if a deadkey has been typed, but not the next character (which the deadkey might modify), + this tries to undo the effect pressing the deadkey. + see: http://archives.miloush.net/michkap/archive/2006/09/10/748775.html + */ + BYTE keyboardState[256]; + WCHAR buffer[16]; + int keycode, scancode, result, i; + + GetKeyboardState(keyboardState); + + keycode = VK_SPACE; + scancode = MapVirtualKey(keycode, MAPVK_VK_TO_VSC); + if (scancode == 0) { + /* the keyboard doesn't have this key */ + return; + } + + for (i = 0; i < 5; i++) { + result = ToUnicode(keycode, scancode, keyboardState, (LPWSTR)buffer, 16, 0); + if (result > 0) { + /* success */ + return; + } + } +} + void WIN_StartTextInput(_THIS) { #ifndef SDL_DISABLE_WINDOWS_IME - SDL_Window *window = SDL_GetKeyboardFocus(); + SDL_Window *window; +#endif + + WIN_ResetDeadKeys(); + +#ifndef SDL_DISABLE_WINDOWS_IME + window = SDL_GetKeyboardFocus(); if (window) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; @@ -176,7 +212,13 @@ void WIN_StopTextInput(_THIS) { #ifndef SDL_DISABLE_WINDOWS_IME - SDL_Window *window = SDL_GetKeyboardFocus(); + SDL_Window *window; +#endif + + WIN_ResetDeadKeys(); + +#ifndef SDL_DISABLE_WINDOWS_IME + window = SDL_GetKeyboardFocus(); if (window) { HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.h b/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.h index d330d3871..84654d7b8 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.h +++ b/Engine/lib/sdl/src/video/windows/SDL_windowskeyboard.h @@ -27,6 +27,8 @@ extern void WIN_InitKeyboard(_THIS); extern void WIN_UpdateKeymap(void); extern void WIN_QuitKeyboard(_THIS); +extern void WIN_ResetDeadKeys(void); + extern void WIN_StartTextInput(_THIS); extern void WIN_StopTextInput(_THIS); extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect); diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsmessagebox.c b/Engine/lib/sdl/src/video/windows/SDL_windowsmessagebox.c index b39df32fc..689e5bbc3 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsmessagebox.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsmessagebox.c @@ -452,9 +452,9 @@ WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) } /* Align the buttons to the right/bottom. */ - x = Size.cx - ButtonWidth - ButtonMargin; + x = Size.cx - (ButtonWidth + ButtonMargin) * messageboxdata->numbuttons; y = Size.cy - ButtonHeight - ButtonMargin; - for (i = 0; i < messageboxdata->numbuttons; ++i) { + for (i = messageboxdata->numbuttons - 1; i >= 0; --i) { SDL_bool isDefault; if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) { @@ -466,7 +466,7 @@ WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) FreeDialogData(dialog); return -1; } - x -= ButtonWidth + ButtonMargin; + x += ButtonWidth + ButtonMargin; } /* FIXME: If we have a parent window, get the Instance and HWND for them */ diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.c b/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.c index 91ed67f87..f172f9a3d 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.c @@ -23,6 +23,7 @@ #if SDL_VIDEO_DRIVER_WINDOWS #include "SDL_windowsvideo.h" +#include "../../../include/SDL_assert.h" /* Windows CE compatibility */ #ifndef CDS_FULLSCREEN @@ -69,40 +70,16 @@ WIN_GetMonitorDPI(HMONITOR hMonitor, return TRUE; } -static SDL_bool -WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) +static void +WIN_UpdateDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) { SDL_VideoData *vid_data = (SDL_VideoData *) _this->driverdata; - SDL_DisplayModeData *data; - DEVMODE devmode; + SDL_DisplayModeData *data = (SDL_DisplayModeData *) mode->driverdata; HDC hdc; - devmode.dmSize = sizeof(devmode); - devmode.dmDriverExtra = 0; - if (!EnumDisplaySettings(deviceName, index, &devmode)) { - return SDL_FALSE; - } - - data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); - if (!data) { - return SDL_FALSE; - } - data->DeviceMode = devmode; data->DeviceMode.dmFields = (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | 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; - mode->w = devmode.dmPelsWidth; - mode->h = devmode.dmPelsHeight; - mode->refresh_rate = devmode.dmDisplayFrequency; - mode->driverdata = data; if (index == ENUM_CURRENT_SETTINGS && (hdc = CreateDC(deviceName, NULL, NULL, NULL)) != NULL) { @@ -112,8 +89,8 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod int logical_width = GetDeviceCaps( hdc, HORZRES ); int logical_height = GetDeviceCaps( hdc, VERTRES ); - data->ScaleX = (float)logical_width / devmode.dmPelsWidth; - data->ScaleY = (float)logical_height / devmode.dmPelsHeight; + data->ScaleX = (float)logical_width / data->DeviceMode.dmPelsWidth; + data->ScaleY = (float)logical_height / data->DeviceMode.dmPelsHeight; mode->w = logical_width; mode->h = logical_height; @@ -126,8 +103,8 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod 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.left = data->DeviceMode.dmPosition.x; + monitor_rect.top = data->DeviceMode.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); @@ -175,10 +152,10 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod } else if (bmi->bmiHeader.biBitCount == 4) { mode->format = SDL_PIXELFORMAT_INDEX4LSB; } - } else { + } else if (mode->format == SDL_PIXELFORMAT_UNKNOWN) { /* FIXME: Can we tell what this will be? */ - if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) { - switch (devmode.dmBitsPerPel) { + if ((data->DeviceMode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) { + switch (data->DeviceMode.dmBitsPerPel) { case 32: mode->format = SDL_PIXELFORMAT_RGB888; break; @@ -200,6 +177,42 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod } } } +} + +static SDL_bool +WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mode) +{ + SDL_DisplayModeData *data; + DEVMODE devmode; + + devmode.dmSize = sizeof(devmode); + devmode.dmDriverExtra = 0; + if (!EnumDisplaySettings(deviceName, index, &devmode)) { + return SDL_FALSE; + } + + data = (SDL_DisplayModeData *) SDL_malloc(sizeof(*data)); + if (!data) { + return SDL_FALSE; + } + + mode->driverdata = data; + data->DeviceMode = devmode; + + /* Default basic information */ + data->ScaleX = 1.0f; + data->ScaleY = 1.0f; + data->DiagDPI = 0.0f; + data->HorzDPI = 0.0f; + data->VertDPI = 0.0f; + + mode->format = SDL_PIXELFORMAT_UNKNOWN; + mode->w = data->DeviceMode.dmPelsWidth; + mode->h = data->DeviceMode.dmPelsHeight; + mode->refresh_rate = data->DeviceMode.dmDisplayFrequency; + + /* Fill in the mode information */ + WIN_UpdateDisplayMode(_this, deviceName, index, mode); return SDL_TRUE; } @@ -329,7 +342,44 @@ WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, *vdpi = data->VertDPI; } - return data->DiagDPI != 0.0f ? 0 : -1; + return data->DiagDPI != 0.0f ? 0 : SDL_SetError("Couldn't get DPI"); +} + +int +WIN_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) +{ + const SDL_DisplayModeData *data = (const SDL_DisplayModeData *) display->current_mode.driverdata; + const DEVMODE *pDevMode = &data->DeviceMode; + POINT pt = { + /* !!! FIXME: no scale, right? */ + (LONG) (pDevMode->dmPosition.x + (pDevMode->dmPelsWidth / 2)), + (LONG) (pDevMode->dmPosition.y + (pDevMode->dmPelsHeight / 2)) + }; + HMONITOR hmon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); + MONITORINFO minfo; + const RECT *work; + BOOL rc = FALSE; + + SDL_assert(hmon != NULL); + + if (hmon != NULL) { + SDL_zero(minfo); + minfo.cbSize = sizeof (MONITORINFO); + rc = GetMonitorInfo(hmon, &minfo); + SDL_assert(rc); + } + + if (!rc) { + return SDL_SetError("Couldn't find monitor data"); + } + + work = &minfo.rcWork; + rect->x = (int)SDL_ceil(work->left * data->ScaleX); + rect->y = (int)SDL_ceil(work->top * data->ScaleY); + rect->w = (int)SDL_ceil((work->right - work->left) * data->ScaleX); + rect->h = (int)SDL_ceil((work->bottom - work->top) * data->ScaleY); + + return 0; } void @@ -366,7 +416,7 @@ WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) LONG status; if (mode->driverdata == display->desktop_mode.driverdata) { - status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, 0, NULL); + status = ChangeDisplaySettingsEx(displaydata->DeviceName, NULL, NULL, CDS_FULLSCREEN, NULL); } else { status = ChangeDisplaySettingsEx(displaydata->DeviceName, &data->DeviceMode, NULL, CDS_FULLSCREEN, NULL); } @@ -389,6 +439,7 @@ WIN_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) return SDL_SetError("ChangeDisplaySettingsEx() failed: %s", reason); } EnumDisplaySettings(displaydata->DeviceName, ENUM_CURRENT_SETTINGS, &data->DeviceMode); + WIN_UpdateDisplayMode(_this, displaydata->DeviceName, ENUM_CURRENT_SETTINGS, mode); return 0; } diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.h b/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.h index e725848b2..6aa293d21 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.h +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsmodes.h @@ -40,6 +40,7 @@ typedef struct extern int WIN_InitModes(_THIS); extern int WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); +extern int WIN_GetDisplayUsableBounds(_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); diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowsvideo.c b/Engine/lib/sdl/src/video/windows/SDL_windowsvideo.c index 37199805b..21f63a018 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowsvideo.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowsvideo.c @@ -124,6 +124,7 @@ WIN_CreateDevice(int devindex) device->VideoInit = WIN_VideoInit; device->VideoQuit = WIN_VideoQuit; device->GetDisplayBounds = WIN_GetDisplayBounds; + device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds; device->GetDisplayDPI = WIN_GetDisplayDPI; device->GetDisplayModes = WIN_GetDisplayModes; device->SetDisplayMode = WIN_SetDisplayMode; @@ -136,6 +137,7 @@ WIN_CreateDevice(int devindex) device->SetWindowIcon = WIN_SetWindowIcon; device->SetWindowPosition = WIN_SetWindowPosition; device->SetWindowSize = WIN_SetWindowSize; + device->SetWindowOpacity = WIN_SetWindowOpacity; device->ShowWindow = WIN_ShowWindow; device->HideWindow = WIN_HideWindow; device->RaiseWindow = WIN_RaiseWindow; @@ -143,6 +145,7 @@ WIN_CreateDevice(int devindex) device->MinimizeWindow = WIN_MinimizeWindow; device->RestoreWindow = WIN_RestoreWindow; device->SetWindowBordered = WIN_SetWindowBordered; + device->SetWindowResizable = WIN_SetWindowResizable; device->SetWindowFullscreen = WIN_SetWindowFullscreen; device->SetWindowGammaRamp = WIN_SetWindowGammaRamp; device->GetWindowGammaRamp = WIN_GetWindowGammaRamp; diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c index 26683a0ed..5ce40e6ba 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c +++ b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.c @@ -478,7 +478,8 @@ WIN_HideWindow(_THIS, SDL_Window * window) void WIN_RaiseWindow(_THIS, SDL_Window * window) { - WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE); + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + SetForegroundWindow(hwnd); } void @@ -519,6 +520,22 @@ WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) data->in_border_change = SDL_FALSE; } +void +WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) +{ + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + HWND hwnd = data->hwnd; + DWORD style = GetWindowLong(hwnd, GWL_STYLE); + + if (resizable) { + style |= STYLE_RESIZABLE; + } else { + style &= ~STYLE_RESIZABLE; + } + + SetWindowLong(hwnd, GWL_STYLE, style); +} + void WIN_RestoreWindow(_THIS, SDL_Window * window) { @@ -826,6 +843,39 @@ WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled) return 0; /* just succeed, the real work is done elsewhere. */ } +int +WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) +{ + const SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + const HWND hwnd = data->hwnd; + const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE); + + SDL_assert(style != 0); + + if (opacity == 1.0f) { + /* want it fully opaque, just mark it unlayered if necessary. */ + if (style & WS_EX_LAYERED) { + if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) { + return WIN_SetError("SetWindowLong()"); + } + } + } else { + const BYTE alpha = (BYTE) ((int) (opacity * 255.0f)); + /* want it transparent, mark it layered if necessary. */ + if ((style & WS_EX_LAYERED) == 0) { + if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) { + return WIN_SetError("SetWindowLong()"); + } + } + + if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) { + return WIN_SetError("SetLayeredWindowAttributes()"); + } + } + + return 0; +} + #endif /* SDL_VIDEO_DRIVER_WINDOWS */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.h b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.h index f91aa0ed2..7d50ba66e 100644 --- a/Engine/lib/sdl/src/video/windows/SDL_windowswindow.h +++ b/Engine/lib/sdl/src/video/windows/SDL_windowswindow.h @@ -41,7 +41,7 @@ typedef struct SDL_bool expected_resize; SDL_bool in_border_change; SDL_bool in_title_click; - SDL_bool focus_click_pending; + Uint8 focus_click_pending; SDL_bool windowed_mode_was_maximized; SDL_bool in_window_deactivation; struct SDL_VideoData *videodata; @@ -56,6 +56,7 @@ extern void WIN_SetWindowTitle(_THIS, SDL_Window * window); extern void WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon); extern void WIN_SetWindowPosition(_THIS, SDL_Window * window); extern void WIN_SetWindowSize(_THIS, SDL_Window * window); +extern int WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity); extern void WIN_ShowWindow(_THIS, SDL_Window * window); extern void WIN_HideWindow(_THIS, SDL_Window * window); extern void WIN_RaiseWindow(_THIS, SDL_Window * window); @@ -63,6 +64,7 @@ extern void WIN_MaximizeWindow(_THIS, SDL_Window * window); extern void WIN_MinimizeWindow(_THIS, SDL_Window * window); extern void WIN_RestoreWindow(_THIS, SDL_Window * window); extern void WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); +extern void WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable); extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp); diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtevents.cpp b/Engine/lib/sdl/src/video/winrt/SDL_winrtevents.cpp index e9df726d4..30cf01633 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtevents.cpp +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtevents.cpp @@ -40,6 +40,7 @@ using Windows::UI::Core::CoreCursor; #include "SDL_system.h" extern "C" { +#include "../../thread/SDL_systhread.h" #include "../SDL_sysvideo.h" #include "../../events/SDL_events_c.h" } @@ -113,7 +114,7 @@ WINRT_CycleXAMLThread() _mutex = SDL_CreateMutex(); _threadState = ThreadState_Running; - _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr); + _XAMLThread = SDL_CreateThreadInternal(WINRT_XAMLThreadMain, "SDL/XAML App Thread", 0, nullptr); SDL_LockMutex(_mutex); while (_threadState != ThreadState_Yielding) { diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtevents_c.h b/Engine/lib/sdl/src/video/winrt/SDL_winrtevents_c.h index dc94526bb..05a90a3bf 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtevents_c.h +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtevents_c.h @@ -67,6 +67,13 @@ 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); +#if NTDDI_VERSION >= NTDDI_WIN10 +extern SDL_bool WINRT_HasScreenKeyboardSupport(_THIS); +extern void WINRT_ShowScreenKeyboard(_THIS, SDL_Window *window); +extern void WINRT_HideScreenKeyboard(_THIS, SDL_Window *window); +extern SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window); +#endif // NTDDI_VERSION >= ... + /* XAML Thread Management */ extern void WINRT_CycleXAMLThread(); diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar.cpp b/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar.cpp new file mode 100644 index 000000000..215dfcc83 --- /dev/null +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar.cpp @@ -0,0 +1,196 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_WINRT + +/* Windows includes */ +#include +#include +#include + + +/* SDL includes */ +extern "C" { +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +} +#include "SDL_winrtvideo_cpp.h" + + +/* Game Bar events can come in off the main thread. Use the following + WinRT CoreDispatcher to deal with them on SDL's thread. +*/ +static Platform::WeakReference WINRT_MainThreadDispatcher; + + +/* Win10's initial SDK (the 10.0.10240.0 release) does not include references + to Game Bar APIs, as the Game Bar was released via Win10 10.0.10586.0. + + Declare its WinRT/COM interface here, to allow compilation with earlier + Windows SDKs. +*/ +MIDL_INTERFACE("1DB9A292-CC78-4173-BE45-B61E67283EA7") +IGameBarStatics_ : public IInspectable +{ +public: + virtual HRESULT STDMETHODCALLTYPE add_VisibilityChanged( + __FIEventHandler_1_IInspectable *handler, + Windows::Foundation::EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_VisibilityChanged( + Windows::Foundation::EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE add_IsInputRedirectedChanged( + __FIEventHandler_1_IInspectable *handler, + Windows::Foundation::EventRegistrationToken *token) = 0; + + virtual HRESULT STDMETHODCALLTYPE remove_IsInputRedirectedChanged( + Windows::Foundation::EventRegistrationToken token) = 0; + + virtual HRESULT STDMETHODCALLTYPE get_Visible( + boolean *value) = 0; + + virtual HRESULT STDMETHODCALLTYPE get_IsInputRedirected( + boolean *value) = 0; +}; + +/* Declare the game bar's COM GUID */ +static GUID IID_IGameBarStatics_ = { MAKELONG(0xA292, 0x1DB9), 0xCC78, 0x4173, { 0xBE, 0x45, 0xB6, 0x1E, 0x67, 0x28, 0x3E, 0xA7 } }; + +/* Retrieves a pointer to the game bar, or NULL if it is not available. + If a pointer is returned, it's ->Release() method must be called + after the caller has finished using it. +*/ +static IGameBarStatics_ * +WINRT_GetGameBar() +{ + wchar_t *wClassName = L"Windows.Gaming.UI.GameBar"; + HSTRING hClassName; + IActivationFactory *pActivationFactory = NULL; + IGameBarStatics_ *pGameBar = NULL; + HRESULT hr; + + hr = ::WindowsCreateString(wClassName, (UINT32)wcslen(wClassName), &hClassName); + if (FAILED(hr)) { + goto done; + } + + hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory); + if (FAILED(hr)) { + goto done; + } + + pActivationFactory->QueryInterface(IID_IGameBarStatics_, (void **) &pGameBar); + +done: + if (pActivationFactory) { + pActivationFactory->Release(); + } + if (hClassName) { + ::WindowsDeleteString(hClassName); + } + return pGameBar; +} + +static void +WINRT_HandleGameBarIsInputRedirected_MainThread() +{ + IGameBarStatics_ *gameBar; + boolean isInputRedirected = 0; + if (!WINRT_MainThreadDispatcher) { + /* The game bar event handler has been deregistered! */ + return; + } + gameBar = WINRT_GetGameBar(); + if (!gameBar) { + /* Shouldn't happen, but just in case... */ + return; + } + if (SUCCEEDED(gameBar->get_IsInputRedirected(&isInputRedirected))) { + if ( ! isInputRedirected) { + /* Input-control is now back to the SDL app. Restore the cursor, + in case Windows does not (it does not in either Win10 + 10.0.10240.0 or 10.0.10586.0, maybe later version(s) too. + */ + SDL_Cursor *cursor = SDL_GetCursor(); + SDL_SetCursor(cursor); + } + } + gameBar->Release(); +} + +static void +WINRT_HandleGameBarIsInputRedirected_NonMainThread(Platform::Object ^ o1, Platform::Object ^o2) +{ + Windows::UI::Core::CoreDispatcher ^dispatcher = WINRT_MainThreadDispatcher.Resolve(); + if (dispatcher) { + dispatcher->RunAsync( + Windows::UI::Core::CoreDispatcherPriority::Normal, + ref new Windows::UI::Core::DispatchedHandler(&WINRT_HandleGameBarIsInputRedirected_MainThread)); + } +} + +void +WINRT_InitGameBar(_THIS) +{ + SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata; + IGameBarStatics_ *gameBar = WINRT_GetGameBar(); + if (gameBar) { + /* GameBar.IsInputRedirected events can come in via something other than + the main/SDL thread. + + Get a WinRT 'CoreDispatcher' that can be used to call back into the + SDL thread. + */ + WINRT_MainThreadDispatcher = Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher; + Windows::Foundation::EventHandler ^handler = \ + ref new Windows::Foundation::EventHandler(&WINRT_HandleGameBarIsInputRedirected_NonMainThread); + __FIEventHandler_1_IInspectable * pHandler = reinterpret_cast<__FIEventHandler_1_IInspectable *>(handler); + gameBar->add_IsInputRedirectedChanged(pHandler, &driverdata->gameBarIsInputRedirectedToken); + gameBar->Release(); + } +} + +void +WINRT_QuitGameBar(_THIS) +{ + SDL_VideoData *driverdata; + IGameBarStatics_ *gameBar; + if (!_this || !_this->driverdata) { + return; + } + gameBar = WINRT_GetGameBar(); + if (!gameBar) { + return; + } + driverdata = (SDL_VideoData *)_this->driverdata; + if (driverdata->gameBarIsInputRedirectedToken.Value) { + gameBar->remove_IsInputRedirectedChanged(driverdata->gameBarIsInputRedirectedToken); + driverdata->gameBarIsInputRedirectedToken.Value = 0; + } + WINRT_MainThreadDispatcher = nullptr; + gameBar->Release(); +} + +#endif /* SDL_VIDEO_DRIVER_WINRT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar_cpp.h b/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar_cpp.h new file mode 100644 index 000000000..afcef37b2 --- /dev/null +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtgamebar_cpp.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifndef _SDL_winrtgamebar_h +#define _SDL_winrtgamebar_h + +#ifdef __cplusplus +/* These are exported as C++ functions, rather than C, to fix a compilation + bug with MSVC 2013, for Windows 8.x builds. */ +extern void WINRT_InitGameBar(_THIS); +extern void WINRT_QuitGameBar(_THIS); +#endif + +#endif /* _SDL_winrtmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtkeyboard.cpp b/Engine/lib/sdl/src/video/winrt/SDL_winrtkeyboard.cpp index 7477cdeeb..affcae62b 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtkeyboard.cpp +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtkeyboard.cpp @@ -383,4 +383,48 @@ WINRT_ProcessCharacterReceivedEvent(Windows::UI::Core::CharacterReceivedEventArg } } + +#if NTDDI_VERSION >= NTDDI_WIN10 + +SDL_bool WINRT_HasScreenKeyboardSupport(_THIS) +{ + return SDL_TRUE; +} + +void WINRT_ShowScreenKeyboard(_THIS, SDL_Window *window) +{ + using namespace Windows::UI::ViewManagement; + InputPane ^ inputPane = InputPane::GetForCurrentView(); + if (inputPane) { + inputPane->TryShow(); + } +} + +void WINRT_HideScreenKeyboard(_THIS, SDL_Window *window) +{ + using namespace Windows::UI::ViewManagement; + InputPane ^ inputPane = InputPane::GetForCurrentView(); + if (inputPane) { + inputPane->TryHide(); + } +} + +SDL_bool WINRT_IsScreenKeyboardShown(_THIS, SDL_Window *window) +{ + using namespace Windows::UI::ViewManagement; + InputPane ^ inputPane = InputPane::GetForCurrentView(); + if (inputPane) { + // dludwig@pobox.com: checking inputPane->Visible doesn't seem to detect visibility, + // at least not on the Windows Phone 10.0.10240.0 emulator. Checking + // the size of inputPane->OccludedRect, however, does seem to work. + Windows::Foundation::Rect rect = inputPane->OccludedRect; + if (rect.Width > 0 && rect.Height > 0) { + return SDL_TRUE; + } + } + return SDL_FALSE; +} + +#endif // NTDDI_VERSION >= ... + #endif // SDL_VIDEO_DRIVER_WINRT diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtmouse.cpp b/Engine/lib/sdl/src/video/winrt/SDL_winrtmouse.cpp index d3140a4a4..9997d6ea4 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtmouse.cpp +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtmouse.cpp @@ -26,6 +26,7 @@ * Windows includes: */ #include +#include using namespace Windows::UI::Core; using Windows::UI::Core::CoreCursor; @@ -116,11 +117,69 @@ WINRT_ShowCursor(SDL_Cursor * cursor) return 0; } + CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread(); if (cursor) { CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; - CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor; + coreWindow->PointerCursor = *theCursor; } else { - CoreWindow::GetForCurrentThread()->PointerCursor = nullptr; + // HACK ALERT: TL;DR - Hiding the cursor in WinRT/UWP apps is weird, and + // a Win32-style cursor resource file must be directly included in apps, + // otherwise hiding the cursor will cause mouse-motion data to never be + // received. + // + // Here's the lengthy explanation: + // + // There are two ways to hide a cursor in WinRT/UWP apps. + // Both involve setting the WinRT CoreWindow's (which is somewhat analogous + // to a Win32 HWND) 'PointerCursor' property. + // + // The first way to hide a cursor sets PointerCursor to nullptr. This + // is, arguably, the easiest to implement for an app. It does have an + // unfortunate side-effect: it'll prevent mouse-motion events from being + // sent to the app (via CoreWindow). + // + // The second way to hide a cursor sets PointerCursor to a transparent + // cursor. This allows mouse-motion events to be sent to the app, but is + // more difficult to set up, as: + // 1. WinRT/UWP, while providing a few stock cursors, does not provide + // a completely transparent cursor. + // 2. WinRT/UWP allows apps to provide custom-built cursors, but *ONLY* + // if they are linked directly inside the app, via Win32-style + // cursor resource files. APIs to create cursors at runtime are + // not provided to apps, and attempting to link-to or use Win32 + // cursor-creation APIs could cause an app to fail Windows Store + // certification. + // + // SDL can use either means of hiding the cursor. It provides a Win32-style + // set of cursor resource files in its source distribution, inside + // src/main/winrt/. If those files are linked to an SDL-for-WinRT/UWP app + // (by including them in a MSVC project, for example), SDL will attempt to + // use those, if and when the cursor is hidden via SDL APIs. If those + // files are not linked in, SDL will attempt to hide the cursor via the + // 'set PointerCursor to nullptr' means (which, if you recall, causes + // mouse-motion data to NOT be sent to the app!). + // + // Tech notes: + // - SDL's blank cursor resource uses a resource ID of 5000. + // - SDL's cursor resources consist of the following two files: + // - src/main/winrt/SDL2-WinRTResource_BlankCursor.cur -- cursor pixel data + // - src/main/winrt/SDL2-WinRTResources.rc -- declares the cursor resource, and its ID (of 5000) + // + + const unsigned int win32CursorResourceID = 5000; + CoreCursor ^ blankCursor = ref new CoreCursor(CoreCursorType::Custom, win32CursorResourceID); + + // Set 'PointerCursor' to 'blankCursor' in a way that shouldn't throw + // an exception if the app hasn't loaded that resource. + ABI::Windows::UI::Core::ICoreCursor * iblankCursor = reinterpret_cast(blankCursor); + ABI::Windows::UI::Core::ICoreWindow * icoreWindow = reinterpret_cast(coreWindow); + HRESULT hr = icoreWindow->put_PointerCursor(iblankCursor); + if (FAILED(hr)) { + // The app doesn't contain the cursor resource, or some other error + // occurred. Just use the other, but mouse-motion-preventing, means of + // hiding the cursor. + coreWindow->PointerCursor = nullptr; + } } return 0; } diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo.cpp b/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo.cpp index 9d7c1ccee..9a26705ad 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo.cpp +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo.cpp @@ -31,6 +31,7 @@ /* Windows includes */ #include #include +#include #include #include using namespace Windows::ApplicationModel::Core; @@ -41,7 +42,8 @@ using namespace Windows::UI::ViewManagement; /* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */ -static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48,{ 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; +static const GUID IID_IDisplayRequest = { 0xe5732044, 0xf49f, 0x4b60, { 0x8d, 0xd4, 0x5e, 0x7e, 0x3a, 0x63, 0x2a, 0xc0 } }; +static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; /* SDL includes */ @@ -61,6 +63,7 @@ extern "C" { #include "../../core/winrt/SDL_winrtapp_xaml.h" #include "SDL_winrtvideo_cpp.h" #include "SDL_winrtevents_c.h" +#include "SDL_winrtgamebar_cpp.h" #include "SDL_winrtmouse_c.h" #include "SDL_main.h" #include "SDL_system.h" @@ -82,6 +85,11 @@ static void WINRT_DestroyWindow(_THIS, SDL_Window * window); static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); +/* Misc functions */ +static ABI::Windows::System::Display::IDisplayRequest * WINRT_CreateDisplayRequest(_THIS); +extern void WINRT_SuspendScreenSaver(_THIS); + + /* SDL-internal globals: */ SDL_Window * WINRT_GlobalSDLWindow = NULL; @@ -118,18 +126,15 @@ WINRT_CreateDevice(int devindex) device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); if (!device) { SDL_OutOfMemory(); - if (device) { - SDL_free(device); - } return (0); } data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); if (!data) { SDL_OutOfMemory(); + SDL_free(device); return (0); } - SDL_zerop(data); device->driverdata = data; /* Set the function pointers */ @@ -142,6 +147,15 @@ WINRT_CreateDevice(int devindex) device->SetDisplayMode = WINRT_SetDisplayMode; device->PumpEvents = WINRT_PumpEvents; device->GetWindowWMInfo = WINRT_GetWindowWMInfo; + device->SuspendScreenSaver = WINRT_SuspendScreenSaver; + +#if NTDDI_VERSION >= NTDDI_WIN10 + device->HasScreenKeyboardSupport = WINRT_HasScreenKeyboardSupport; + device->ShowScreenKeyboard = WINRT_ShowScreenKeyboard; + device->HideScreenKeyboard = WINRT_HideScreenKeyboard; + device->IsScreenKeyboardShown = WINRT_IsScreenKeyboardShown; +#endif + #ifdef SDL_VIDEO_OPENGL_EGL device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; @@ -167,12 +181,17 @@ VideoBootStrap WINRT_bootstrap = { int WINRT_VideoInit(_THIS) { + SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata; if (WINRT_InitModes(_this) < 0) { return -1; } WINRT_InitMouse(_this); WINRT_InitTouch(_this); - + WINRT_InitGameBar(_this); + if (driverdata) { + /* Initialize screensaver-disabling support */ + driverdata->displayRequest = WINRT_CreateDisplayRequest(_this); + } return 0; } @@ -414,6 +433,12 @@ WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) void WINRT_VideoQuit(_THIS) { + SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata; + if (driverdata && driverdata->displayRequest) { + driverdata->displayRequest->Release(); + driverdata->displayRequest = NULL; + } + WINRT_QuitGameBar(_this); WINRT_QuitMouse(_this); } @@ -483,7 +508,7 @@ WINRT_DetectWindowFlags(SDL_Window * window) // data->coreWindow->PointerPosition is not supported on WinPhone 8.0 latestFlags |= SDL_WINDOW_MOUSE_FOCUS; #else - if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) { + if (data->coreWindow->Visible && data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) { latestFlags |= SDL_WINDOW_MOUSE_FOCUS; } #endif @@ -753,6 +778,65 @@ WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) return SDL_FALSE; } +static ABI::Windows::System::Display::IDisplayRequest * +WINRT_CreateDisplayRequest(_THIS) +{ + /* Setup a WinRT DisplayRequest object, usable for enabling/disabling screensaver requests */ + wchar_t *wClassName = L"Windows.System.Display.DisplayRequest"; + HSTRING hClassName; + IActivationFactory *pActivationFactory = NULL; + IInspectable * pDisplayRequestRaw = nullptr; + ABI::Windows::System::Display::IDisplayRequest * pDisplayRequest = nullptr; + HRESULT hr; + + hr = ::WindowsCreateString(wClassName, (UINT32)wcslen(wClassName), &hClassName); + if (FAILED(hr)) { + goto done; + } + + hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory); + if (FAILED(hr)) { + goto done; + } + + hr = pActivationFactory->ActivateInstance(&pDisplayRequestRaw); + if (FAILED(hr)) { + goto done; + } + + hr = pDisplayRequestRaw->QueryInterface(IID_IDisplayRequest, (void **) &pDisplayRequest); + if (FAILED(hr)) { + goto done; + } + +done: + if (pDisplayRequestRaw) { + pDisplayRequestRaw->Release(); + } + if (pActivationFactory) { + pActivationFactory->Release(); + } + if (hClassName) { + ::WindowsDeleteString(hClassName); + } + + return pDisplayRequest; +} + +void +WINRT_SuspendScreenSaver(_THIS) +{ + SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata; + if (driverdata && driverdata->displayRequest) { + ABI::Windows::System::Display::IDisplayRequest * displayRequest = (ABI::Windows::System::Display::IDisplayRequest *) driverdata->displayRequest; + if (_this->suspend_screensaver) { + displayRequest->RequestActive(); + } else { + displayRequest->RequestRelease(); + } + } +} + #endif /* SDL_VIDEO_DRIVER_WINRT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo_cpp.h b/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo_cpp.h index 26eb008d4..7d5ce13e0 100644 --- a/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/Engine/lib/sdl/src/video/winrt/SDL_winrtvideo_cpp.h @@ -46,6 +46,17 @@ typedef struct SDL_VideoData { * passed to eglGetDisplay and eglCreateWindowSurface: */ IUnknown *winrtEglWindow; + + /* Event token(s), for unregistering WinRT event handler(s). + These are just a struct with a 64-bit integer inside them + */ + Windows::Foundation::EventRegistrationToken gameBarIsInputRedirectedToken; + + /* A WinRT DisplayRequest, used for implementing SDL_*ScreenSaver() functions. + * This is really a pointer to a 'ABI::Windows::System::Display::IDisplayRequest *', + * It's casted to 'IUnknown *', to help with building SDL. + */ + IUnknown *displayRequest; } SDL_VideoData; /* The global, WinRT, SDL Window. diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11dyn.c b/Engine/lib/sdl/src/video/x11/SDL_x11dyn.c index 7cbfa3e97..d07fda740 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11dyn.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11dyn.c @@ -106,11 +106,8 @@ X11_GetSym(const char *fnname, int *pHasModule) #endif /* SDL_VIDEO_DRIVER_X11_DYNAMIC */ /* Define all the function pointers and wrappers... */ -#define SDL_X11_MODULE(modname) #define SDL_X11_SYM(rc,fn,params,args,ret) SDL_DYNX11FN_##fn X11_##fn = NULL; #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM /* Annoying varargs entry point... */ #ifdef X_HAVE_UTF8_STRING @@ -120,10 +117,7 @@ SDL_DYNX11FN_XGetICValues X11_XGetICValues = NULL; /* These SDL_X11_HAVE_* flags are here whether you have dynamic X11 or not. */ #define SDL_X11_MODULE(modname) int SDL_X11_HAVE_##modname = 0; -#define SDL_X11_SYM(rc,fn,params,args,ret) #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM static int x11_load_refcount = 0; @@ -139,8 +133,6 @@ SDL_X11_UnloadSymbols(void) #define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 0; #define SDL_X11_SYM(rc,fn,params,args,ret) X11_##fn = NULL; #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM #ifdef X_HAVE_UTF8_STRING X11_XCreateIC = NULL; @@ -177,16 +169,11 @@ SDL_X11_LoadSymbols(void) } #define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 1; /* default yes */ -#define SDL_X11_SYM(a,fn,x,y,z) #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM #define SDL_X11_MODULE(modname) thismod = &SDL_X11_HAVE_##modname; #define SDL_X11_SYM(a,fn,x,y,z) X11_##fn = (SDL_DYNX11FN_##fn) X11_GetSym(#fn,thismod); #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM #ifdef X_HAVE_UTF8_STRING X11_XCreateIC = (SDL_DYNX11FN_XCreateIC) @@ -209,8 +196,6 @@ SDL_X11_LoadSymbols(void) #define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 1; /* default yes */ #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 #ifdef X_HAVE_UTF8_STRING X11_XCreateIC = XCreateIC; diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11dyn.h b/Engine/lib/sdl/src/video/x11/SDL_x11dyn.h index 136609b85..be1ddaa1c 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11dyn.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11dyn.h @@ -86,13 +86,10 @@ int SDL_X11_LoadSymbols(void); void SDL_X11_UnloadSymbols(void); /* Declare all the function pointers and wrappers... */ -#define SDL_X11_MODULE(modname) #define SDL_X11_SYM(rc,fn,params,args,ret) \ typedef rc (*SDL_DYNX11FN_##fn) params; \ extern SDL_DYNX11FN_##fn X11_##fn; #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM /* Annoying varargs entry point... */ #ifdef X_HAVE_UTF8_STRING @@ -104,10 +101,7 @@ extern SDL_DYNX11FN_XGetICValues X11_XGetICValues; /* These SDL_X11_HAVE_* flags are here whether you have dynamic X11 or not. */ #define SDL_X11_MODULE(modname) extern int SDL_X11_HAVE_##modname; -#define SDL_X11_SYM(rc,fn,params,args,ret) #include "SDL_x11sym.h" -#undef SDL_X11_MODULE -#undef SDL_X11_SYM #ifdef __cplusplus } diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11events.c b/Engine/lib/sdl/src/video/x11/SDL_x11events.c index 208009607..56d2368a0 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11events.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11events.c @@ -35,6 +35,7 @@ #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h" +#include "SDL_hints.h" #include "SDL_timer.h" #include "SDL_syswm.h" @@ -117,7 +118,9 @@ static Atom X11_PickTarget(Display *disp, Atom list[], int list_count) int i; for (i=0; i < list_count && request == None; i++) { name = X11_XGetAtomName(disp, list[i]); - if (strcmp("text/uri-list", name)==0) request = list[i]; + if ((SDL_strcmp("text/uri-list", name) == 0) || (SDL_strcmp("text/plain", name) == 0)) { + request = list[i]; + } X11_XFree(name); } return request; @@ -377,8 +380,8 @@ X11_DispatchFocusIn(_THIS, SDL_WindowData *data) X11_XSetICFocus(data->ic); } #endif -#ifdef SDL_USE_IBUS - SDL_IBus_SetFocus(SDL_TRUE); +#ifdef SDL_USE_IME + SDL_IME_SetFocus(SDL_TRUE); #endif } @@ -400,8 +403,8 @@ X11_DispatchFocusOut(_THIS, SDL_WindowData *data) X11_XUnsetICFocus(data->ic); } #endif -#ifdef SDL_USE_IBUS - SDL_IBus_SetFocus(SDL_FALSE); +#ifdef SDL_USE_IME + SDL_IME_SetFocus(SDL_FALSE); #endif } @@ -512,11 +515,28 @@ ProcessHitTest(_THIS, const SDL_WindowData *data, const XEvent *xev) return SDL_FALSE; } +static void +X11_UpdateUserTime(SDL_WindowData *data, const unsigned long latest) +{ + if (latest && (latest != data->user_time)) { + SDL_VideoData *videodata = data->videodata; + Display *display = videodata->display; + X11_XChangeProperty(display, data->xwindow, videodata->_NET_WM_USER_TIME, + XA_CARDINAL, 32, PropModeReplace, + (const unsigned char *) &latest, 1); +#ifdef DEBUG_XEVENTS + printf("window %p: updating _NET_WM_USER_TIME to %lu\n", data, latest); +#endif + data->user_time = latest; + } +} + + static void X11_DispatchEvent(_THIS) { SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; - Display *display = videodata->display; + Display *display; SDL_WindowData *data; XEvent xevent; int orig_event_type; @@ -524,6 +544,11 @@ X11_DispatchEvent(_THIS) XClientMessageEvent m; int i; + if (!videodata) { + return; + } + display = videodata->display; + SDL_zero(xevent); /* valgrind fix. --ryan. */ X11_XNextEvent(display, &xevent); @@ -545,15 +570,12 @@ X11_DispatchEvent(_THIS) #endif if (orig_keycode) { /* Make sure dead key press/release events are sent */ - /* Actually, don't do this because it causes double-delivery - of some keys on Ubuntu 14.04 (bug 2526) SDL_Scancode scancode = videodata->key_layout[orig_keycode]; if (orig_event_type == KeyPress) { SDL_SendKeyboardKey(SDL_PRESSED, scancode); } else { SDL_SendKeyboardKey(SDL_RELEASED, scancode); } - */ } return; } @@ -617,6 +639,7 @@ X11_DispatchEvent(_THIS) /* Gaining mouse coverage? */ case EnterNotify:{ + SDL_Mouse *mouse = SDL_GetMouse(); #ifdef DEBUG_XEVENTS printf("window %p: EnterNotify! (%d,%d,%d)\n", data, xevent.xcrossing.x, @@ -629,7 +652,10 @@ X11_DispatchEvent(_THIS) #endif SDL_SetMouseFocus(data->window); - if (!SDL_GetMouse()->relative_mode) { + mouse->last_x = xevent.xcrossing.x; + mouse->last_y = xevent.xcrossing.y; + + if (!mouse->relative_mode) { SDL_SendMouseMotion(data->window, 0, 0, xevent.xcrossing.x, xevent.xcrossing.y); } } @@ -688,6 +714,7 @@ X11_DispatchEvent(_THIS) data->pending_focus = PENDING_FOCUS_IN; data->pending_focus_time = SDL_GetTicks() + PENDING_FOCUS_TIME; } + data->last_focus_event_time = SDL_GetTicks(); } break; @@ -739,11 +766,7 @@ X11_DispatchEvent(_THIS) if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { int min_keycode, max_keycode; X11_XDisplayKeycodes(display, &min_keycode, &max_keycode); -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); -#else - keysym = X11_XKeycodeToKeysym(display, keycode, 0); -#endif + keysym = X11_KeyCodeToSym(_this, keycode, xevent.xkey.state >> 13); 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", keycode, keycode - min_keycode, keysym, @@ -756,14 +779,16 @@ X11_DispatchEvent(_THIS) if (data->ic) { X11_Xutf8LookupString(data->ic, &xevent.xkey, text, sizeof(text), &keysym, &status); + } else { + X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); } #else X11_XLookupString(&xevent.xkey, text, sizeof(text), &keysym, NULL); #endif -#ifdef SDL_USE_IBUS +#ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - handled_by_ime = SDL_IBus_ProcessKeyEvent(keysym, keycode); + handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode); } #endif if (!handled_by_ime) { @@ -773,6 +798,7 @@ X11_DispatchEvent(_THIS) } } + X11_UpdateUserTime(data, xevent.xkey.time); } break; @@ -816,36 +842,28 @@ X11_DispatchEvent(_THIS) xevent.xconfigure.x, xevent.xconfigure.y, xevent.xconfigure.width, xevent.xconfigure.height); #endif - long border_left = 0; - long border_top = 0; - if (data->xwindow) { - Atom _net_frame_extents = X11_XInternAtom(display, "_NET_FRAME_EXTENTS", 0); - Atom type; - int format; - unsigned long nitems, bytes_after; - unsigned char *property; - if (X11_XGetWindowProperty(display, data->xwindow, - _net_frame_extents, 0, 16, 0, - XA_CARDINAL, &type, &format, - &nitems, &bytes_after, &property) == Success) { - if (type != None && nitems == 4) - { - border_left = ((long*)property)[0]; - border_top = ((long*)property)[2]; - } - X11_XFree(property); - } + /* Real configure notify events are relative to the parent, synthetic events are absolute. */ + if (!xevent.xconfigure.send_event) { + unsigned int NumChildren; + Window ChildReturn, Root, Parent; + Window * Children; + /* Translate these coodinates back to relative to root */ + X11_XQueryTree(data->videodata->display, xevent.xconfigure.window, &Root, &Parent, &Children, &NumChildren); + X11_XTranslateCoordinates(xevent.xconfigure.display, + Parent, DefaultRootWindow(xevent.xconfigure.display), + xevent.xconfigure.x, xevent.xconfigure.y, + &xevent.xconfigure.x, &xevent.xconfigure.y, + &ChildReturn); } - + if (xevent.xconfigure.x != data->last_xconfigure.x || xevent.xconfigure.y != data->last_xconfigure.y) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, - xevent.xconfigure.x - border_left, - xevent.xconfigure.y - border_top); -#ifdef SDL_USE_IBUS + xevent.xconfigure.x, xevent.xconfigure.y); +#ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - /* Update IBus candidate list position */ - SDL_IBus_UpdateTextRect(NULL); + /* Update IME candidate list position */ + SDL_IME_UpdateTextRect(NULL); } #endif } @@ -959,6 +977,16 @@ X11_DispatchEvent(_THIS) SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0); break; } + else if ((xevent.xclient.message_type == videodata->WM_PROTOCOLS) && + (xevent.xclient.format == 32) && + (xevent.xclient.data.l[0] == videodata->WM_TAKE_FOCUS)) { + +#ifdef DEBUG_XEVENTS + printf("window %p: WM_TAKE_FOCUS\n", data); +#endif + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_TAKE_FOCUS, 0, 0); + break; + } } break; @@ -975,7 +1003,7 @@ X11_DispatchEvent(_THIS) SDL_Mouse *mouse = SDL_GetMouse(); if(!mouse->relative_mode || mouse->relative_mode_warp) { #ifdef DEBUG_MOTION - printf("window %p: X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); + printf("window %p: X11 motion: %d,%d\n", data, xevent.xmotion.x, xevent.xmotion.y); #endif SDL_SendMouseMotion(data->window, 0, 0, xevent.xmotion.x, xevent.xmotion.y); @@ -985,12 +1013,17 @@ X11_DispatchEvent(_THIS) case ButtonPress:{ int xticks = 0, yticks = 0; +#ifdef DEBUG_XEVENTS + printf("window %p: ButtonPress (X11 button = %d)\n", data, xevent.xbutton.button); +#endif if (X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) { SDL_SendMouseWheel(data->window, 0, xticks, yticks, SDL_MOUSEWHEEL_NORMAL); } else { + SDL_bool ignore_click = SDL_FALSE; int button = xevent.xbutton.button; if(button == Button1) { if (ProcessHitTest(_this, data, &xevent)) { + SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); break; /* don't pass this event on to app. */ } } @@ -999,8 +1032,18 @@ X11_DispatchEvent(_THIS) => subtract (8-SDL_BUTTON_X1) to get value SDL expects */ button -= (8-SDL_BUTTON_X1); } - SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button); + if (data->last_focus_event_time) { + const int X11_FOCUS_CLICK_TIMEOUT = 10; + if (!SDL_TICKS_PASSED(SDL_GetTicks(), data->last_focus_event_time + X11_FOCUS_CLICK_TIMEOUT)) { + ignore_click = !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE); + } + data->last_focus_event_time = 0; + } + if (!ignore_click) { + SDL_SendMouseButton(data->window, 0, SDL_PRESSED, button); + } } + X11_UpdateUserTime(data, xevent.xbutton.time); } break; @@ -1008,7 +1051,10 @@ X11_DispatchEvent(_THIS) int button = xevent.xbutton.button; /* The X server sends a Release event for each Press for wheels. Ignore them. */ int xticks = 0, yticks = 0; - if (!X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) { +#ifdef DEBUG_XEVENTS + printf("window %p: ButtonRelease (X11 button = %d)\n", data, xevent.xbutton.button); +#endif + if (!X11_IsWheelEvent(display, &xevent, &xticks, &yticks)) { if (button > 7) { /* see explanation at case ButtonPress */ button -= (8-SDL_BUTTON_X1); @@ -1027,7 +1073,7 @@ X11_DispatchEvent(_THIS) char *name = X11_XGetAtomName(display, xevent.xproperty.atom); if (name) { - printf("window %p: PropertyNotify: %s %s\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed"); + printf("window %p: PropertyNotify: %s %s time=%lu\n", data, name, (xevent.xproperty.state == PropertyDelete) ? "deleted" : "changed", xevent.xproperty.time); X11_XFree(name); } @@ -1095,6 +1141,17 @@ X11_DispatchEvent(_THIS) } #endif /* DEBUG_XEVENTS */ + /* Take advantage of this moment to make sure user_time has a + valid timestamp from the X server, so if we later try to + raise/restore this window, _NET_ACTIVE_WINDOW can have a + non-zero timestamp, even if there's never been a mouse or + key press to this window so far. Note that we don't try to + set _NET_WM_USER_TIME here, though. That's only for legit + user interaction with the window. */ + if (!data->user_time) { + data->user_time = xevent.xproperty.time; + } + if (xevent.xproperty.atom == data->videodata->_NET_WM_STATE) { /* Get the new state from the window manager. Compositing window managers can alter visibility of windows @@ -1128,6 +1185,24 @@ X11_DispatchEvent(_THIS) right approach, but it seems to work. */ X11_UpdateKeymap(_this); SDL_SendKeymapChangedEvent(); + } else if (xevent.xproperty.atom == videodata->_NET_FRAME_EXTENTS) { + Atom type; + int format; + unsigned long nitems, bytes_after; + unsigned char *property; + if (X11_XGetWindowProperty(display, data->xwindow, videodata->_NET_FRAME_EXTENTS, 0, 16, 0, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &property) == Success) { + if (type != None && nitems == 4) { + data->border_left = (int) ((long*)property)[0]; + data->border_right = (int) ((long*)property)[1]; + data->border_top = (int) ((long*)property)[2]; + data->border_bottom = (int) ((long*)property)[3]; + } + X11_XFree(property); + + #ifdef DEBUG_XEVENTS + printf("New _NET_FRAME_EXTENTS: left=%d right=%d, top=%d, bottom=%d\n", data->border_left, data->border_right, data->border_top, data->border_bottom); + #endif + } } } break; @@ -1182,51 +1257,33 @@ X11_DispatchEvent(_THIS) break; case SelectionNotify: { + Atom target = xevent.xselection.target; #ifdef DEBUG_XEVENTS printf("window %p: SelectionNotify (requestor = %ld, target = %ld)\n", data, xevent.xselection.requestor, xevent.xselection.target); #endif - Atom target = xevent.xselection.target; if (target == data->xdnd_req) { /* read data */ SDL_x11Prop p; X11_ReadProperty(&p, display, data->xwindow, videodata->PRIMARY); if (p.format == 8) { - SDL_bool expect_lf = SDL_FALSE; - char *start = NULL; - char *scan = (char*)p.data; - char *fn; - char *uri; - int length = 0; - while (p.count--) { - if (!expect_lf) { - if (*scan == 0x0D) { - expect_lf = SDL_TRUE; + /* !!! FIXME: don't use strtok here. It's not reentrant and not in SDL_stdinc. */ + char* name = X11_XGetAtomName(display, target); + char *token = strtok((char *) p.data, "\r\n"); + while (token != NULL) { + if (SDL_strcmp("text/plain", name)==0) { + SDL_SendDropText(data->window, token); + } else if (SDL_strcmp("text/uri-list", name)==0) { + char *fn = X11_URIToLocal(token); + if (fn) { + SDL_SendDropFile(data->window, fn); } - if (start == NULL) { - start = scan; - length = 0; - } - length++; - } else { - if (*scan == 0x0A && length > 0) { - uri = SDL_malloc(length--); - SDL_memcpy(uri, start, length); - uri[length] = '\0'; - fn = X11_URIToLocal(uri); - if (fn) { - SDL_SendDropFile(fn); - } - SDL_free(uri); - } - expect_lf = SDL_FALSE; - start = NULL; } - scan++; + token = strtok(NULL, "\r\n"); } + SDL_SendDropComplete(data->window); } - X11_XFree(p.data); /* send reply */ @@ -1350,9 +1407,9 @@ X11_PumpEvents(_THIS) X11_DispatchEvent(_this); } -#ifdef SDL_USE_IBUS +#ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - SDL_IBus_PumpEvents(); + SDL_IME_PumpEvents(); } #endif diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c index 2c3acdadd..b888bff35 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.c @@ -129,9 +129,21 @@ static const struct { { XK_Control_R, SDL_SCANCODE_RCTRL }, { XK_Shift_R, SDL_SCANCODE_RSHIFT }, { XK_Alt_R, SDL_SCANCODE_RALT }, + { XK_ISO_Level3_Shift, SDL_SCANCODE_RALT }, { XK_Meta_R, SDL_SCANCODE_RGUI }, { XK_Super_R, SDL_SCANCODE_RGUI }, { XK_Mode_switch, SDL_SCANCODE_MODE }, + { XK_period, SDL_SCANCODE_PERIOD }, + { XK_comma, SDL_SCANCODE_COMMA }, + { XK_slash, SDL_SCANCODE_SLASH }, + { XK_backslash, SDL_SCANCODE_BACKSLASH }, + { XK_minus, SDL_SCANCODE_MINUS }, + { XK_equal, SDL_SCANCODE_EQUALS }, + { XK_space, SDL_SCANCODE_SPACE }, + { XK_grave, SDL_SCANCODE_GRAVE }, + { XK_apostrophe, SDL_SCANCODE_APOSTROPHE }, + { XK_bracketleft, SDL_SCANCODE_LEFTBRACKET }, + { XK_bracketright, SDL_SCANCODE_RIGHTBRACKET }, }; static const struct @@ -142,31 +154,34 @@ static const struct { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) }, { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) }, { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) }, + { xvnc_scancode_table, SDL_arraysize(xvnc_scancode_table) }, }; /* *INDENT-OFF* */ /* This function only works for keyboards in US QWERTY layout */ static SDL_Scancode -X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) +X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode) { KeySym keysym; int i; -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); -#else - keysym = X11_XKeycodeToKeysym(display, keycode, 0); -#endif + keysym = X11_KeyCodeToSym(_this, keycode, 0); if (keysym == NoSymbol) { return SDL_SCANCODE_UNKNOWN; } + if (keysym >= XK_a && keysym <= XK_z) { + return SDL_SCANCODE_A + (keysym - XK_a); + } if (keysym >= XK_A && keysym <= XK_Z) { return SDL_SCANCODE_A + (keysym - XK_A); } - if (keysym >= XK_0 && keysym <= XK_9) { - return SDL_SCANCODE_0 + (keysym - XK_0); + if (keysym == XK_0) { + return SDL_SCANCODE_0; + } + if (keysym >= XK_1 && keysym <= XK_9) { + return SDL_SCANCODE_1 + (keysym - XK_1); } for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) { @@ -178,15 +193,10 @@ X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) } static Uint32 -X11_KeyCodeToUcs4(Display *display, KeyCode keycode, unsigned char group) +X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group) { - KeySym keysym; + KeySym keysym = X11_KeyCodeToSym(_this, keycode, group); -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - keysym = X11_XkbKeycodeToKeysym(display, keycode, group, 0); -#else - keysym = X11_XKeycodeToKeysym(display, keycode, 0); -#endif if (keysym == NoSymbol) { return 0; } @@ -194,6 +204,42 @@ X11_KeyCodeToUcs4(Display *display, KeyCode keycode, unsigned char group) return X11_KeySymToUcs4(keysym); } +KeySym +X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + KeySym keysym; + +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + if (data->xkb) { + int num_groups = XkbKeyNumGroups(data->xkb, keycode); + unsigned char info = XkbKeyGroupInfo(data->xkb, keycode); + + if (num_groups && group >= num_groups) { + + int action = XkbOutOfRangeGroupAction(info); + + if (action == XkbRedirectIntoRange) { + if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) { + group = 0; + } + } else if (action == XkbClampIntoRange) { + group = num_groups - 1; + } else { + group %= num_groups; + } + } + keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0); + } else { + keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); + } +#else + keysym = X11_XKeycodeToKeysym(data->display, keycode, 0); +#endif + + return keysym; +} + int X11_InitKeyboard(_THIS) { @@ -219,6 +265,16 @@ X11_InitKeyboard(_THIS) X11_XAutoRepeatOn(data->display); +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + { + int xkb_major = XkbMajorVersion; + int xkb_minor = XkbMinorVersion; + if (X11_XkbQueryExtension(data->display, NULL, NULL, NULL, &xkb_major, &xkb_minor)) { + data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd); + } + } +#endif + /* Try to determine which scancodes are being used based on fingerprint */ best_distance = SDL_arraysize(fingerprint) + 1; best_index = -1; @@ -263,16 +319,12 @@ X11_InitKeyboard(_THIS) SDL_GetDefaultKeymap(keymap); for (i = min_keycode; i <= max_keycode; ++i) { KeySym sym; -#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0); -#else - sym = X11_XKeycodeToKeysym(data->display, i, 0); -#endif + sym = X11_KeyCodeToSym(_this, (KeyCode) i, 0); if (sym != NoSymbol) { SDL_Scancode scancode; printf("code = %d, sym = 0x%X (%s) ", i - min_keycode, (unsigned int) sym, X11_XKeysymToString(sym)); - scancode = X11_KeyCodeToSDLScancode(data->display, i); + scancode = X11_KeyCodeToSDLScancode(_this, i); data->key_layout[i] = scancode; if (scancode == SDL_SCANCODE_UNKNOWN) { printf("scancode not found\n"); @@ -287,8 +339,8 @@ X11_InitKeyboard(_THIS) SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); -#ifdef SDL_USE_IBUS - SDL_IBus_Init(); +#ifdef SDL_USE_IME + SDL_IME_Init(); #endif return 0; @@ -304,10 +356,12 @@ X11_UpdateKeymap(_THIS) unsigned char group = 0; SDL_GetDefaultKeymap(keymap); - + #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM - { + if (data->xkb) { XkbStateRec state; + X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb); + if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) { group = state.group; } @@ -325,11 +379,11 @@ X11_UpdateKeymap(_THIS) } /* See if there is a UCS keycode for this scancode */ - key = X11_KeyCodeToUcs4(data->display, (KeyCode)i, group); + key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group); if (key) { keymap[scancode] = key; } else { - SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(data->display, (KeyCode)i); + SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i); switch (keyScancode) { case SDL_SCANCODE_RETURN: @@ -359,22 +413,54 @@ X11_UpdateKeymap(_THIS) void X11_QuitKeyboard(_THIS) { -#ifdef SDL_USE_IBUS - SDL_IBus_Quit(); + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + if (data->xkb) { + X11_XkbFreeClientMap(data->xkb, 0, True); + data->xkb = NULL; + } +#endif + +#ifdef SDL_USE_IME + SDL_IME_Quit(); +#endif +} + +static void +X11_ResetXIM(_THIS) +{ +#ifdef X_HAVE_UTF8_STRING + SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; + int i; + + if (videodata && videodata->windowlist) { + for (i = 0; i < videodata->numwindows; ++i) { + SDL_WindowData *data = videodata->windowlist[i]; + if (data && data->ic) { + /* Clear any partially entered dead keys */ + char *contents = X11_Xutf8ResetIC(data->ic); + if (contents) { + X11_XFree(contents); + } + } + } + } #endif } void X11_StartTextInput(_THIS) { - + X11_ResetXIM(_this); } void X11_StopTextInput(_THIS) { -#ifdef SDL_USE_IBUS - SDL_IBus_Reset(); + X11_ResetXIM(_this); +#ifdef SDL_USE_IME + SDL_IME_Reset(); #endif } @@ -386,8 +472,8 @@ X11_SetTextInputRect(_THIS, SDL_Rect *rect) return; } -#ifdef SDL_USE_IBUS - SDL_IBus_UpdateTextRect(rect); +#ifdef SDL_USE_IME + SDL_IME_UpdateTextRect(rect); #endif } diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.h b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.h index a1102ed75..6ce3c9cce 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11keyboard.h @@ -29,6 +29,7 @@ extern void X11_QuitKeyboard(_THIS); extern void X11_StartTextInput(_THIS); extern void X11_StopTextInput(_THIS); extern void X11_SetTextInputRect(_THIS, SDL_Rect *rect); +extern KeySym X11_KeyCodeToSym(_THIS, KeyCode, unsigned char group); #endif /* _SDL_x11keyboard_h */ diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11modes.c b/Engine/lib/sdl/src/video/x11/SDL_x11modes.c index 446da2b64..29307b3a6 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11modes.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11modes.c @@ -157,14 +157,12 @@ CheckXinerama(Display * display, int *major, int *minor) { int event_base = 0; int error_base = 0; - const char *env; /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ - env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA); - if (env && !SDL_atoi(env)) { + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XINERAMA, SDL_TRUE)) { #ifdef X11MODES_DEBUG printf("Xinerama disabled due to hint\n"); #endif @@ -213,22 +211,19 @@ X11_XineramaFailed(Display * d, XErrorEvent * e) static SDL_bool CheckXRandR(Display * display, int *major, int *minor) { - const char *env; - /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ - env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR); #ifdef XRANDR_DISABLED_BY_DEFAULT - if (!env || !SDL_atoi(env)) { + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_FALSE)) { #ifdef X11MODES_DEBUG printf("XRandR disabled by default due to window manager issues\n"); #endif return SDL_FALSE; } #else - if (env && !SDL_atoi(env)) { + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, SDL_TRUE)) { #ifdef X11MODES_DEBUG printf("XRandR disabled due to hint\n"); #endif @@ -264,8 +259,8 @@ CheckXRandR(Display * display, int *major, int *minor) static int CalculateXRandRRefreshRate(const XRRModeInfo *info) { - return (info->hTotal - && info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0; + return (info->hTotal && info->vTotal) ? + round(((double)info->dotClock / (double)(info->hTotal * info->vTotal))) : 0; } static SDL_bool @@ -342,7 +337,7 @@ SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, X11_XFree(props); } - inches = (int)((SDL_sqrt(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f); + inches = (int)((SDL_sqrtf(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); @@ -507,14 +502,11 @@ X11_InitModes_XRandR(_THIS) static SDL_bool CheckVidMode(Display * display, int *major, int *minor) { - const char *env; - /* Default the extension not available */ *major = *minor = 0; /* Allow environment override */ - env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE); - if (env && !SDL_atoi(env)) { + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XVIDMODE, SDL_TRUE)) { #ifdef X11MODES_DEBUG printf("XVidMode disabled due to hint\n"); #endif @@ -618,6 +610,19 @@ X11_InitModes(_THIS) /* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */ + /* This is a workaround for some apps (UnrealEngine4, for example) until + we sort out the ramifications of removing XVidMode support outright. + This block should be removed with the XVidMode support. */ + { + if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) { + #if SDL_VIDEO_DRIVER_X11_XRANDR + return SDL_SetError("XRandR support is required but not available"); + #else + return SDL_SetError("XRandR support is required but not built into SDL!"); + #endif + } + } + #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) @@ -1056,7 +1061,44 @@ X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * h *vdpi = data->vdpi; } - return data->ddpi != 0.0f ? 0 : -1; + return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI"); +} + +int +X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + Display *display = data->display; + Atom _NET_WORKAREA; + int status, real_format; + int retval = -1; + Atom real_type; + unsigned long items_read = 0, items_left = 0; + unsigned char *propdata = NULL; + + if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) { + return -1; + } + + _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False); + status = X11_XGetWindowProperty(display, DefaultRootWindow(display), + _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL, + &real_type, &real_format, &items_read, + &items_left, &propdata); + if ((status == Success) && (items_read >= 4)) { + const long *p = (long*) propdata; + const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] }; + retval = 0; + if (!SDL_IntersectRect(rect, &usable, rect)) { + SDL_zerop(rect); + } + } + + if (propdata) { + X11_XFree(propdata); + } + + return retval; } #endif /* SDL_VIDEO_DRIVER_X11 */ diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11modes.h b/Engine/lib/sdl/src/video/x11/SDL_x11modes.h index a68286ab1..4f47f3b5c 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11modes.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11modes.h @@ -77,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_GetDisplayUsableBounds(_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/Engine/lib/sdl/src/video/x11/SDL_x11mouse.c b/Engine/lib/sdl/src/video/x11/SDL_x11mouse.c index 245b116ea..e1a16c225 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11mouse.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11mouse.c @@ -366,39 +366,52 @@ X11_CaptureMouse(SDL_Window *window) static Uint32 X11_GetGlobalMouseState(int *x, int *y) { + SDL_VideoData *videodata = (SDL_VideoData *) SDL_GetVideoDevice()->driverdata; Display *display = GetDisplay(); const int num_screens = SDL_GetNumVideoDisplays(); int i; /* !!! FIXME: should we XSync() here first? */ - for (i = 0; i < num_screens; i++) { - SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i); - if (data != NULL) { - Window root, child; - 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; - /* 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; +#if !SDL_VIDEO_DRIVER_X11_XINPUT2 + videodata->global_mouse_changed = SDL_TRUE; +#endif + + /* check if we have this cached since XInput last saw the mouse move. */ + /* !!! FIXME: can we just calculate this from XInput's events? */ + if (videodata->global_mouse_changed) { + for (i = 0; i < num_screens; i++) { + SDL_DisplayData *data = (SDL_DisplayData *) SDL_GetDisplayDriverData(i); + if (data != NULL) { + Window root, child; + 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 buttons = 0; + buttons |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0; + buttons |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0; + buttons |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0; + /* 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); + videodata->global_mouse_position.x = root_attrs.x + rootx; + videodata->global_mouse_position.y = root_attrs.y + rooty; + videodata->global_mouse_buttons = buttons; + videodata->global_mouse_changed = SDL_FALSE; + break; + } } } } - SDL_assert(0 && "The pointer wasn't on any X11 screen?!"); + SDL_assert(!videodata->global_mouse_changed); /* The pointer wasn't on any X11 screen?! */ - return 0; + *x = videodata->global_mouse_position.x; + *y = videodata->global_mouse_position.y; + return videodata->global_mouse_buttons; } diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c b/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c index 8b634be3d..abc699dd4 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11opengl.c @@ -695,7 +695,7 @@ X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) 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 */ + } else if (!rc) { /* glXMakeCurrent() failed without throwing an X error */ return SDL_SetError("Unable to make GL context current"); } @@ -703,14 +703,14 @@ X11_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) } /* - 0 is a valid argument to glxSwapInterval(MESA|EXT) and setting it to 0 + 0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0 will undo the effect of a previous call with a value that is greater than zero (or at least that is what the docs say). OTOH, 0 is an invalid - argument to glxSwapIntervalSGI and it returns an error if you call it + argument to glXSwapIntervalSGI and it returns an error if you call it with 0 as an argument. */ -static int swapinterval = -1; +static int swapinterval = 0; int X11_GL_SetSwapInterval(_THIS, int interval) { @@ -742,14 +742,14 @@ X11_GL_SetSwapInterval(_THIS, int interval) } else if (_this->gl_data->glXSwapIntervalMESA) { status = _this->gl_data->glXSwapIntervalMESA(interval); if (status != 0) { - SDL_SetError("glxSwapIntervalMESA failed"); + SDL_SetError("glXSwapIntervalMESA failed"); } else { swapinterval = interval; } } else if (_this->gl_data->glXSwapIntervalSGI) { status = _this->gl_data->glXSwapIntervalSGI(interval); if (status != 0) { - SDL_SetError("glxSwapIntervalSGI failed"); + SDL_SetError("glXSwapIntervalSGI failed"); } else { swapinterval = interval; } diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11sym.h b/Engine/lib/sdl/src/video/x11/SDL_x11sym.h index 3683ac0a5..7290412b7 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11sym.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11sym.h @@ -21,6 +21,14 @@ /* *INDENT-OFF* */ +#ifndef SDL_X11_MODULE +#define SDL_X11_MODULE(modname) +#endif + +#ifndef SDL_X11_SYM +#define SDL_X11_SYM(rc,fn,params,args,ret) +#endif + SDL_X11_MODULE(BASEXLIB) SDL_X11_SYM(XSizeHints*,XAllocSizeHints,(void),(),return) SDL_X11_SYM(XWMHints*,XAllocWMHints,(void),(),return) @@ -153,6 +161,7 @@ SDL_X11_SYM(SDL_X11_XSynchronizeRetType,XSynchronize,(Display* a,Bool b),(a,b),r 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),) +SDL_X11_SYM(int,XQueryTree,(Display* a,Window b,Window* c,Window* d,Window** e,unsigned int* f),(a,b,c,d,e,f),return) #if SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return) @@ -160,12 +169,16 @@ SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),) #endif #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM +SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f),(a,b,c,d,e,f),return) #if NeedWidePrototypes SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,unsigned int b,int c,int d),(a,b,c,d),return) #else SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,KeyCode b,int c,int d),(a,b,c,d),return) #endif SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c),return) +SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return) +SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b,c),return) +SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),) #endif #if NeedWidePrototypes @@ -187,6 +200,8 @@ SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d) SDL_X11_SYM(Status,XCloseIM,(XIM a),(a),return) SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h),(a,b,c,d,e,f,g,h),) SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle* d, XRectangle* e),(a,b,c,d,e),return) +SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a),(a),return) +SDL_X11_SYM(char*,Xutf8ResetIC,(XIC a),(a),return) #endif #ifndef NO_SHARED_MEMORY @@ -311,6 +326,9 @@ SDL_X11_SYM(Bool,XF86VidModeSwitchToMode,(Display *a,int b,XF86VidModeModeInfo * SDL_X11_SYM(Bool,XF86VidModeLockModeSwitch,(Display *a,int b,int c),(a,b,c),return) #endif +#undef SDL_X11_MODULE +#undef SDL_X11_SYM + /* *INDENT-ON* */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11video.c b/Engine/lib/sdl/src/video/x11/SDL_x11video.c index 01f8ae60f..38b34de34 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11video.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11video.c @@ -39,6 +39,10 @@ #include "SDL_x11opengles.h" #endif +#ifdef X_HAVE_UTF8_STRING +#include +#endif + /* Initialization/Query functions */ static int X11_VideoInit(_THIS); static void X11_VideoQuit(_THIS); @@ -175,6 +179,8 @@ X11_CreateDevice(int devindex) } device->driverdata = data; + data->global_mouse_changed = SDL_TRUE; + /* FIXME: Do we need this? if ( (SDL_strncmp(X11_XDisplayName(display), ":", 1) == 0) || (SDL_strncmp(X11_XDisplayName(display), "unix:", 5) == 0) ) { @@ -216,6 +222,7 @@ X11_CreateDevice(int devindex) device->VideoQuit = X11_VideoQuit; device->GetDisplayModes = X11_GetDisplayModes; device->GetDisplayBounds = X11_GetDisplayBounds; + device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds; device->GetDisplayDPI = X11_GetDisplayDPI; device->SetDisplayMode = X11_SetDisplayMode; device->SuspendScreenSaver = X11_SuspendScreenSaver; @@ -229,6 +236,10 @@ X11_CreateDevice(int devindex) device->SetWindowSize = X11_SetWindowSize; device->SetWindowMinimumSize = X11_SetWindowMinimumSize; device->SetWindowMaximumSize = X11_SetWindowMaximumSize; + device->GetWindowBordersSize = X11_GetWindowBordersSize; + device->SetWindowOpacity = X11_SetWindowOpacity; + device->SetWindowModalFor = X11_SetWindowModalFor; + device->SetWindowInputFocus = X11_SetWindowInputFocus; device->ShowWindow = X11_ShowWindow; device->HideWindow = X11_HideWindow; device->RaiseWindow = X11_RaiseWindow; @@ -236,6 +247,7 @@ X11_CreateDevice(int devindex) device->MinimizeWindow = X11_MinimizeWindow; device->RestoreWindow = X11_RestoreWindow; device->SetWindowBordered = X11_SetWindowBordered; + device->SetWindowResizable = X11_SetWindowResizable; device->SetWindowFullscreen = X11_SetWindowFullscreen; device->SetWindowGammaRamp = X11_SetWindowGammaRamp; device->SetWindowGrab = X11_SetWindowGrab; @@ -278,7 +290,7 @@ X11_CreateDevice(int devindex) device->StartTextInput = X11_StartTextInput; device->StopTextInput = X11_StopTextInput; device->SetTextInputRect = X11_SetTextInputRect; - + device->free = X11_DeleteDevice; return device; @@ -373,11 +385,65 @@ X11_VideoInit(_THIS) /* Get the process PID to be associated to the window */ data->pid = getpid(); + /* I have no idea how random this actually is, or has to be. */ + data->window_group = (XID) (((size_t) data->pid) ^ ((size_t) _this)); + /* Open a connection to the X input manager */ #ifdef X_HAVE_UTF8_STRING if (SDL_X11_HAVE_UTF8) { - data->im = - X11_XOpenIM(data->display, NULL, data->classname, data->classname); + /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that + Compose keys will work correctly. */ + char *prev_locale = setlocale(LC_ALL, NULL); + char *prev_xmods = X11_XSetLocaleModifiers(NULL); + const char *new_xmods = ""; +#if defined(HAVE_IBUS_IBUS_H) || defined(HAVE_FCITX_FRONTEND_H) + const char *env_xmods = SDL_getenv("XMODIFIERS"); +#endif + SDL_bool has_dbus_ime_support = SDL_FALSE; + + if (prev_locale) { + prev_locale = SDL_strdup(prev_locale); + } + + if (prev_xmods) { + prev_xmods = SDL_strdup(prev_xmods); + } + + /* IBus resends some key events that were filtered by XFilterEvents + when it is used via XIM which causes issues. Prevent this by forcing + @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via + the DBus implementation, which also has support for pre-editing. */ +#ifdef HAVE_IBUS_IBUS_H + if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) { + has_dbus_ime_support = SDL_TRUE; + } +#endif +#ifdef HAVE_FCITX_FRONTEND_H + if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) { + has_dbus_ime_support = SDL_TRUE; + } +#endif + if (has_dbus_ime_support) { + new_xmods = "@im=none"; + } + + setlocale(LC_ALL, ""); + X11_XSetLocaleModifiers(new_xmods); + + data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname); + + /* Reset the locale + X locale modifiers back to how they were, + locale first because the X locale modifiers depend on it. */ + setlocale(LC_ALL, prev_locale); + X11_XSetLocaleModifiers(prev_xmods); + + if (prev_locale) { + SDL_free(prev_locale); + } + + if (prev_xmods) { + SDL_free(prev_xmods); + } } #endif @@ -385,19 +451,26 @@ X11_VideoInit(_THIS) #define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False) GET_ATOM(WM_PROTOCOLS); GET_ATOM(WM_DELETE_WINDOW); + GET_ATOM(WM_TAKE_FOCUS); GET_ATOM(_NET_WM_STATE); GET_ATOM(_NET_WM_STATE_HIDDEN); GET_ATOM(_NET_WM_STATE_FOCUSED); GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT); GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ); GET_ATOM(_NET_WM_STATE_FULLSCREEN); + GET_ATOM(_NET_WM_STATE_ABOVE); + GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR); + GET_ATOM(_NET_WM_STATE_SKIP_PAGER); GET_ATOM(_NET_WM_ALLOWED_ACTIONS); GET_ATOM(_NET_WM_ACTION_FULLSCREEN); GET_ATOM(_NET_WM_NAME); GET_ATOM(_NET_WM_ICON_NAME); GET_ATOM(_NET_WM_ICON); GET_ATOM(_NET_WM_PING); + GET_ATOM(_NET_WM_WINDOW_OPACITY); + GET_ATOM(_NET_WM_USER_TIME); GET_ATOM(_NET_ACTIVE_WINDOW); + GET_ATOM(_NET_FRAME_EXTENTS); GET_ATOM(UTF8_STRING); GET_ATOM(PRIMARY); GET_ATOM(XdndEnter); diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11video.h b/Engine/lib/sdl/src/video/x11/SDL_x11video.h index 2083defd2..a3324ff53 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11video.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11video.h @@ -57,7 +57,7 @@ #endif #include "../../core/linux/SDL_dbus.h" -#include "../../core/linux/SDL_ibus.h" +#include "../../core/linux/SDL_ime.h" #include "SDL_x11dyn.h" @@ -81,6 +81,7 @@ typedef struct SDL_VideoData int numwindows; SDL_WindowData **windowlist; int windowlistlength; + XID window_group; /* This is true for ICCCM2.0-compliant window managers */ SDL_bool net_wm; @@ -88,19 +89,26 @@ typedef struct SDL_VideoData /* Useful atoms */ Atom WM_PROTOCOLS; Atom WM_DELETE_WINDOW; + Atom WM_TAKE_FOCUS; Atom _NET_WM_STATE; Atom _NET_WM_STATE_HIDDEN; Atom _NET_WM_STATE_FOCUSED; Atom _NET_WM_STATE_MAXIMIZED_VERT; Atom _NET_WM_STATE_MAXIMIZED_HORZ; Atom _NET_WM_STATE_FULLSCREEN; + Atom _NET_WM_STATE_ABOVE; + Atom _NET_WM_STATE_SKIP_TASKBAR; + Atom _NET_WM_STATE_SKIP_PAGER; Atom _NET_WM_ALLOWED_ACTIONS; Atom _NET_WM_ACTION_FULLSCREEN; Atom _NET_WM_NAME; Atom _NET_WM_ICON_NAME; Atom _NET_WM_ICON; Atom _NET_WM_PING; + Atom _NET_WM_WINDOW_OPACITY; + Atom _NET_WM_USER_TIME; Atom _NET_ACTIVE_WINDOW; + Atom _NET_FRAME_EXTENTS; Atom UTF8_STRING; Atom PRIMARY; Atom XdndEnter; @@ -117,6 +125,14 @@ typedef struct SDL_VideoData SDL_bool selection_waiting; Uint32 last_mode_change_deadline; + + SDL_bool global_mouse_changed; + SDL_Point global_mouse_position; + Uint32 global_mouse_buttons; + +#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM + XkbDescPtr xkb; +#endif } SDL_VideoData; extern SDL_bool X11_UseDirectColorVisuals(void); diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11window.c b/Engine/lib/sdl/src/video/x11/SDL_x11window.c index afc802198..668bce225 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11window.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11window.c @@ -130,13 +130,17 @@ X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags) { SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; Display *display = videodata->display; + /* !!! FIXME: just dereference videodata below instead of copying to locals. */ Atom _NET_WM_STATE = videodata->_NET_WM_STATE; /* Atom _NET_WM_STATE_HIDDEN = videodata->_NET_WM_STATE_HIDDEN; */ Atom _NET_WM_STATE_FOCUSED = videodata->_NET_WM_STATE_FOCUSED; Atom _NET_WM_STATE_MAXIMIZED_VERT = videodata->_NET_WM_STATE_MAXIMIZED_VERT; Atom _NET_WM_STATE_MAXIMIZED_HORZ = videodata->_NET_WM_STATE_MAXIMIZED_HORZ; Atom _NET_WM_STATE_FULLSCREEN = videodata->_NET_WM_STATE_FULLSCREEN; - Atom atoms[5]; + Atom _NET_WM_STATE_ABOVE = videodata->_NET_WM_STATE_ABOVE; + Atom _NET_WM_STATE_SKIP_TASKBAR = videodata->_NET_WM_STATE_SKIP_TASKBAR; + Atom _NET_WM_STATE_SKIP_PAGER = videodata->_NET_WM_STATE_SKIP_PAGER; + Atom atoms[16]; int count = 0; /* The window manager sets this property, we shouldn't set it. @@ -147,6 +151,14 @@ X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags) atoms[count++] = _NET_WM_STATE_HIDDEN; } */ + + if (flags & SDL_WINDOW_ALWAYS_ON_TOP) { + atoms[count++] = _NET_WM_STATE_ABOVE; + } + if (flags & SDL_WINDOW_SKIP_TASKBAR) { + atoms[count++] = _NET_WM_STATE_SKIP_TASKBAR; + atoms[count++] = _NET_WM_STATE_SKIP_PAGER; + } if (flags & SDL_WINDOW_INPUT_FOCUS) { atoms[count++] = _NET_WM_STATE_FOCUSED; } @@ -157,6 +169,9 @@ X11_SetNetWMState(_THIS, Window xwindow, Uint32 flags) if (flags & SDL_WINDOW_FULLSCREEN) { atoms[count++] = _NET_WM_STATE_FULLSCREEN; } + + SDL_assert(count <= SDL_arraysize(atoms)); + if (count > 0) { X11_XChangeProperty(display, xwindow, _NET_WM_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, count); @@ -206,7 +221,9 @@ X11_GetNetWMState(_THIS, Window xwindow) } if (maximized == 3) { flags |= SDL_WINDOW_MAXIMIZED; - } else if (fullscreen == 1) { + } + + if (fullscreen == 1) { flags |= SDL_WINDOW_FULLSCREEN; } X11_XFree(propertyValue); @@ -355,10 +372,11 @@ X11_CreateWindow(_THIS, SDL_Window * window) XSizeHints *sizehints; XWMHints *wmhints; XClassHint *classhints; - const long _NET_WM_BYPASS_COMPOSITOR_HINT_ON = 1; Atom _NET_WM_BYPASS_COMPOSITOR; Atom _NET_WM_WINDOW_TYPE; - Atom _NET_WM_WINDOW_TYPE_NORMAL; + Atom wintype; + const char *wintype_name = NULL; + int compositor = 1; Atom _NET_WM_PID; Atom XdndAware, xdnd_version = 5; long fevent = 0; @@ -396,7 +414,7 @@ X11_CreateWindow(_THIS, SDL_Window * window) depth = displaydata->depth; } - xattr.override_redirect = False; + xattr.override_redirect = ((window->flags & SDL_WINDOW_TOOLTIP) || (window->flags & SDL_WINDOW_POPUP_MENU)) ? True : False; xattr.background_pixmap = None; xattr.border_pixel = 0; @@ -506,7 +524,8 @@ X11_CreateWindow(_THIS, SDL_Window * window) /* Setup the input hints so we get keyboard input */ wmhints = X11_XAllocWMHints(); wmhints->input = True; - wmhints->flags = InputHint; + wmhints->window_group = data->window_group; + wmhints->flags = InputHint | WindowGroupHint; /* Setup the class hints so we can get an icon (AfterStep) */ classhints = X11_XAllocClassHint(); @@ -521,39 +540,49 @@ X11_CreateWindow(_THIS, SDL_Window * window) X11_XFree(classhints); /* Set the PID related to the window for the given hostname, if possible */ if (data->pid > 0) { + long pid = (long) data->pid; _NET_WM_PID = X11_XInternAtom(display, "_NET_WM_PID", False); X11_XChangeProperty(display, w, _NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)&data->pid, 1); + (unsigned char *) &pid, 1); } /* Set the window manager state */ X11_SetNetWMState(_this, w, window->flags); - /* Let the window manager know we're a "normal" window */ + compositor = 2; /* don't disable compositing except for "normal" windows */ + + if (window->flags & SDL_WINDOW_UTILITY) { + wintype_name = "_NET_WM_WINDOW_TYPE_UTILITY"; + } else if (window->flags & SDL_WINDOW_TOOLTIP) { + wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP"; + } else if (window->flags & SDL_WINDOW_POPUP_MENU) { + wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU"; + } else { + wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL"; + compositor = 1; /* disable compositing for "normal" windows */ + } + + /* Let the window manager know what type of window we are. */ _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); - _NET_WM_WINDOW_TYPE_NORMAL = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False); + wintype = X11_XInternAtom(display, wintype_name, False); X11_XChangeProperty(display, w, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, - PropModeReplace, - (unsigned char *)&_NET_WM_WINDOW_TYPE_NORMAL, 1); + PropModeReplace, (unsigned char *)&wintype, 1); _NET_WM_BYPASS_COMPOSITOR = X11_XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", False); X11_XChangeProperty(display, w, _NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON, 1); + (unsigned char *)&compositor, 1); { - Atom protocols[2]; + Atom protocols[3]; int proto_count = 0; - const char *ping_hint; - protocols[proto_count] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */ - proto_count++; - - ping_hint = SDL_GetHint(SDL_HINT_VIDEO_X11_NET_WM_PING); + protocols[proto_count++] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */ + protocols[proto_count++] = data->WM_TAKE_FOCUS; /* Since we will want to set input focus explicitly */ + /* Default to using ping if there is no hint */ - if (!ping_hint || SDL_atoi(ping_hint)) { - protocols[proto_count] = data->_NET_WM_PING; /* Respond so WM knows we're alive */ - proto_count++; + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NET_WM_PING, SDL_TRUE)) { + protocols[proto_count++] = data->_NET_WM_PING; /* Respond so WM knows we're alive */ } SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0])); @@ -750,7 +779,7 @@ X11_SetWindowPosition(_THIS, SDL_Window * window) SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; - X11_XMoveWindow(display, data->xwindow, window->x, window->y); + X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); X11_XFlush(display); } @@ -776,7 +805,7 @@ X11_SetWindowMinimumSize(_THIS, SDL_Window * window) /* See comment in X11_SetWindowSize. */ X11_XResizeWindow(display, data->xwindow, window->w, window->h); - X11_XMoveWindow(display, data->xwindow, window->x, window->y); + X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); X11_XRaiseWindow(display, data->xwindow); } @@ -805,7 +834,7 @@ X11_SetWindowMaximumSize(_THIS, SDL_Window * window) /* See comment in X11_SetWindowSize. */ X11_XResizeWindow(display, data->xwindow, window->w, window->h); - X11_XMoveWindow(display, data->xwindow, window->x, window->y); + X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); X11_XRaiseWindow(display, data->xwindow); } @@ -854,7 +883,7 @@ X11_SetWindowSize(_THIS, SDL_Window * window) and transitioning from windowed to fullscreen in Unity. */ X11_XResizeWindow(display, data->xwindow, window->w, window->h); - X11_XMoveWindow(display, data->xwindow, window->x, window->y); + X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); X11_XRaiseWindow(display, data->xwindow); } else { X11_XResizeWindow(display, data->xwindow, window->w, window->h); @@ -863,6 +892,61 @@ X11_SetWindowSize(_THIS, SDL_Window * window) X11_XFlush(display); } +int +X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right) +{ + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + + *left = data->border_left; + *right = data->border_right; + *top = data->border_top; + *bottom = data->border_bottom; + + return 0; +} + +int +X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + Atom _NET_WM_WINDOW_OPACITY = data->videodata->_NET_WM_WINDOW_OPACITY; + + if (opacity == 1.0f) { + X11_XDeleteProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY); + } else { + const Uint32 FullyOpaque = 0xFFFFFFFF; + const long alpha = (long) ((double)opacity * (double)FullyOpaque); + X11_XChangeProperty(display, data->xwindow, _NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&alpha, 1); + } + + return 0; +} + +int +X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window) { + SDL_WindowData *data = (SDL_WindowData *) modal_window->driverdata; + SDL_WindowData *parent_data = (SDL_WindowData *) parent_window->driverdata; + Display *display = data->videodata->display; + + X11_XSetTransientForHint(display, data->xwindow, parent_data->xwindow); + return 0; +} + +int +X11_SetWindowInputFocus(_THIS, SDL_Window * window) +{ + if (X11_IsWindowMapped(_this, window)) { + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + X11_XSetInputFocus(display, data->xwindow, RevertToNone, CurrentTime); + X11_XFlush(display); + return 0; + } + return -1; +} + void X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { @@ -895,6 +979,44 @@ X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) X11_XCheckIfEvent(display, &event, &isMapNotify, (XPointer)&data->xwindow); } +void +X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + Display *display = data->videodata->display; + + XSizeHints *sizehints = X11_XAllocSizeHints(); + long userhints; + + X11_XGetWMNormalHints(display, data->xwindow, sizehints, &userhints); + + if (resizable) { + /* FIXME: Is there a better way to get max window size from X? -flibit */ + const int maxsize = 0x7FFFFFFF; + sizehints->min_width = window->min_w; + sizehints->min_height = window->min_h; + sizehints->max_width = (window->max_w == 0) ? maxsize : window->max_w; + sizehints->max_height = (window->max_h == 0) ? maxsize : window->max_h; + } else { + sizehints->min_width = window->w; + sizehints->min_height = window->h; + sizehints->max_width = window->w; + sizehints->max_height = window->h; + } + sizehints->flags |= PMinSize | PMaxSize; + + X11_XSetWMNormalHints(display, data->xwindow, sizehints); + + X11_XFree(sizehints); + + /* See comment in X11_SetWindowSize. */ + X11_XResizeWindow(display, data->xwindow, window->w, window->h); + X11_XMoveWindow(display, data->xwindow, window->x - data->border_left, window->y - data->border_top); + X11_XRaiseWindow(display, data->xwindow); + + X11_XFlush(display); +} + void X11_ShowWindow(_THIS, SDL_Window * window) { @@ -946,13 +1068,15 @@ SetWindowActive(_THIS, SDL_Window * window) if (X11_IsWindowMapped(_this, window)) { XEvent e; + /*printf("SDL Window %p: sending _NET_ACTIVE_WINDOW with timestamp %lu\n", window, data->user_time);*/ + SDL_zero(e); e.xany.type = ClientMessage; e.xclient.message_type = _NET_ACTIVE_WINDOW; e.xclient.format = 32; e.xclient.window = data->xwindow; e.xclient.data.l[0] = 1; /* source indication. 1 = application */ - e.xclient.data.l[1] = CurrentTime; + e.xclient.data.l[1] = data->user_time; e.xclient.data.l[2] = 0; X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0, @@ -1038,7 +1162,7 @@ X11_RestoreWindow(_THIS, SDL_Window * window) SetWindowActive(_this, window); } -/* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */ +/* This asks the Window Manager to handle fullscreen for us. This is the modern way. */ static void X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen) { @@ -1083,6 +1207,22 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0, SubstructureNotifyMask | SubstructureRedirectMask, &e); + + /* Fullscreen windows sometimes end up being marked maximized by + window managers. Force it back to how we expect it to be. */ + if (!fullscreen && ((window->flags & SDL_WINDOW_MAXIMIZED) == 0)) { + SDL_zero(e); + e.xany.type = ClientMessage; + e.xclient.message_type = _NET_WM_STATE; + e.xclient.format = 32; + e.xclient.window = data->xwindow; + e.xclient.data.l[0] = _NET_WM_STATE_REMOVE; + e.xclient.data.l[1] = data->videodata->_NET_WM_STATE_MAXIMIZED_VERT; + e.xclient.data.l[2] = data->videodata->_NET_WM_STATE_MAXIMIZED_HORZ; + e.xclient.data.l[3] = 0l; + X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0, + SubstructureNotifyMask | SubstructureRedirectMask, &e); + } } else { Uint32 flags; @@ -1335,7 +1475,6 @@ X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) Display *display = data->videodata->display; SDL_bool oldstyle_fullscreen; SDL_bool grab_keyboard; - const char *hint; /* ICCCM2.0-compliant window managers can handle fullscreen windows If we're using XVidMode to change resolution we need to confine @@ -1359,8 +1498,7 @@ X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed) X11_XRaiseWindow(display, data->xwindow); /* Now grab the keyboard */ - hint = SDL_GetHint(SDL_HINT_GRAB_KEYBOARD); - if (hint && SDL_atoi(hint)) { + if (SDL_GetHintBoolean(SDL_HINT_GRAB_KEYBOARD, SDL_FALSE)) { grab_keyboard = SDL_TRUE; } else { /* We need to do this with the old style override_redirect diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11window.h b/Engine/lib/sdl/src/video/x11/SDL_x11window.h index efe7ec0f0..50a739dad 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11window.h +++ b/Engine/lib/sdl/src/video/x11/SDL_x11window.h @@ -56,10 +56,16 @@ typedef struct GC gc; XIC ic; SDL_bool created; + int border_left; + int border_right; + int border_top; + int border_bottom; + Uint32 last_focus_event_time; PendingFocusEnum pending_focus; Uint32 pending_focus_time; XConfigureEvent last_xconfigure; struct SDL_VideoData *videodata; + unsigned long user_time; Atom xdnd_req; Window xdnd_source; #if SDL_VIDEO_OPENGL_EGL @@ -78,6 +84,10 @@ extern void X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon); extern void X11_SetWindowPosition(_THIS, SDL_Window * window); extern void X11_SetWindowMinimumSize(_THIS, SDL_Window * window); extern void X11_SetWindowMaximumSize(_THIS, SDL_Window * window); +extern int X11_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right); +extern int X11_SetWindowOpacity(_THIS, SDL_Window * window, float opacity); +extern int X11_SetWindowModalFor(_THIS, SDL_Window * modal_window, SDL_Window * parent_window); +extern int X11_SetWindowInputFocus(_THIS, SDL_Window * window); extern void X11_SetWindowSize(_THIS, SDL_Window * window); extern void X11_ShowWindow(_THIS, SDL_Window * window); extern void X11_HideWindow(_THIS, SDL_Window * window); @@ -86,6 +96,7 @@ extern void X11_MaximizeWindow(_THIS, SDL_Window * window); extern void X11_MinimizeWindow(_THIS, SDL_Window * window); extern void X11_RestoreWindow(_THIS, SDL_Window * window); extern void X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered); +extern void X11_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable); extern void X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen); extern int X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp); extern void X11_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed); diff --git a/Engine/lib/sdl/src/video/x11/SDL_x11xinput2.c b/Engine/lib/sdl/src/video/x11/SDL_x11xinput2.c index 57132fe9e..bed4234f0 100644 --- a/Engine/lib/sdl/src/video/x11/SDL_x11xinput2.c +++ b/Engine/lib/sdl/src/video/x11/SDL_x11xinput2.c @@ -118,6 +118,8 @@ X11_InitXinput2(_THIS) eventmask.mask = mask; XISetMask(mask, XI_RawMotion); + XISetMask(mask, XI_RawButtonPress); + XISetMask(mask, XI_RawButtonRelease); if (X11_XISelectEvents(data->display,DefaultRootWindow(data->display),&eventmask,1) != Success) { return; @@ -140,6 +142,8 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) static Time prev_time = 0; static double prev_rel_coords[2]; + videodata->global_mouse_changed = SDL_TRUE; + if (!mouse->relative_mode || mouse->relative_mode_warp) { return 0; } @@ -158,6 +162,12 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie) return 1; } break; + + case XI_RawButtonPress: + case XI_RawButtonRelease: + videodata->global_mouse_changed = SDL_TRUE; + break; + #if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH case XI_TouchBegin: { const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data; diff --git a/Engine/lib/sdl/src/video/x11/edid-parse.c b/Engine/lib/sdl/src/video/x11/edid-parse.c index 2c145e23c..57f225b85 100644 --- a/Engine/lib/sdl/src/video/x11/edid-parse.c +++ b/Engine/lib/sdl/src/video/x11/edid-parse.c @@ -21,6 +21,8 @@ */ /* Author: Soren Sandmann */ +#include "../../SDL_internal.h" +#include "SDL_stdinc.h" #include "edid.h" #include @@ -247,7 +249,7 @@ decode_fraction (int high, int low) high = (high << 2) | low; for (i = 0; i < 10; ++i) - result += get_bit (high, i) * pow (2, i - 10); + result += get_bit (high, i) * SDL_pow (2, i - 10); return result; } diff --git a/Engine/lib/sdl/src/video/x11/imKStoUCS.c b/Engine/lib/sdl/src/video/x11/imKStoUCS.c index e4f086464..40e224243 100644 --- a/Engine/lib/sdl/src/video/x11/imKStoUCS.c +++ b/Engine/lib/sdl/src/video/x11/imKStoUCS.c @@ -1,297 +1,296 @@ -/* Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved. +/* +Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett +Copyright © 2009 Red Hat, Inc. +Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates. +All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is fur- -nished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- -NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- -NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the XFree86 Project shall not -be used in advertising or otherwise to promote the sale, use or other deal- -ings in this Software without prior written authorization from the XFree86 -Project. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. */ + #include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_X11 - -/* $XFree86: xc/lib/X11/imKStoUCS.c,v 1.4 2003/04/29 11:29:18 pascal Exp $ */ - #include #include "imKStoUCS.h" static unsigned short const keysym_to_unicode_1a1_1ff[] = { - 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */ - 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */ - 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */ - 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */ - 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */ - 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */ - 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */ - 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */ - 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */ - 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */ - 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */ - 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */ + 0x0104, 0x02d8, 0x0141, 0x0000, 0x013d, 0x015a, 0x0000, /* 0x01a0-0x01a7 */ + 0x0000, 0x0160, 0x015e, 0x0164, 0x0179, 0x0000, 0x017d, 0x017b, /* 0x01a8-0x01af */ + 0x0000, 0x0105, 0x02db, 0x0142, 0x0000, 0x013e, 0x015b, 0x02c7, /* 0x01b0-0x01b7 */ + 0x0000, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, /* 0x01b8-0x01bf */ + 0x0154, 0x0000, 0x0000, 0x0102, 0x0000, 0x0139, 0x0106, 0x0000, /* 0x01c0-0x01c7 */ + 0x010c, 0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x0000, 0x010e, /* 0x01c8-0x01cf */ + 0x0110, 0x0143, 0x0147, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000, /* 0x01d0-0x01d7 */ + 0x0158, 0x016e, 0x0000, 0x0170, 0x0000, 0x0000, 0x0162, 0x0000, /* 0x01d8-0x01df */ + 0x0155, 0x0000, 0x0000, 0x0103, 0x0000, 0x013a, 0x0107, 0x0000, /* 0x01e0-0x01e7 */ + 0x010d, 0x0000, 0x0119, 0x0000, 0x011b, 0x0000, 0x0000, 0x010f, /* 0x01e8-0x01ef */ + 0x0111, 0x0144, 0x0148, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, /* 0x01f0-0x01f7 */ + 0x0159, 0x016f, 0x0000, 0x0171, 0x0000, 0x0000, 0x0163, 0x02d9 /* 0x01f8-0x01ff */ }; static unsigned short const keysym_to_unicode_2a1_2fe[] = { - 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */ - 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */ - 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */ - 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */ - 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */ - 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */ + 0x0126, 0x0000, 0x0000, 0x0000, 0x0000, 0x0124, 0x0000, /* 0x02a0-0x02a7 */ + 0x0000, 0x0130, 0x0000, 0x011e, 0x0134, 0x0000, 0x0000, 0x0000, /* 0x02a8-0x02af */ + 0x0000, 0x0127, 0x0000, 0x0000, 0x0000, 0x0000, 0x0125, 0x0000, /* 0x02b0-0x02b7 */ + 0x0000, 0x0131, 0x0000, 0x011f, 0x0135, 0x0000, 0x0000, 0x0000, /* 0x02b8-0x02bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010a, 0x0108, 0x0000, /* 0x02c0-0x02c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02c8-0x02cf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0120, 0x0000, 0x0000, /* 0x02d0-0x02d7 */ + 0x011c, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x015c, 0x0000, /* 0x02d8-0x02df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x010b, 0x0109, 0x0000, /* 0x02e0-0x02e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x02e8-0x02ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0121, 0x0000, 0x0000, /* 0x02f0-0x02f7 */ + 0x011d, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x015d /* 0x02f8-0x02ff */ }; static unsigned short const keysym_to_unicode_3a2_3fe[] = { - 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */ - 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */ - 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */ - 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */ - 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */ - 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */ - 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */ - 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */ - 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */ - 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */ + 0x0138, 0x0156, 0x0000, 0x0128, 0x013b, 0x0000, /* 0x03a0-0x03a7 */ + 0x0000, 0x0000, 0x0112, 0x0122, 0x0166, 0x0000, 0x0000, 0x0000, /* 0x03a8-0x03af */ + 0x0000, 0x0000, 0x0000, 0x0157, 0x0000, 0x0129, 0x013c, 0x0000, /* 0x03b0-0x03b7 */ + 0x0000, 0x0000, 0x0113, 0x0123, 0x0167, 0x014a, 0x0000, 0x014b, /* 0x03b8-0x03bf */ + 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012e, /* 0x03c0-0x03c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0116, 0x0000, 0x0000, 0x012a, /* 0x03c8-0x03cf */ + 0x0000, 0x0145, 0x014c, 0x0136, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03d0-0x03d7 */ + 0x0000, 0x0172, 0x0000, 0x0000, 0x0000, 0x0168, 0x016a, 0x0000, /* 0x03d8-0x03df */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x012f, /* 0x03e0-0x03e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0117, 0x0000, 0x0000, 0x012b, /* 0x03e8-0x03ef */ + 0x0000, 0x0146, 0x014d, 0x0137, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x03f0-0x03f7 */ + 0x0000, 0x0173, 0x0000, 0x0000, 0x0000, 0x0169, 0x016b /* 0x03f8-0x03ff */ }; static unsigned short const keysym_to_unicode_4a1_4df[] = { - 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */ - 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */ - 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */ - 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */ - 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */ - 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */ - 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */ - 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */ + 0x3002, 0x3008, 0x3009, 0x3001, 0x30fb, 0x30f2, 0x30a1, /* 0x04a0-0x04a7 */ + 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30e3, 0x30e5, 0x30e7, 0x30c3, /* 0x04a8-0x04af */ + 0x30fc, 0x30a2, 0x30a4, 0x30a6, 0x30a8, 0x30aa, 0x30ab, 0x30ad, /* 0x04b0-0x04b7 */ + 0x30af, 0x30b1, 0x30b3, 0x30b5, 0x30b7, 0x30b9, 0x30bb, 0x30bd, /* 0x04b8-0x04bf */ + 0x30bf, 0x30c1, 0x30c4, 0x30c6, 0x30c8, 0x30ca, 0x30cb, 0x30cc, /* 0x04c0-0x04c7 */ + 0x30cd, 0x30ce, 0x30cf, 0x30d2, 0x30d5, 0x30d8, 0x30db, 0x30de, /* 0x04c8-0x04cf */ + 0x30df, 0x30e0, 0x30e1, 0x30e2, 0x30e4, 0x30e6, 0x30e8, 0x30e9, /* 0x04d0-0x04d7 */ + 0x30ea, 0x30eb, 0x30ec, 0x30ed, 0x30ef, 0x30f3, 0x309b, 0x309c /* 0x04d8-0x04df */ }; static unsigned short const keysym_to_unicode_590_5fe[] = { - 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */ - 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */ + 0x06f0, 0x06f1, 0x06f2, 0x06f3, 0x06f4, 0x06f5, 0x06f6, 0x06f7, /* 0x0590-0x0597 */ + 0x06f8, 0x06f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x0598-0x059f */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x066a, 0x0670, 0x0679, /* 0x05a0-0x05a7 */ - 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */ - 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */ - 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */ - 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */ - 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */ - 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */ - 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */ - 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */ - 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */ - 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */ - 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */ + 0x067e, 0x0686, 0x0688, 0x0691, 0x060c, 0x0000, 0x06d4, 0x0000, /* 0x05ac-0x05af */ + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, /* 0x05b0-0x05b7 */ + 0x0668, 0x0669, 0x0000, 0x061b, 0x0000, 0x0000, 0x0000, 0x061f, /* 0x05b8-0x05bf */ + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, /* 0x05c0-0x05c7 */ + 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f, /* 0x05c8-0x05cf */ + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, /* 0x05d0-0x05d7 */ + 0x0638, 0x0639, 0x063a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x05d8-0x05df */ + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, /* 0x05e0-0x05e7 */ + 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, /* 0x05e8-0x05ef */ + 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0698, 0x06a4, /* 0x05f0-0x05f7 */ + 0x06a9, 0x06af, 0x06ba, 0x06be, 0x06cc, 0x06d2, 0x06c1 /* 0x05f8-0x05fe */ }; -static unsigned short const keysym_to_unicode_680_6ff[] = { - 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */ - 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */ - 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */ - 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */ - 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */ - 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */ - 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */ - 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */ - 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */ - 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */ - 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */ - 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */ - 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */ - 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */ - 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */ - 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */ +static unsigned short keysym_to_unicode_680_6ff[] = { + 0x0492, 0x0496, 0x049a, 0x049c, 0x04a2, 0x04ae, 0x04b0, 0x04b2, /* 0x0680-0x0687 */ + 0x04b6, 0x04b8, 0x04ba, 0x0000, 0x04d8, 0x04e2, 0x04e8, 0x04ee, /* 0x0688-0x068f */ + 0x0493, 0x0497, 0x049b, 0x049d, 0x04a3, 0x04af, 0x04b1, 0x04b3, /* 0x0690-0x0697 */ + 0x04b7, 0x04b9, 0x04bb, 0x0000, 0x04d9, 0x04e3, 0x04e9, 0x04ef, /* 0x0698-0x069f */ + 0x0000, 0x0452, 0x0453, 0x0451, 0x0454, 0x0455, 0x0456, 0x0457, /* 0x06a0-0x06a7 */ + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x0491, 0x045e, 0x045f, /* 0x06a8-0x06af */ + 0x2116, 0x0402, 0x0403, 0x0401, 0x0404, 0x0405, 0x0406, 0x0407, /* 0x06b0-0x06b7 */ + 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x0490, 0x040e, 0x040f, /* 0x06b8-0x06bf */ + 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, /* 0x06c0-0x06c7 */ + 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, /* 0x06c8-0x06cf */ + 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, /* 0x06d0-0x06d7 */ + 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a, /* 0x06d8-0x06df */ + 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, /* 0x06e0-0x06e7 */ + 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, /* 0x06e8-0x06ef */ + 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, /* 0x06f0-0x06f7 */ + 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a /* 0x06f8-0x06ff */ }; static unsigned short const keysym_to_unicode_7a1_7f9[] = { - 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */ - 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */ - 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */ - 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */ - 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */ - 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */ - 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */ - 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */ - 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */ - 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */ - 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */ - 0x03c8, 0x03c9 /* 0x07f8-0x07ff */ + 0x0386, 0x0388, 0x0389, 0x038a, 0x03aa, 0x0000, 0x038c, /* 0x07a0-0x07a7 */ + 0x038e, 0x03ab, 0x0000, 0x038f, 0x0000, 0x0000, 0x0385, 0x2015, /* 0x07a8-0x07af */ + 0x0000, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03ca, 0x0390, 0x03cc, /* 0x07b0-0x07b7 */ + 0x03cd, 0x03cb, 0x03b0, 0x03ce, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07b8-0x07bf */ + 0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, /* 0x07c0-0x07c7 */ + 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, /* 0x07c8-0x07cf */ + 0x03a0, 0x03a1, 0x03a3, 0x0000, 0x03a4, 0x03a5, 0x03a6, 0x03a7, /* 0x07d0-0x07d7 */ + 0x03a8, 0x03a9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x07d8-0x07df */ + 0x0000, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, /* 0x07e0-0x07e7 */ + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, /* 0x07e8-0x07ef */ + 0x03c0, 0x03c1, 0x03c3, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, /* 0x07f0-0x07f7 */ + 0x03c8, 0x03c9 /* 0x07f8-0x07ff */ }; static unsigned short const keysym_to_unicode_8a4_8fe[] = { - 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */ - 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */ - 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */ - 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x22a2, 0x0000, /* 0x08c8-0x08cf */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */ - 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e8-0x08ef */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */ - 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */ + 0x2320, 0x2321, 0x0000, 0x231c, /* 0x08a0-0x08a7 */ + 0x231d, 0x231e, 0x231f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08a8-0x08af */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08b0-0x08b7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x2264, 0x2260, 0x2265, 0x222b, /* 0x08b8-0x08bf */ + 0x2234, 0x0000, 0x221e, 0x0000, 0x0000, 0x2207, 0x0000, 0x0000, /* 0x08c0-0x08c7 */ + 0x2245, 0x2246, 0x0000, 0x0000, 0x0000, 0x0000, 0x21d2, 0x0000, /* 0x08c8-0x08cf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x221a, 0x0000, /* 0x08d0-0x08d7 */ + 0x0000, 0x0000, 0x2282, 0x2283, 0x2229, 0x222a, 0x2227, 0x2228, /* 0x08d8-0x08df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x08e0-0x08e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2202, /* 0x08e8-0x08ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0192, 0x0000, /* 0x08f0-0x08f7 */ + 0x0000, 0x0000, 0x0000, 0x2190, 0x2191, 0x2192, 0x2193 /* 0x08f8-0x08ff */ }; static unsigned short const keysym_to_unicode_9df_9f8[] = { - 0x2422, /* 0x09d8-0x09df */ - 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */ - 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */ - 0x2502 /* 0x09f8-0x09ff */ + 0x2422, /* 0x09d8-0x09df */ + 0x2666, 0x25a6, 0x2409, 0x240c, 0x240d, 0x240a, 0x0000, 0x0000, /* 0x09e0-0x09e7 */ + 0x240a, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x2500, /* 0x09e8-0x09ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x251c, 0x2524, 0x2534, 0x252c, /* 0x09f0-0x09f7 */ + 0x2502 /* 0x09f8-0x09ff */ }; static unsigned short const keysym_to_unicode_aa1_afe[] = { - 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */ - 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */ - 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */ - 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */ - 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */ - 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */ - 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x0000, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */ - 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */ - 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */ - 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */ - 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */ - 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */ + 0x2003, 0x2002, 0x2004, 0x2005, 0x2007, 0x2008, 0x2009, /* 0x0aa0-0x0aa7 */ + 0x200a, 0x2014, 0x2013, 0x0000, 0x0000, 0x0000, 0x2026, 0x2025, /* 0x0aa8-0x0aaf */ + 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, /* 0x0ab0-0x0ab7 */ + 0x2105, 0x0000, 0x0000, 0x2012, 0x2039, 0x2024, 0x203a, 0x0000, /* 0x0ab8-0x0abf */ + 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e, 0x0000, /* 0x0ac0-0x0ac7 */ + 0x0000, 0x2122, 0x2120, 0x0000, 0x25c1, 0x25b7, 0x25cb, 0x25ad, /* 0x0ac8-0x0acf */ + 0x2018, 0x2019, 0x201c, 0x201d, 0x211e, 0x2030, 0x2032, 0x2033, /* 0x0ad0-0x0ad7 */ + 0x0000, 0x271d, 0x0000, 0x220e, 0x25c2, 0x2023, 0x25cf, 0x25ac, /* 0x0ad8-0x0adf */ + 0x25e6, 0x25ab, 0x25ae, 0x25b5, 0x25bf, 0x2606, 0x2022, 0x25aa, /* 0x0ae0-0x0ae7 */ + 0x25b4, 0x25be, 0x261a, 0x261b, 0x2663, 0x2666, 0x2665, 0x0000, /* 0x0ae8-0x0aef */ + 0x2720, 0x2020, 0x2021, 0x2713, 0x2612, 0x266f, 0x266d, 0x2642, /* 0x0af0-0x0af7 */ + 0x2640, 0x2121, 0x2315, 0x2117, 0x2038, 0x201a, 0x201e /* 0x0af8-0x0aff */ }; /* none of the APL keysyms match the Unicode characters */ static unsigned short const keysym_to_unicode_cdf_cfa[] = { - 0x2017, /* 0x0cd8-0x0cdf */ - 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */ - 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */ - 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */ - 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */ + 0x2017, /* 0x0cd8-0x0cdf */ + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, /* 0x0ce0-0x0ce7 */ + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, /* 0x0ce8-0x0cef */ + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, /* 0x0cf0-0x0cf7 */ + 0x05e8, 0x05e9, 0x05ea /* 0x0cf8-0x0cff */ }; static unsigned short const keysym_to_unicode_da1_df9[] = { - 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */ - 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */ - 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */ - 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */ - 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */ - 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */ - 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */ - 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */ - 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */ - 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */ - 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */ - 0x0e58, 0x0e59 /* 0x0df8-0x0dff */ + 0x0e01, 0x0e02, 0x0e03, 0x0e04, 0x0e05, 0x0e06, 0x0e07, /* 0x0da0-0x0da7 */ + 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, /* 0x0da8-0x0daf */ + 0x0e10, 0x0e11, 0x0e12, 0x0e13, 0x0e14, 0x0e15, 0x0e16, 0x0e17, /* 0x0db0-0x0db7 */ + 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, /* 0x0db8-0x0dbf */ + 0x0e20, 0x0e21, 0x0e22, 0x0e23, 0x0e24, 0x0e25, 0x0e26, 0x0e27, /* 0x0dc0-0x0dc7 */ + 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, /* 0x0dc8-0x0dcf */ + 0x0e30, 0x0e31, 0x0e32, 0x0e33, 0x0e34, 0x0e35, 0x0e36, 0x0e37, /* 0x0dd0-0x0dd7 */ + 0x0e38, 0x0e39, 0x0e3a, 0x0000, 0x0000, 0x0000, 0x0e3e, 0x0e3f, /* 0x0dd8-0x0ddf */ + 0x0e40, 0x0e41, 0x0e42, 0x0e43, 0x0e44, 0x0e45, 0x0e46, 0x0e47, /* 0x0de0-0x0de7 */ + 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c, 0x0e4d, 0x0000, 0x0000, /* 0x0de8-0x0def */ + 0x0e50, 0x0e51, 0x0e52, 0x0e53, 0x0e54, 0x0e55, 0x0e56, 0x0e57, /* 0x0df0-0x0df7 */ + 0x0e58, 0x0e59 /* 0x0df8-0x0dff */ }; static unsigned short const keysym_to_unicode_ea0_eff[] = { - 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */ - 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */ - 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */ - 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */ - 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */ - 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */ - 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */ - 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */ - 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */ - 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */ - 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */ - 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */ + 0x0000, 0x1101, 0x1101, 0x11aa, 0x1102, 0x11ac, 0x11ad, 0x1103, /* 0x0ea0-0x0ea7 */ + 0x1104, 0x1105, 0x11b0, 0x11b1, 0x11b2, 0x11b3, 0x11b4, 0x11b5, /* 0x0ea8-0x0eaf */ + 0x11b6, 0x1106, 0x1107, 0x1108, 0x11b9, 0x1109, 0x110a, 0x110b, /* 0x0eb0-0x0eb7 */ + 0x110c, 0x110d, 0x110e, 0x110f, 0x1110, 0x1111, 0x1112, 0x1161, /* 0x0eb8-0x0ebf */ + 0x1162, 0x1163, 0x1164, 0x1165, 0x1166, 0x1167, 0x1168, 0x1169, /* 0x0ec0-0x0ec7 */ + 0x116a, 0x116b, 0x116c, 0x116d, 0x116e, 0x116f, 0x1170, 0x1171, /* 0x0ec8-0x0ecf */ + 0x1172, 0x1173, 0x1174, 0x1175, 0x11a8, 0x11a9, 0x11aa, 0x11ab, /* 0x0ed0-0x0ed7 */ + 0x11ac, 0x11ad, 0x11ae, 0x11af, 0x11b0, 0x11b1, 0x11b2, 0x11b3, /* 0x0ed8-0x0edf */ + 0x11b4, 0x11b5, 0x11b6, 0x11b7, 0x11b8, 0x11b9, 0x11ba, 0x11bb, /* 0x0ee0-0x0ee7 */ + 0x11bc, 0x11bd, 0x11be, 0x11bf, 0x11c0, 0x11c1, 0x11c2, 0x0000, /* 0x0ee8-0x0eef */ + 0x0000, 0x0000, 0x1140, 0x0000, 0x0000, 0x1159, 0x119e, 0x0000, /* 0x0ef0-0x0ef7 */ + 0x11eb, 0x0000, 0x11f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x20a9, /* 0x0ef8-0x0eff */ }; -static unsigned short const keysym_to_unicode_12a1_12fe[] = { - 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */ - 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */ - 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */ - 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */ - 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */ - 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */ +static unsigned short keysym_to_unicode_12a1_12fe[] = { + 0x1e02, 0x1e03, 0x0000, 0x0000, 0x0000, 0x1e0a, 0x0000, /* 0x12a0-0x12a7 */ + 0x1e80, 0x0000, 0x1e82, 0x1e0b, 0x1ef2, 0x0000, 0x0000, 0x0000, /* 0x12a8-0x12af */ + 0x1e1e, 0x1e1f, 0x0000, 0x0000, 0x1e40, 0x1e41, 0x0000, 0x1e56, /* 0x12b0-0x12b7 */ + 0x1e81, 0x1e57, 0x1e83, 0x1e60, 0x1ef3, 0x1e84, 0x1e85, 0x1e61, /* 0x12b8-0x12bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c0-0x12c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12c8-0x12cf */ + 0x0174, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6a, /* 0x12d0-0x12d7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0176, 0x0000, /* 0x12d8-0x12df */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e0-0x12e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x12e8-0x12ef */ + 0x0175, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e6b, /* 0x12f0-0x12f7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0177 /* 0x12f0-0x12ff */ }; static unsigned short const keysym_to_unicode_13bc_13be[] = { - 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */ + 0x0152, 0x0153, 0x0178 /* 0x13b8-0x13bf */ }; -static unsigned short const keysym_to_unicode_14a1_14ff[] = { - 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */ - 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */ - 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */ - 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */ - 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */ - 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */ - 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */ - 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */ - 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */ - 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */ - 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */ - 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */ +static unsigned short keysym_to_unicode_14a1_14ff[] = { + 0x2741, 0x00a7, 0x0589, 0x0029, 0x0028, 0x00bb, 0x00ab, /* 0x14a0-0x14a7 */ + 0x2014, 0x002e, 0x055d, 0x002c, 0x2013, 0x058a, 0x2026, 0x055c, /* 0x14a8-0x14af */ + 0x055b, 0x055e, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, /* 0x14b0-0x14b7 */ + 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, /* 0x14b8-0x14bf */ + 0x0538, 0x0568, 0x0539, 0x0569, 0x053a, 0x056a, 0x053b, 0x056b, /* 0x14c0-0x14c7 */ + 0x053c, 0x056c, 0x053d, 0x056d, 0x053e, 0x056e, 0x053f, 0x056f, /* 0x14c8-0x14cf */ + 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, /* 0x14d0-0x14d7 */ + 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, /* 0x14d8-0x14df */ + 0x0548, 0x0578, 0x0549, 0x0579, 0x054a, 0x057a, 0x054b, 0x057b, /* 0x14e0-0x14e7 */ + 0x054c, 0x057c, 0x054d, 0x057d, 0x054e, 0x057e, 0x054f, 0x057f, /* 0x14e8-0x14ef */ + 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, /* 0x14f0-0x14f7 */ + 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x2019, 0x0027, /* 0x14f8-0x14ff */ }; -static unsigned short const keysym_to_unicode_15d0_15f6[] = { - 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */ - 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */ - 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */ - 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */ - 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */ +static unsigned short keysym_to_unicode_15d0_15f6[] = { + 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, /* 0x15d0-0x15d7 */ + 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, /* 0x15d8-0x15df */ + 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, /* 0x15e0-0x15e7 */ + 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, /* 0x15e8-0x15ef */ + 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6 /* 0x15f0-0x15f7 */ }; -static unsigned short const keysym_to_unicode_16a0_16f6[] = { - 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */ - 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */ - 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */ - 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */ - 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */ - 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */ +static unsigned short keysym_to_unicode_16a0_16f6[] = { + 0x0000, 0x0000, 0xf0a2, 0x1e8a, 0x0000, 0xf0a5, 0x012c, 0xf0a7, /* 0x16a0-0x16a7 */ + 0xf0a8, 0x01b5, 0x01e6, 0x0000, 0x0000, 0x0000, 0x0000, 0x019f, /* 0x16a8-0x16af */ + 0x0000, 0x0000, 0xf0b2, 0x1e8b, 0x01d1, 0xf0b5, 0x012d, 0xf0b7, /* 0x16b0-0x16b7 */ + 0xf0b8, 0x01b6, 0x01e7, 0x0000, 0x0000, 0x01d2, 0x0000, 0x0275, /* 0x16b8-0x16bf */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018f, 0x0000, /* 0x16c0-0x16c7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16c8-0x16cf */ + 0x0000, 0x1e36, 0xf0d2, 0xf0d3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d0-0x16d7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16d8-0x16df */ + 0x0000, 0x1e37, 0xf0e2, 0xf0e3, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e0-0x16e7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 0x16e8-0x16ef */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259 /* 0x16f0-0x16f6 */ }; static unsigned short const keysym_to_unicode_1e9f_1eff[] = { - 0x0303, - 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */ - 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */ - 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */ - 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */ - 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */ - 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */ - 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */ - 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */ - 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */ - 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */ - 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */ - 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */ + 0x0303, + 0x1ea0, 0x1ea1, 0x1ea2, 0x1ea3, 0x1ea4, 0x1ea5, 0x1ea6, 0x1ea7, /* 0x1ea0-0x1ea7 */ + 0x1ea8, 0x1ea9, 0x1eaa, 0x1eab, 0x1eac, 0x1ead, 0x1eae, 0x1eaf, /* 0x1ea8-0x1eaf */ + 0x1eb0, 0x1eb1, 0x1eb2, 0x1eb3, 0x1eb4, 0x1eb5, 0x1eb6, 0x1eb7, /* 0x1eb0-0x1eb7 */ + 0x1eb8, 0x1eb9, 0x1eba, 0x1ebb, 0x1ebc, 0x1ebd, 0x1ebe, 0x1ebf, /* 0x1eb8-0x1ebf */ + 0x1ec0, 0x1ec1, 0x1ec2, 0x1ec3, 0x1ec4, 0x1ec5, 0x1ec6, 0x1ec7, /* 0x1ec0-0x1ec7 */ + 0x1ec8, 0x1ec9, 0x1eca, 0x1ecb, 0x1ecc, 0x1ecd, 0x1ece, 0x1ecf, /* 0x1ec8-0x1ecf */ + 0x1ed0, 0x1ed1, 0x1ed2, 0x1ed3, 0x1ed4, 0x1ed5, 0x1ed6, 0x1ed7, /* 0x1ed0-0x1ed7 */ + 0x1ed8, 0x1ed9, 0x1eda, 0x1edb, 0x1edc, 0x1edd, 0x1ede, 0x1edf, /* 0x1ed8-0x1edf */ + 0x1ee0, 0x1ee1, 0x1ee2, 0x1ee3, 0x1ee4, 0x1ee5, 0x1ee6, 0x1ee7, /* 0x1ee0-0x1ee7 */ + 0x1ee8, 0x1ee9, 0x1eea, 0x1eeb, 0x1eec, 0x1eed, 0x1eee, 0x1eef, /* 0x1ee8-0x1eef */ + 0x1ef0, 0x1ef1, 0x0300, 0x0301, 0x1ef4, 0x1ef5, 0x1ef6, 0x1ef7, /* 0x1ef0-0x1ef7 */ + 0x1ef8, 0x1ef9, 0x01a0, 0x01a1, 0x01af, 0x01b0, 0x0309, 0x0323 /* 0x1ef8-0x1eff */ }; static unsigned short const keysym_to_unicode_20a0_20ac[] = { - 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */ - 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ + 0x20a0, 0x20a1, 0x20a2, 0x20a3, 0x20a4, 0x20a5, 0x20a6, 0x20a7, /* 0x20a0-0x20a7 */ + 0x20a8, 0x20a9, 0x20aa, 0x20ab, 0x20ac /* 0x20a8-0x20af */ }; unsigned int @@ -302,49 +301,50 @@ X11_KeySymToUcs4(KeySym keysym) return (keysym & 0x00ffffff); if (keysym > 0 && keysym < 0x100) - return keysym; + return keysym; else if (keysym > 0x1a0 && keysym < 0x200) - return keysym_to_unicode_1a1_1ff[keysym - 0x1a1]; + return keysym_to_unicode_1a1_1ff[keysym - 0x1a1]; else if (keysym > 0x2a0 && keysym < 0x2ff) - return keysym_to_unicode_2a1_2fe[keysym - 0x2a1]; + return keysym_to_unicode_2a1_2fe[keysym - 0x2a1]; else if (keysym > 0x3a1 && keysym < 0x3ff) - return keysym_to_unicode_3a2_3fe[keysym - 0x3a2]; + return keysym_to_unicode_3a2_3fe[keysym - 0x3a2]; else if (keysym > 0x4a0 && keysym < 0x4e0) - return keysym_to_unicode_4a1_4df[keysym - 0x4a1]; + return keysym_to_unicode_4a1_4df[keysym - 0x4a1]; else if (keysym > 0x589 && keysym < 0x5ff) - return keysym_to_unicode_590_5fe[keysym - 0x590]; + return keysym_to_unicode_590_5fe[keysym - 0x590]; else if (keysym > 0x67f && keysym < 0x700) - return keysym_to_unicode_680_6ff[keysym - 0x680]; + return keysym_to_unicode_680_6ff[keysym - 0x680]; else if (keysym > 0x7a0 && keysym < 0x7fa) - return keysym_to_unicode_7a1_7f9[keysym - 0x7a1]; + return keysym_to_unicode_7a1_7f9[keysym - 0x7a1]; else if (keysym > 0x8a3 && keysym < 0x8ff) - return keysym_to_unicode_8a4_8fe[keysym - 0x8a4]; + return keysym_to_unicode_8a4_8fe[keysym - 0x8a4]; else if (keysym > 0x9de && keysym < 0x9f9) - return keysym_to_unicode_9df_9f8[keysym - 0x9df]; + return keysym_to_unicode_9df_9f8[keysym - 0x9df]; else if (keysym > 0xaa0 && keysym < 0xaff) - return keysym_to_unicode_aa1_afe[keysym - 0xaa1]; + return keysym_to_unicode_aa1_afe[keysym - 0xaa1]; else if (keysym > 0xcde && keysym < 0xcfb) - return keysym_to_unicode_cdf_cfa[keysym - 0xcdf]; + return keysym_to_unicode_cdf_cfa[keysym - 0xcdf]; else if (keysym > 0xda0 && keysym < 0xdfa) - return keysym_to_unicode_da1_df9[keysym - 0xda1]; + return keysym_to_unicode_da1_df9[keysym - 0xda1]; else if (keysym > 0xe9f && keysym < 0xf00) - return keysym_to_unicode_ea0_eff[keysym - 0xea0]; + return keysym_to_unicode_ea0_eff[keysym - 0xea0]; else if (keysym > 0x12a0 && keysym < 0x12ff) - return keysym_to_unicode_12a1_12fe[keysym - 0x12a1]; + return keysym_to_unicode_12a1_12fe[keysym - 0x12a1]; else if (keysym > 0x13bb && keysym < 0x13bf) - return keysym_to_unicode_13bc_13be[keysym - 0x13bc]; + return keysym_to_unicode_13bc_13be[keysym - 0x13bc]; else if (keysym > 0x14a0 && keysym < 0x1500) return keysym_to_unicode_14a1_14ff[keysym - 0x14a1]; else if (keysym > 0x15cf && keysym < 0x15f7) - return keysym_to_unicode_15d0_15f6[keysym - 0x15d0]; + return keysym_to_unicode_15d0_15f6[keysym - 0x15d0]; else if (keysym > 0x169f && keysym < 0x16f7) - return keysym_to_unicode_16a0_16f6[keysym - 0x16a0]; + return keysym_to_unicode_16a0_16f6[keysym - 0x16a0]; else if (keysym > 0x1e9e && keysym < 0x1f00) - return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; + return keysym_to_unicode_1e9f_1eff[keysym - 0x1e9f]; else if (keysym > 0x209f && keysym < 0x20ad) - return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; + return keysym_to_unicode_20a0_20ac[keysym - 0x20a0]; else - return 0; + return 0; } #endif /* SDL_VIDEO_DRIVER_X11 */ + diff --git a/Engine/lib/sdl/src/video/x11/imKStoUCS.h b/Engine/lib/sdl/src/video/x11/imKStoUCS.h index cc684c2e3..fe4381d98 100644 --- a/Engine/lib/sdl/src/video/x11/imKStoUCS.h +++ b/Engine/lib/sdl/src/video/x11/imKStoUCS.h @@ -1,29 +1,30 @@ #ifndef _imKStoUCS_h #define _imKStoUCS_h -/* Copyright (C) 1994-2003 The XFree86 Project, Inc. All Rights Reserved. +/* +Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett +Copyright © 2009 Red Hat, Inc. +Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates. +All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is fur- -nished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- -NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- -NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of the XFree86 Project shall not -be used in advertising or otherwise to promote the sale, use or other deal- -ings in this Software without prior written authorization from the XFree86 -Project. +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. */ extern unsigned int X11_KeySymToUcs4(KeySym keysym);