From e8156c6b688b7aab8ef27eb6a57a6f106f02af5b Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Thu, 28 Apr 2022 20:02:38 +0100 Subject: [PATCH] SDL 2.0.22 (#46) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make Win32 fullscreen and borderless windows minimizable * reduced a few ifdefs, fixed an unused warning if built w/o SDL_HAVE_YUV. * rawinput: Fix double detection of gamepads on some 3rd party X360 wireless receivers The name that the Raw Input joystick driver pulls from the HID stack comes from USB string descriptors contained on the device. For official wireless receivers, this always contains "Xbox 360 Wireless Receiver for Windows" which matches the friendly name that WGI provides. 3rd party Xbox 360 wireless receivers may have different strings in their USB string descriptors (one uses "XBOX 360 For Windows" instead). This fails to match WGI's name and causes Raw Input and WGI to both report the same gamepad. Since wireless Xbox 360 controllers seem to have a consistent VID/PID regardless of the adapter enumerating them, we can also match on that to catch these. The duplicate case reported to me was: Controller (XBOX 360 For Windows) - 030000005e040000a102000000007200 Xbox 360 Wireless Receiver for Windows - 030000005e0400000000000000007701 * Makefile.os2: fixed setting OS2DEBUG in CFLAGS. * minor os/2 clean-ups. * emscripten: Don't prevent default on filtered key events * IME Composition Truncation + SDL_IsTextInputShown + SDL_ClearComposition (#5398) * Fixes for IME Composition Truncation + Addition of SDL_ClearComposition, SDL_IsTextInputShown * Fixed: Documentation and code style issues raised during code review. * Sync wiki -> header * SDL_windowskeyboard.c (IME_IsTextInputShown): remove unused local vars. * cmake: Make test code use proper C main functions. Fixes #5021. * SDL_blit_N.c: removed duplicated const (fixes bug #5401) * SDL_endian.h: use endian predefs from newer gcc and clang versions. Closes: https://github.com/libsdl-org/SDL/pull/5403 * Android: add comment to set render target to NULL when going to background (bug #4041) * Make SDL_VIDEO_OPENGL_EGL optional on Android * Fixed: Incorrect assumption that mouse button is released when window is allocated * SDL_audiocvt.c: Don't byteswap 8-bit streams Otherwise, this results an assert on big endian machines when attenpting to use SDL_LoadWAV_RW function to load 8-bit WAV files. * METAL: clip rect w/h must be <= render pass * Fix name of macOS platform and link to README file * Fixed bug #2199: make SDL_blit_slow handles SDL_PIXELFORMAT_ARGB2101010, storing as RGBA * Fixed bug #2691 - re-enable surface_testCompleteSurfaceConversion for ARGB2101010 * INSTALL.txt: Say "macOS" instead of "Mac OS X" in modern times. Reference Issue #5407. * SDL_windowskeyboard.c: fix build with SDL_DISABLE_WINDOWS_IME defined. Fixes https://github.com/libsdl-org/SDL/issues/5408 * minor whitespace cleanup. * SDL_audiocvt.c: minor cleanup. * Adjust gradle dependencies to enable the build to position assets for the APK * emscripten: obey enable-misc/SDL_MISC settings * minor optimization (SDL_audiocvt.c) * imported two libtool mainstream commits 28fbcb6a and b55b1cc8 * Remove 'reserved identifier' warning * SDL_blit_slow: remove one nested 'if()' because of ARGB2101010 handling * SDL_triangle_blit_slow: sync code with SDL_blit_slow to handle ARGB2101010 * SDL_GetBasePath() fixes for OS/2 * use _Static_assert for SDL_COMPILE_TIME_ASSERT(), when available * testplatform.c: move static asserts out of TestTypes(). * simplify SetDSerror - no need to keep the error in a static variable - always print the error code - reduce the required stack-size - reduce the number of snprintf calls (and code size) * Fixed build when events are disabled Fixes https://github.com/libsdl-org/SDL/issues/5413 * Removed problematic call to ISensor_SetEventSink() Fixes https://github.com/libsdl-org/SDL/issues/5288 * Fixed warnings when building with cygwin Fixes https://github.com/libsdl-org/SDL/issues/5025 * SDL_cocoawindow.m: update fullscreen toggle when SDL_SetWindowResizable called * Ignore unknown WM_SIZE types. According to MSDN, we can also get SIZE_MAXHIDE and SIZE_MAXSHOW, based on state changes to other windows. It's not clear under what circumstances this will happen (I saw some docs indicating it may require multiple application windows), but it doesn't seem right to treat them as RESTORED. * Fix relative mouse input for Unvanquished (unvanquished.net) Here's an IRC dump that hopefully explains the issue this fixes: > I'm debugging something odd where, for a libre game, unvanquished.net (a FPS), relative mouse input in fullscreen is buggy > it's like, working mostly ok, but it has a weird performance/cleanup bug > after some time in relative mouse input mode, some time as low as 15s, usually more, the SDL sends A LOT of relative mouse input per frame > almost all of which have xrel==0 && yrel==0 > by A LOT, I mean that after ~1min, it's usually in the thousands per frame > each frame, a while ( SDL_PollEvent( &e)) loop reads the inputs, but it seems SDL is not clearing the list. > one way to clear the list is to open the in-game console or menu, which switches the input mode to absolute, then close it which gets a working relative input mode (for some time at least) > I've shown the issue to be present with SDL2.0.20 but not with 2.0.14 on my system > some other players on Arch Linux (SDL2.0.20) report a possibly related issue, where some keys seem to be pressed at random > I've did some bisection on SDL master, and I've found that there are actually two commits involved, one breaking it totally (no input at all), and one fixing it partially (with the problem described above) First related commit that breaks it totally: commit 82793ac279d19b5bde8fc2bd62877b05ba5a76e0 Author: Sam Lantinga Date: Thu Oct 14 14:26:21 2021 -0700 Fixed mouse warping while in relative mode We should get a mouse event with an absolute position and no relative motion and shouldn't change the OS cursor position at all Second related commit, that halfway fixes it: commit 31f8c3ef4409a93fafa894b78c2ce176bd0c3cf3 Author: Sam Lantinga Date: Thu Jan 6 11:27:44 2022 -0800 Fixed event pump starvation if the application frequently pushes its own events Reverting the first commit did fix the issue for me, but would probably reintroduce the bug it was fixing(?). This patch should fix it for everyone hopefully. https://github.com/DaemonEngine/Daemon/issues/600 is the upstream bug, and contains some early investigation. * Don't warn if anyone peeps for events after quitting the event subsystem Fixes https://github.com/libsdl-org/SDL/issues/5013 * video: Add a hint to allow Vulkan surfaces on foreign windows * Fixed compile warning and comment typo * Added a hint to mark a foreign window as usable with OpenGL Fixes https://github.com/libsdl-org/SDL/issues/2942 * When updating grab state, only activate windows that are grabbed, fullscreen, and shown. Fixes https://github.com/libsdl-org/SDL/issues/5371 * Try not forcing activation when grabbing the mouse in fullscreen windows * Workaround for bug in Microsoft WGI support Fixes https://github.com/libsdl-org/SDL/issues/5270 * Use SDL_Log instead of printf * Added a hint to capture the mouse when mouse buttons are pressed, defaulting on Fixes https://github.com/libsdl-org/SDL/issues/5301 * Fixed memory leak in WIN_CreateBlankCursor() * Fixed freeing the Windows blank cursor * Start rumbling once a raw input controller has been correlated Fixes https://github.com/libsdl-org/SDL/issues/5351 * Modern CMake doesn't need "LANGUAGE C" for Objective-C CMake 3.19 fails to compile Objective-C with that property set Fixes https://github.com/libsdl-org/SDL/issues/5418 * Added the hint SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, controlling whether the mouse should be constrained to the center of the window or the whole window in relative mode. For further info about the pros and cons, check out the discussion in https://github.com/libsdl-org/SDL/issues/5271 * Added a note that SDL_RenderReadPixels() should be called before SDL_RenderPresent() * Sync wiki -> header * Fix "SDL_TRUE is not defined" runtime error for emscripten. * SDL_UnionRect: If both rects are empty, zero out the result struct. * SDL_Rect: minor code cleanups. * SDL_Rect: Added floating point versions of all the rectangle APIs. Fixes #5110. * Fix "SDL_FALSE is not defined" runtime error for emscripten. * Fixed Android crash when SDL_HIDAPI_DISABLED set to 1 The Java code needs the native functions to be implemented, even if they're not surfaced via the C API. Fixes https://github.com/libsdl-org/SDL/issues/5326 * Relative mouse mode is tied to the window with keyboard focus This isn't obvious, but makes sense when thinking about how games actually use it. This is also in line with how Windows mouse relative mode is implemented. Fixes https://github.com/libsdl-org/SDL/issues/5340 * Fixed parameter operation ordering for ease of reading * audio: Set error message on dsp init failure. if SDL_EnumUnixAudioDevices() fails to find any devices, set an error message on the exit path. Without this, SDL_Init() could fail without any message available in SDL_GetError(). * Sync wiki -> headers. * Fixed bug #2426 - SDL_RenderReadPixels result is unspecified and fails testautomation Call SDL_RenderPresent after calling SDL_RenderReadPixels. From "include/SDL_render.h": "If you're using this on the main rendering target, it should be called after rendering and before SDL_RenderPresent()." * Fixed bug #2962 - when SDL_RenderReadPixels format = 0, used format of the target texture include/SDL_render.h, format: "0 to use the format of the rendering target " * blit-auto optimizations * regenerated SDL_blit_auto.c. * Don't try to hide foreign windows when destroying the SDL window representation Fixes https://github.com/libsdl-org/SDL/issues/5432 * hints: Added SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE. Fixes #2349. * SDL_render.c: remove unsused case, since renderer target has been forced to NULL previously (see bug #4213) * Add mapping for Logitech Precision Gamepad * Also fix Android crash when SDL_HIDAPI_DISABLED set to 1 The Java code needs the native functions to be implemented, even if they're not surfaced via the C API, therefore, a stub version of functions were made only to the purpose of "fill the gaps" when SDL_HIDAPI_DISABLED set to 1. * use != '\0' comparison instead of SDL_strlen in the functions of SDL_getenv * make SDL_strcasecmp standard compliant * optimize the SDL_str(case)cmp functions * Avoid trying to use texture framebuffers on emscripten * stdlib: just cast iconv()'s 2nd arg to void *. This makes the compiler happy (enough) regardless of whether the C runtime headers think this argument should be const or not. Fixes #4966. * Fixed freeing a constant string (thanks @gnrlwart) * Android: add SetWindowResizable() implementation - which also enable/disable the orientation lock status. This is only provided when the window is not SDL_WINDOW_FULLSCREEN (see SDL_video.c). Final orientation also depends on SDL_HINT_ORIENTATIONS. * Video: do not use hardcoded VIVANTE and VDK libraries * Add SDL_RenderGetWindow() API to get the window associated with a renderer (#5440) Add SDL_RenderGetWindow() API to get the window associated with a renderer * Sync wiki -> header * wayland: Bump minimum requirement to wayland-client 1.18 or newer * wayland: The rest of the wayland-client 1.18 requirement... Git, please * wayland: Basic support for zwp_tablet_*v2 protocol * video: wayland: Use xdg-output for retrieving the desktop dimensions Using wl-output to get the desktop display dimensions and dividing by the integer scale factor will not return the correct result when using a desktop with fractional scaling (e.g. a 3840x2160 display at 150% will incorrectly report the scaled desktop area as 1920x1080 instead of 2560x1440). Use the xdg-output protocol, if available, to retrieve the correct desktop dimensions and offset. Versions 1 through 3 of the protocol are supported. * Vita: support audio format fallback * Vita: add native YUV textures support. * Fail if texture init fails. * Refactor and cleanup. * static analysis: Fixed several complaints from codechecker. There are still some pending Objective-C specific issues. Reference issue #4600. * add some Thrustmaster wheels * Fixed bug #1650: X11 doesn't set KMOD_NUM and KMOD_CAPS to system state * x11: Minor cleanups and corrections in X11_ShowMessageBox. Reference issue #3254. * Avoid depending on libwayland 1.20 unnecessarily When using shared linking (linking in the normal way with -lwayland-client) rather than loading Wayland libraries dynamically at runtime, listing symbols that don't exist in the current version results in a build failure. We don't actually call wl_proxy_marshal_flags() or wl_proxy_marshal_array_flags() directly; the reason we need them is that they're called by the code generated by wayland-scanner >= 1.20. If we're building against an older Wayland library, then we'll have its corresponding version of wayland-scanner (mismatched versions are not supported), so we won't need those two symbols, and can avoid generating a dependency on them. Conversely, if we're building against a newer Wayland library, the generated code will call them unconditionally, so we cannot treat them as optional and gracefully fall back: that would result in a crash. Instead, treat them as a mandatory part of the Wayland library, so that if they are not found at runtime, we can fall back to X11 without crashing. libwayland 1.18 is in several LTS distributions (Ubuntu 20.04, Debian 11, RHEL 8) so avoiding a hard dependency on 1.20 is quite useful. Signed-off-by: Simon McVittie Resolves: https://github.com/libsdl-org/SDL/issues/5376 * wayland: Don't overwrite error message from SDL_EGL_CreateSurface SDL_EGL_CreateSurface sets a more specific error message, so overwriting it would lose information. Signed-off-by: Simon McVittie * wayland: Minor fixes for old compilers * wayland: Remove some now-redundant casts * iOS >= 10.0 silence GLes deprecation warnings * wayland: Add an xkb_keysym_t->SDL_Keycode mapping for backspace * wayland: Enforce text capitalization manually, for remapped keymods * wayland: Use xkb_keymap_mod to set mod state * YUV: fix invalid read on last line when converting from SDL_PIXELFORMAT_YUY2 (see bug #4841) * Vita: Fix NULL-pointer dereference * wayland: Optimize keyboard_handle_modifiers. 1. Mod index values are (mostly) constant, so can be done with xkb_state_new 2. Mods can change without the group changing, avoid remap events if possible Lastly, as a bonus, I added braces to the locale check, because I was nearby. * Initialize compile status variable and check also program link status * testshader: use SDL_malloc instead of SDL_stack_alloc. * README-windows: Convert to actual Markdown text. * README-windows: Wordwrap text file. This makes for easier reading outside of a formal Markdown viewer. * README-windows: Notes on building with Visual Studio/LLVM. Fixes #5186. * wayland: Work around a GNOME xdg_output scaling issue * wayland: Avoid overwriting xdg_output position with wl_output position * wayland: Relax the check for mismatching output scales * configure: improvements to libdecor discovery : use PKG_CHECK_MODULES, and use DECOR_LIB with find_lib. Closes: https://github.com/libsdl-org/SDL/pull/5460 Co-authored-by: Trigan2025 * direct3d: Implement missing blend operations. This is only for Direct3D 9; Direct3D 11 already had this implemented. Fixes #5375. * Remove URLs from markdown headers in README-visualc.md * Clean up formatting in README-directfb.md * testgles2: Call correct function to get shader info log and add link status checking * Sync wiki -> header * Sync wiki -> header * Vita: Use preallocated memory pool for textures * Sync wiki -> header * Correct default structure packing on Windows ARM64 See issue #5454 for details * Fix potential memory leak in QueueCmdFillRects * Vita: add hint to select which touchpad generates mouse events * emscriptenaudio: proxy calls to main thread * video: wayland: Use wp-viewporter for fullscreen with non-native resolutions Wayland doesn't support mode switching, however Wayland compositors can support the wp_viewporter protocol, which allows for the mapping of arbitrarily sized buffer regions to output surfaces. Use this functionality, when available, for fullscreen output when using non-native display modes and/or when dealing with scaled desktops, which can incur significant overdraw without this extension. This also allows for the exposure of arbitrarily sized, emulated display modes, which can be useful for legacy compatability. * wayland: Minor fix for old compilers * video: wayland: Expose more resolutions for mode emulation Expose as many emulated display modes as possible. They will currently display stretched to the display's native desktop aspect, but if an application requires a hardcoded resolution, it will work at minimum. Aside from the change in the emulated display mode list, the Wayland event handling code had to be updated to support separate scaling for the x and y axes, as square pixels are no longer guaranteed. * video: wayland: Use viewports for non-fullscreen windows with fractional scaling Use viewports for non-fullscreen windows when the desktop uses fractional scaling and the window is flagged as DPI-aware to provide a backbuffer mapped as close to 1:1 output as possible. In the cases of odd window sizes the backbuffer may be a pixel off of scaling perfectly into the window size due to its scaled size being rounded off, but a minute amount of scaling during output is likely preferable to the large amounts of overdraw needed with integer scaled buffers. * Vita: add audio capture support * Vita: add SDL_GetPreferredLocales support * stdinc: SDL_COMPILE_TIME_ASSERT defines shouldn't have a semicolon. * x11: Catch X11 errors in X11_SetWindowPosition and X11_SetWindowSize. The functions can go south if other operations are in progress, like X11_SetWindowBordered, which might be doing something traumatic behind the scenes of the window manager. We can't make these tasks totally synchronous, which would fix the problem, because not only can the window manager block however long it wants, it might also decide to deny our requests without any notification, so we'd be waiting forever for a window change that isn't coming. :( Fixes #5274. * joystick: Fix rumble issues on PS5 HIDAPI controllers We were returning the report size from HIDAPI_DriverPS5_RumbleJoystick() rather than 0 upon success, causing SDL_JoystickRumble() (and callers) to think that rumbling failed. This didn't cause major problems until 1868c5b, when it started preventing rumble state from being persisted in the joystick core, even though it was successfully sent to the hardware. This led to all sorts of strangeness, including broken rumble duration and attempts to stop rumble being discarded. * Desktop OpenGL 1.X/2.X PSVita Support * Update README-vita.md * Cleanup Spaces * Vita: PVROGL: fix indentation and ifdef guards * Vita: fix readme * x11: Ignore BadValue for extremely small XRRSetScreenSize resolutions. Reference Issue #4840. * SDL2 thread proxying fixes This PR uses new APIs added in [emscripten-core/emscripten#9336](https://github.com/emscripten-core/emscripten/pull/9336) to improve compatibility with USE_PTHREADS=1. Original PR: https://github.com/emscripten-ports/SDL2/pull/127 By: @jakogut Reviewed by: Daft-Freak * emscriptenmouse: remove old extra `_INT` * fix formatting and cast warnings Co-authored-by: Charlie Birks * emscriptenmouse: remove useless return statement * emscriptenframebuffer: fix formatting * emscripten: Proxy SDL_GetUsableDisplayBounds to the main thread. * Fixed loading 32-bit BMP files * Move SDL_List functions to SDL_list.c to avoid more merge with eventual PR * Add SDL_list.c/h * Add SDL_list to macosx xcode * Use RoInitialize/RoUninitialize for Windows.Gaming.Input Thanks @walbourn! Fixes https://github.com/libsdl-org/SDL/issues/5270 * fix build against older SDKs after commit 8ebef12. * check for HAVE_ROAPI_H in cmake and autotools, and update SDL_config_windows.h and SDL_config_winrt.h * attempt to fix uwp build * render: Fix setting the scale mode for non-native textures * Visualise scroll wheel events in testmouse * Minor cleanup * x11: Don't unload libGL.so to prevent a crash in XCloseDisplay() libGL.so may register callbacks that can be invoked upon XCloseDisplay(). If XCloseDisplay() is called after libGL.so is unloaded, the callback pointer will point at freed memory and invoking it will crash. The texture framebuffer check optimized out in f37e4a9 was causing libGL.so to never be unloaded as a side-effect. Skipping it exposed this bug by allowing libGL.so to actually unload. * x11: Wait a bit to see if window pos changes when changing fullscreen. Helps prevent window from moving to 0,0 when leaving fullscreen. Fixes #4749. * testgles2: Fix buffer object sizes * Added a define VERBOSE_MOTION_EVENTS to show mouse and finger motion events * Handle interaction between auto capture and the SDL_CaptureMouse() API Fixes https://github.com/libsdl-org/SDL/issues/5457 * Minor cleanup * IBus should use ev keycode instead of X keycode See: https://github.com/ibus/ibus/blob/5a455b1ead5d72483952356ddfe25b9e3b637e6f/client/gtk2/ibusimcontext.c#L468 * Ignore focus change messages that contradict GetForegroundWindow. On Wine, when a window is programmatically minimized in response to losing focus, we receive a WM_ACTIVATE for the deactivation, but GetForegroundWindow still indicates that our window is focused. This causes an incorrect SDL_WINDOWEVENT_FOCUS_GAINED. This is probably a Wine bug, but it may take a while to fix and then for the fix to make its way to users. * Don't resize fullscreen windows when hiding or minimizing them (thanks @madewokherd!) This has the benefit of window previews (mousing over the icon) having the correct size and contents. Fixes https://github.com/libsdl-org/SDL/issues/5320 * x11: when waiting on fullscreen changes, not window position _and_ size. This makes sure the window doesn't have outdated values if you try to access them (or call something that does, like SDL_SetWindowMinimumSize). Fixes #5233. * Send key release event to input method. (#5281) Co-authored-by: Ethan Lee * Cache the fact that a device didn't look like a joystick Fixes https://github.com/libsdl-org/SDL/issues/5211 * x11: Try to keep SDL_WINDOW_FULLSCREEN* in sync with window manager. So if Gnome/KDE/etc have a keyboard shortcut or titlebar decoration to make any window go fullscreen (with the _NET_WM_FULLSCREEN flag on the _NET_WM_STATE property), we update the SDL window flag. Fixes #5390. * Sort controllers by the js* index on Linux Also fixed the initial scan to directly scan devices instead of using udev so they can be sorted, as intended. Fixes https://github.com/libsdl-org/SDL/issues/4688 * wayland: Evaluate WINDOWPOS_CENTERED_DISPLAY for move events Partially fixes the mouse cursor in UE5 editor. Imperfect because UE5 uses window position and global mouse state to get position, but of course we don't have global mouse and this is just to get the right display index so this still fails overall. We really need to make global mouse support a feature query... * wayland: Try to detach at the beginning of ShowWindow, just in case. It's possible that an external component (probably a GL/VK context) committed, so we need to cover our bases and detach in both HideWindow and ShowWindow. Fixes a crash in UE5 editor's pop-ups. * wayland: Add a bug link for the detach FIXME * wayland: Pin the fake window position at (0, 0). I kind of thought it'd be nice to have it in the center, but this is an issue for applications that still assume global mouse and window positions are accessible. For example, this fixes cursor offset issues in UE5. * Makefile.in: added missing CXX variable. * Compile with recursive mutexes for emscripten Emscripten actually does support recursive mutexes, so no need to use SDL's fake recursive code. Background: #5428, #5479 * x11: Treat WM setting the window "fullscreen" like FULLSCREEN_DESKTOP. Fixes #5390. * Only update modifier state for keys that are pressed in another application Fixes https://github.com/libsdl-org/SDL/issues/4432 * minor adjustment to os/2 watcom makefile * Make sure the UIKit message box is being handled on the main thread Potentially fixes https://github.com/libsdl-org/SDL/issues/4865 * render: Update the size/scale/viewport on moves, in addition to resizes. For OpenGL this means resetting the viewport state shadowing flag too. Fixes #1504 * direct3d11: Set the swapchain target immediately after creating it. Fixes #4782 * video: wayland: Set the surface damage region when using fullscreen viewports When using emulated display modes, the output size is often larger than the drawable buffer. As the surface damage region is automatically calculated from the smaller drawable buffer size, the damage region needs to be manually set to cover the entire viewport region or visual repaint artifacts can result. * Fixed typo * Updated the patch notes with API changes for 2.0.22 * Update version to 2.0.22 for release * audio: SDL_ConvertStereoToMono_SSE3 missed an unaligned load. * UWP: Require Windows 10 16299 or newer. This is required to build with WGI support. Thanks for @FrozenChameleon for the fix! Fixes #5504 * Vita: fix VIDEO_VITA_PVR flag * fix os2 timer in fallback mode * testevdev: Recognise touchpads as such At the time I contributed this unit test, SDL didn't understand Linux touchpads, but now it does. Fixes: 373216ae "Added support for touchpads in the Linux evdev code" Signed-off-by: Simon McVittie * testevdev: Adapt to a broader definition of keyboards At the time I contributed this unit test, SDL had a relatively narrow definition of what is a keyboard, approximately matching udev ID_INPUT_KEYBOARD. Now it uses the equivalent of udev ID_INPUT_KEY, which matches anything with keyboard keys, and not just reasonably complete alphanumeric keyboards. Fixes: 040bd7a9 "Fix udev not detecting ID_INPUT_KEY devices when udev is not running" Signed-off-by: Simon McVittie * test: Copy utf8.txt to build directory testiconv wants this. Signed-off-by: Simon McVittie * Initialise scandir argument 'scandir' does not initialise 'entries' on error * Wayland: Add SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR This hint allows libdecor to be used even when xdg-decoration is available. It's mostly useful for debugging libdecor, but could in theory be used by applications which want to (for example) bundle their own libdecor plugins. * WhatsNew.txt: Added SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR * WhatsNew.txt: Document new dependency on libwayland-client 1.18.0 Signed-off-by: Simon McVittie * CI: update os2.yml to use open-watcom/setup-watcom also remove os2-buildbot.sh -- not needed anymore. * avoid NullPointer in SDL_GL_MakeCurrent * avoid NullPointer in SDL_GetRenderTarget * video: Wayland: Clamp fullscreen window dimensions to desktop A scaled fullscreen window may exceed the bounds of the desktop. Clamp the window size to the desktop dimensions in fullscreen mode. * video: Wayland: Always round scaled pointer coordinates down Rounding up can cause the pointer coordinates to exceed the window boundaries at the right and bottom edges. * x11: Update the display when the WM changes a window's fullscreen state. Fixes #5390. * Added CMake option to disable the installer * cmake: Fixed indenting and some oldschool `endif(TEXT)` things. * hints: Make SDL_VIDEODRIVER and SDL_AUDIODRIVER formal hints. They were just environment variables before. Fixes #5528. * Revert "video: Prefer Wayland over X11" This reverts commit 8ceba27d6291f1195e13608033ec439aec621fc6. SDL Wayland support is stable, but there are a number of issues with third-party software (NVIDIA drivers, libwayland event overflow, libdecor not handling plugin load failures, Steam overlay not working with Wayland, etc.) that make it better to default to X11 at this time. Games which would like to prefer wayland when available can use the following code before SDL_Init(): SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland,x11"); Fixes https://github.com/libsdl-org/SDL/issues/5527 * Certain audio drivers, like the RME "Pro" Audio driver, have resampling quality issues when using WASAPI. We'll use SDL's resampling algorithm so we have consistent quality between platforms and drivers. Fixes https://github.com/libsdl-org/SDL/issues/5538 * wayland: Add support for TOOLTIP/POPUP_MENU * video: Don't minimize fullscreen windows on focus loss by default when mode switching is disabled When mode switching is disabled in a video backend, fullscreen windows are basically just fullscreen desktop windows with different internal scaling. As no mode switching occurs, there's no need to minimize them on focus loss by default. This can still be overridden by explicitly setting the internal hint for minimizing on focus loss. This has the side effect of fixing a bug on GNOME, where, when a fullscreen Wayland window has it's focus lost and restored via alt+tab followed by switching back to windowed mode, the top portion of the window won't end up being obstructed by GNOME's top bar. * Added controller mapping for the Thrustmaster Dual Analog 3.2 on Linux * Enable evdev-based gamecontrollerdb on FreeBSD * simplify SDL_GetBasePath on windows - use GetModuleFileName directly (as recommended) * use explicit GetModuleFileNameW * Remove HWND_TOPMOST for fullscreen windows Fixes https://github.com/libsdl-org/SDL/issues/5509 * SDL_render.c: internally change viewport/cliprect type from SDL_FRect to SDL_DRect (double precision). (see bug #5547) * Don't call scandir() inside of scandir() This works around a crash in address sanitizer * Fixed compile warnings * x11: Revert "Fix keymap updating for X11 backend" This reverts commit de6d290266d1def0eef9df81bf9be41c12a98c61. This patch had multiple issues, discussed in #5520. * Fixed build * Fix recent changes in VitaSDK * SceKernelMemBlockType to unsigned int * Fix a -Wshadow warning * Remove an unused function prototype * WhatsNew.txt: Add SDL_FRectEqualsEpsilon() * Add SDL_FLT_EPSILON. * SDL_Rect: Use a default epsilon in SDL_FRectEquals() Add SDL_FRectEqualsEpsilon() for when more control over equality test is required. * test: Basic tests for SDL_FRectEquals Based on the integer version. These tests mostly check that input isn't mangled and that invalid input gives the expected negative result. * hidapi: Wrap CopyHIDDeviceInfo in define checks. The purpose of this is to silence a 'defined but not used' warning. * os2: SDL_DestroyMutex should ignore NULL mutexes. Every other backend does this, so this should match, now. It's possible this was harmless, but we can avoid the system call and the (likely?) debug message when it fails, though! * windows: Fix calling convention for RoInitialize/RoUninitialize Fixes #5563 * windows: Fix RoInitialize() failure after a CoInitializeEx() call using apartment threading This mirrors the same codepath in WIN_CoInitialize() which handles STA and MTA. * WGI: Keep a reference to the MTA to avoid crashing on COM teardown Fixes #5552 Fixes #5270 * WGI: Only call RoUninitialize() if RoInitialize() succeeded * Handle potential out of memory condition when working with hints * SDL_Rect: Add \sa documentation block to SDL_FRect * Return a correlation error when trigger rumble is attempted without correlation * Fixed build * SDL: sometimes the PS5 controller doesn't report having to power even when connected over USB. Possibly related to being completely charged? Either way we already know that it's USB or BT so let's use the driver's knowledge instead. * Added support for the Backbone One controller on iOS * Revert "Fix relative mouse input for Unvanquished (unvanquished.net)" This reverts commit 331859079674465a39b24f32a6a113959601dca3. Fixes https://github.com/libsdl-org/SDL/issues/5569 * hidapi, libusb: import mainstream commit 536bad201e * Fixed logical size synchronization issue on macOS https://discourse.libsdl.org/t/sdl-2-0-22-prerelease/35306/6 * x11: revert checks for _NET_WM_STATE_FULLSCREEN changes. This reverts commit 85977354fbce9ecb2add660a88e6bec3532c3e26. This reverts commit 0249df9d960f9bc28b476e1171c5501fc37cca12. Fixes #5572. Reopens #5390. Co-authored-by: Jo Bates Co-authored-by: Ozkan Sezer Co-authored-by: Cameron Gutman Co-authored-by: Charlie Birks Co-authored-by: Zach Reedy <86971250+zreedy@users.noreply.github.com> Co-authored-by: SDL Wiki Bot Co-authored-by: Ryan C. Gordon Co-authored-by: Sylvain Co-authored-by: Guus Waals <_@guusw.nl> Co-authored-by: Zach Reedy Co-authored-by: Wohlstand Co-authored-by: Sam Lantinga Co-authored-by: staphen Co-authored-by: pionere Co-authored-by: uyjulian Co-authored-by: Esme Povirk Co-authored-by: Antoine Fontaine Co-authored-by: Ethan Lee Co-authored-by: Christian Kündig Co-authored-by: Eddy Jansson Co-authored-by: Egor Co-authored-by: Jonatha Gabriel Co-authored-by: Joao Paulo Magalhaes Co-authored-by: Florian "sp1rit"​ Co-authored-by: Frank Praznik Co-authored-by: Ivan Epifanov Co-authored-by: Kimplul Co-authored-by: Simon McVittie Co-authored-by: DominusExult Co-authored-by: capehill Co-authored-by: Trigan2025 Co-authored-by: Cameron Cawley Co-authored-by: Mathieu Eyraud <70028899+meyraud705@users.noreply.github.com> Co-authored-by: Connor Clark Co-authored-by: Jaylon Gowie Co-authored-by: Reinhold Gschweicher Co-authored-by: Christoph Reichenbach Co-authored-by: Weng Xuetian Co-authored-by: David Gow Co-authored-by: Semphris Co-authored-by: Jan Beich --- CMakeLists.txt | 627 +++++---- INSTALL.txt | 4 +- Makefile.in | 3 +- Makefile.os2 | 20 +- Makefile.psp | 117 -- Makefile.wiz | 88 -- VisualC-WinRT/SDL-UWP.vcxproj | 10 +- VisualC-WinRT/SDL-UWP.vcxproj.filters | 8 +- VisualC/SDL/SDL.vcxproj | 2 + VisualC/SDL/SDL.vcxproj.filters | 2 + WhatsNew.txt | 38 + Xcode/SDL/Info-Framework.plist | 4 +- Xcode/SDL/SDL.xcodeproj/project.pbxproj | 46 +- acinclude/libtool.m4 | 2 +- android-project/app/build.gradle | 4 + android-project/app/jni/src/Android.mk | 2 +- .../main/java/org/libsdl/app/SDLActivity.java | 121 +- .../org/libsdl/app/SDLControllerManager.java | 38 +- build-scripts/ltmain.sh | 16 +- build-scripts/os2-buildbot.sh | 41 - build-scripts/winrtbuild.ps1 | 2 +- cmake/macros.cmake | 19 +- cmake/sdlchecks.cmake | 49 +- configure | 372 ++++-- configure.ac | 270 ++-- debian/changelog | 186 --- debian/compat | 1 - debian/control | 91 -- debian/copyright | 351 ----- debian/docs | 4 - debian/libsdl2-2.0-0-udeb.install | 1 - debian/libsdl2-2.0-0.install | 1 - debian/libsdl2-dev.install | 9 - debian/libsdl2-dev.manpages | 1 - debian/rules | 54 - debian/sdl2-config.1 | 86 -- debian/source/format | 1 - debian/watch | 2 - docs/README-android.md | 3 + docs/README-directfb.md | 42 +- docs/README-psp.md | 43 +- docs/README-visualc.md | 2 +- docs/README-vita.md | 5 +- docs/README-windows.md | 87 +- docs/README.md | 4 +- include/SDL_audio.h | 4 +- include/SDL_blendmode.h | 10 +- include/SDL_config.h | 2 - include/SDL_config.h.cmake | 10 + include/SDL_config.h.in | 15 +- include/SDL_config_emscripten.h | 1 + include/SDL_config_psp.h | 165 --- include/SDL_config_windows.h | 5 + include/SDL_config_winrt.h | 6 + include/SDL_config_wiz.h | 154 --- include/SDL_endian.h | 9 + include/SDL_events.h | 15 + include/SDL_gamecontroller.h | 5 +- include/SDL_hints.h | 216 ++- include/SDL_joystick.h | 6 +- include/SDL_keyboard.h | 21 + include/SDL_metal.h | 1 + include/SDL_rect.h | 156 ++- include/SDL_render.h | 28 +- include/SDL_stdinc.h | 19 + include/SDL_system.h | 12 + include/SDL_syswm.h | 2 + include/SDL_touch.h | 8 + include/SDL_version.h | 2 +- include/SDL_video.h | 1 + include/begin_code.h | 2 +- src/SDL.c | 9 +- src/SDL_hints.c | 5 + src/SDL_list.c | 93 ++ src/SDL_list.h | 39 + src/audio/SDL_audio.c | 130 +- src/audio/SDL_audiocvt.c | 79 +- src/audio/SDL_mixer.c | 107 +- src/audio/SDL_sysaudio.h | 24 +- src/audio/SDL_wave.c | 2 +- src/audio/aaudio/SDL_aaudio.c | 17 +- src/audio/alsa/SDL_alsa_audio.c | 33 +- src/audio/android/SDL_androidaudio.c | 21 +- src/audio/arts/SDL_artsaudio.c | 38 +- src/audio/coreaudio/SDL_coreaudio.m | 60 +- src/audio/directsound/SDL_directsound.c | 44 +- src/audio/disk/SDL_diskaudio.c | 14 +- src/audio/dsp/SDL_dspaudio.c | 14 +- src/audio/dummy/SDL_dummyaudio.c | 12 +- src/audio/emscripten/SDL_emscriptenaudio.c | 65 +- src/audio/esd/SDL_esdaudio.c | 14 +- src/audio/fusionsound/SDL_fsaudio.c | 39 +- src/audio/haiku/SDL_haikuaudio.cc | 31 +- src/audio/jack/SDL_jackaudio.c | 13 +- src/audio/nacl/SDL_naclaudio.c | 14 +- src/audio/nas/SDL_nasaudio.c | 72 +- src/audio/netbsd/SDL_netbsdaudio.c | 58 +- src/audio/openslES/SDL_openslES.c | 68 +- src/audio/os2/SDL_os2audio.c | 31 +- src/audio/paudio/SDL_paudio.c | 78 +- src/audio/pipewire/SDL_pipewire.c | 245 ++-- src/audio/pipewire/SDL_pipewire.h | 6 +- src/audio/psp/SDL_pspaudio.c | 14 +- src/audio/pulseaudio/SDL_pulseaudio.c | 52 +- src/audio/qsa/SDL_qsa_audio.c | 111 +- src/audio/qsa/SDL_qsa_audio.h | 3 - src/audio/sndio/SDL_sndioaudio.c | 25 +- src/audio/sun/SDL_sunaudio.c | 11 +- src/audio/vita/SDL_vitaaudio.c | 95 +- src/audio/vita/SDL_vitaaudio.h | 4 +- src/audio/wasapi/SDL_wasapi.c | 44 +- src/audio/wasapi/SDL_wasapi.h | 1 - src/audio/winmm/SDL_winmm.c | 30 +- src/core/android/SDL_android.c | 13 + src/core/linux/SDL_fcitx.c | 8 +- src/core/linux/SDL_fcitx.h | 2 +- src/core/linux/SDL_ibus.c | 11 +- src/core/linux/SDL_ibus.h | 2 +- src/core/linux/SDL_ime.c | 6 +- src/core/linux/SDL_ime.h | 2 +- src/core/openbsd/SDL_wscons_kbd.c | 9 +- src/core/os2/geniconv/geniconv.c | 29 +- src/core/windows/SDL_windows.c | 73 +- src/core/windows/SDL_windows.h | 9 + src/core/winrt/SDL_winrtapp_xaml.cpp | 2 +- src/dynapi/SDL_dynapi_overrides.h | 10 + src/dynapi/SDL_dynapi_procs.h | 12 + src/events/SDL_events.c | 125 +- src/events/SDL_keyboard.c | 25 +- src/events/SDL_mouse.c | 150 ++- src/events/SDL_mouse_c.h | 10 + src/events/SDL_touch.c | 22 +- src/events/SDL_touch_c.h | 1 + src/events/SDL_windowevents.c | 7 +- src/file/SDL_rwops.c | 2 +- src/filesystem/os2/SDL_sysfilesystem.c | 24 +- src/filesystem/windows/SDL_sysfilesystem.c | 20 +- src/haptic/windows/SDL_dinputhaptic.c | 6 +- src/haptic/windows/SDL_xinputhaptic.c | 3 +- src/hidapi/SDL_hidapi.c | 10 +- src/hidapi/android/hid.cpp | 119 +- src/hidapi/libusb/hid.c | 51 +- src/hidapi/mac/hid.c | 33 +- src/joystick/SDL_gamecontrollerdb.h | 13 +- src/joystick/SDL_joystick.c | 89 +- src/joystick/android/SDL_sysjoystick.c | 1 + src/joystick/hidapi/SDL_hidapi_gamecube.c | 31 +- src/joystick/hidapi/SDL_hidapi_ps4.c | 6 + src/joystick/hidapi/SDL_hidapi_ps5.c | 11 +- src/joystick/hidapi/SDL_hidapi_switch.c | 3 +- src/joystick/hidapi/SDL_hidapi_xboxone.c | 48 +- src/joystick/hidapi/SDL_hidapijoystick.c | 20 +- src/joystick/iphoneos/SDL_mfijoystick.m | 22 +- src/joystick/linux/SDL_sysjoystick.c | 119 +- src/joystick/usb_ids.h | 1 + src/joystick/vita/SDL_sysjoystick.c | 3 +- src/joystick/windows/SDL_rawinputjoystick.c | 146 +- .../windows/SDL_windows_gaming_input.c | 109 +- src/joystick/windows/SDL_xinputjoystick.c | 17 +- src/loadso/os2/SDL_sysloadso.c | 2 +- src/loadso/windows/SDL_sysloadso.c | 2 +- src/locale/vita/SDL_syslocale.c | 71 + src/main/haiku/SDL_BApp.h | 51 +- src/main/windows/version.rc | 8 +- src/misc/emscripten/SDL_sysurl.c | 37 + src/misc/winrt/SDL_sysurl.cpp | 3 +- src/power/linux/SDL_syspower.c | 32 +- src/render/SDL_render.c | 220 ++- src/render/SDL_sysrender.h | 27 +- src/render/direct3d/SDL_render_d3d.c | 113 +- src/render/direct3d11/SDL_render_d3d11.c | 115 +- src/render/direct3d11/SDL_shaders_d3d11.c | 4 +- src/render/direct3d11/SDL_shaders_d3d11.h | 2 + src/render/metal/SDL_render_metal.m | 64 +- src/render/opengl/SDL_render_gl.c | 249 +++- src/render/opengl/SDL_shaders_gl.c | 3 +- src/render/opengl/SDL_shaders_gl.h | 2 + src/render/opengles2/SDL_render_gles2.c | 116 +- src/render/opengles2/SDL_shaders_gles2.c | 5 + src/render/opengles2/SDL_shaders_gles2.h | 2 + src/render/psp/SDL_render_psp.c | 67 +- src/render/software/SDL_blendfillrect.c | 4 +- src/render/software/SDL_blendline.c | 2 +- src/render/software/SDL_blendpoint.c | 4 +- src/render/software/SDL_drawline.c | 4 +- src/render/software/SDL_drawpoint.c | 4 +- src/render/software/SDL_render_sw.c | 140 +- src/render/software/SDL_rotate.c | 230 ++-- src/render/software/SDL_rotate.h | 6 +- src/render/software/SDL_triangle.c | 57 +- src/render/vitagxm/SDL_render_vita_gxm.c | 291 +++- .../vitagxm/SDL_render_vita_gxm_memory.c | 76 +- .../vitagxm/SDL_render_vita_gxm_memory.h | 16 +- .../vitagxm/SDL_render_vita_gxm_tools.c | 152 ++- .../vitagxm/SDL_render_vita_gxm_tools.h | 7 +- .../vitagxm/SDL_render_vita_gxm_types.h | 13 +- src/sensor/windows/SDL_windowssensor.c | 5 +- src/stdlib/SDL_getenv.c | 14 +- src/stdlib/SDL_iconv.c | 21 +- src/stdlib/SDL_string.c | 70 +- src/test/SDL_test_common.c | 2 + src/thread/generic/SDL_syscond.c | 6 +- src/thread/generic/SDL_sysmutex.c | 6 +- src/thread/generic/SDL_syssem.c | 6 +- src/thread/os2/SDL_sysmutex.c | 16 +- src/thread/os2/SDL_syssem.c | 6 +- src/thread/psp/SDL_syscond.c | 6 +- src/thread/psp/SDL_sysmutex.c | 6 +- src/thread/psp/SDL_syssem.c | 6 +- src/thread/pthread/SDL_syscond.c | 8 +- src/thread/pthread/SDL_sysmutex.c | 6 +- src/thread/pthread/SDL_syssem.c | 8 +- src/thread/pthread/SDL_systhread.c | 19 +- src/thread/stdcpp/SDL_syscond.cpp | 15 +- src/thread/stdcpp/SDL_sysmutex.cpp | 11 +- src/thread/stdcpp/SDL_systhread.cpp | 6 +- src/thread/vita/SDL_syscond.c | 6 +- src/thread/vita/SDL_sysmutex.c | 6 +- src/thread/vita/SDL_syssem.c | 6 +- src/thread/windows/SDL_syscond_cv.c | 8 +- src/thread/windows/SDL_sysmutex.c | 12 +- src/thread/windows/SDL_syssem.c | 16 +- src/timer/os2/SDL_systimer.c | 13 +- src/timer/unix/SDL_systimer.c | 15 +- src/video/SDL_blit.c | 4 +- src/video/SDL_blit.h | 18 +- src/video/SDL_blit_0.c | 83 ++ src/video/SDL_blit_N.c | 2 +- src/video/SDL_blit_auto.c | 24 +- src/video/SDL_blit_slow.c | 59 +- src/video/SDL_bmp.c | 37 +- src/video/SDL_egl.c | 26 +- src/video/SDL_fillrect.c | 30 +- src/video/SDL_pixels.c | 43 +- src/video/SDL_rect.c | 491 +------ src/video/SDL_rect_impl.h | 444 +++++++ src/video/SDL_surface.c | 9 +- src/video/SDL_sysvideo.h | 4 + src/video/SDL_video.c | 367 ++--- src/video/SDL_vulkan_internal.h | 8 +- src/video/android/SDL_androidevents.c | 11 +- src/video/android/SDL_androidgl.c | 2 +- src/video/android/SDL_androidvideo.c | 3 + src/video/android/SDL_androidwindow.c | 16 + src/video/android/SDL_androidwindow.h | 3 + src/video/cocoa/SDL_cocoamodes.m | 3 + src/video/cocoa/SDL_cocoamouse.m | 6 +- src/video/cocoa/SDL_cocoawindow.m | 10 + src/video/dummy/SDL_nullframebuffer.c | 8 +- src/video/dummy/SDL_nullvideo.c | 3 +- src/video/emscripten/SDL_emscriptenevents.c | 6 +- .../emscripten/SDL_emscriptenframebuffer.c | 38 +- src/video/emscripten/SDL_emscriptenmouse.c | 56 +- src/video/emscripten/SDL_emscriptenvideo.c | 27 +- src/video/haiku/SDL_BApp.h | 431 ++++++ src/video/haiku/SDL_BWin.h | 416 +++--- src/video/haiku/SDL_bframebuffer.cc | 148 +-- src/video/haiku/SDL_bopengl.cc | 36 +- src/video/haiku/SDL_bvideo.cc | 29 +- src/video/haiku/SDL_bwindow.cc | 7 + src/video/haiku/SDL_bwindow.h | 1 + src/video/nacl/SDL_naclwindow.c | 3 +- .../offscreen/SDL_offscreenframebuffer.c | 8 +- src/video/os2/SDL_os2dive.c | 8 +- src/video/os2/SDL_os2messagebox.c | 10 +- src/video/os2/SDL_os2util.c | 9 +- src/video/os2/SDL_os2video.c | 14 +- src/video/os2/SDL_os2vman.c | 11 +- src/video/riscos/SDL_riscosevents.c | 19 +- src/video/sdlgenblit.pl | 100 +- src/video/uikit/SDL_uikitevents.m | 8 +- src/video/uikit/SDL_uikitmessagebox.m | 26 +- src/video/uikit/SDL_uikitopengles.m | 4 +- src/video/vita/SDL_vitaframebuffer.c | 2 +- src/video/vita/SDL_vitagl_pvr.c | 65 +- src/video/vita/SDL_vitagl_pvr_c.h | 9 +- .../vita/{SDL_vitagl.c => SDL_vitagles.c} | 24 +- .../vita/{SDL_vitagl_c.h => SDL_vitagles_c.h} | 24 +- src/video/vita/SDL_vitagles_pvr.c | 103 ++ src/video/vita/SDL_vitagles_pvr_c.h | 35 + src/video/vita/SDL_vitatouch.c | 29 +- src/video/vita/SDL_vitavideo.c | 64 +- src/video/vita/SDL_vitavideo.h | 21 +- src/video/wayland/SDL_waylanddyn.h | 11 +- src/video/wayland/SDL_waylandevents.c | 606 ++++++++- src/video/wayland/SDL_waylandevents_c.h | 44 + src/video/wayland/SDL_waylandkeyboard.h | 1 + src/video/wayland/SDL_waylandopengles.c | 4 +- src/video/wayland/SDL_waylandsym.h | 17 +- src/video/wayland/SDL_waylandvideo.c | 402 +++++- src/video/wayland/SDL_waylandvideo.h | 17 +- src/video/wayland/SDL_waylandvulkan.c | 4 +- src/video/wayland/SDL_waylandwindow.c | 760 +++++++++-- src/video/wayland/SDL_waylandwindow.h | 22 +- src/video/windows/SDL_windowsevents.c | 82 +- src/video/windows/SDL_windowskeyboard.c | 272 ++-- src/video/windows/SDL_windowskeyboard.h | 2 + src/video/windows/SDL_windowsmouse.c | 9 +- src/video/windows/SDL_windowsvideo.c | 2 + src/video/windows/SDL_windowsvideo.h | 8 +- src/video/windows/SDL_windowswindow.c | 179 ++- src/video/windows/SDL_windowswindow.h | 1 + src/video/winrt/SDL_winrtvideo.cpp | 14 +- src/video/x11/SDL_x11events.c | 74 +- src/video/x11/SDL_x11events.h | 1 + src/video/x11/SDL_x11keyboard.c | 2 + src/video/x11/SDL_x11messagebox.c | 16 +- src/video/x11/SDL_x11modes.c | 8 +- src/video/x11/SDL_x11mouse.c | 13 +- src/video/x11/SDL_x11opengl.c | 5 - src/video/x11/SDL_x11sym.h | 1 - src/video/x11/SDL_x11window.c | 127 +- src/video/yuv2rgb/yuv_rgb_sse_func.h | 19 +- test/CMakeLists.txt | 1 - test/Makefile.in | 1 + test/testautomation_rect.c | 98 +- test/testautomation_render.c | 59 +- test/testautomation_surface.c | 2 +- test/testevdev.c | 36 +- test/testgamecontroller.c | 1 + test/testgesture.c | 3 +- test/testgles2.c | 71 +- test/testmouse.c | 38 + test/testplatform.c | 40 +- test/testshader.c | 49 +- wayland-protocols/tablet-unstable-v2.xml | 1178 +++++++++++++++++ wayland-protocols/viewporter.xml | 186 +++ wayland-protocols/xdg-output-unstable-v1.xml | 220 +++ 328 files changed, 11731 insertions(+), 6060 deletions(-) delete mode 100644 Makefile.psp delete mode 100644 Makefile.wiz delete mode 100755 build-scripts/os2-buildbot.sh delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100644 debian/docs delete mode 100644 debian/libsdl2-2.0-0-udeb.install delete mode 100644 debian/libsdl2-2.0-0.install delete mode 100644 debian/libsdl2-dev.install delete mode 100644 debian/libsdl2-dev.manpages delete mode 100755 debian/rules delete mode 100644 debian/sdl2-config.1 delete mode 100644 debian/source/format delete mode 100644 debian/watch delete mode 100644 include/SDL_config_psp.h delete mode 100644 include/SDL_config_wiz.h create mode 100644 src/SDL_list.c create mode 100644 src/SDL_list.h create mode 100644 src/locale/vita/SDL_syslocale.c create mode 100644 src/misc/emscripten/SDL_sysurl.c create mode 100644 src/video/SDL_rect_impl.h create mode 100644 src/video/haiku/SDL_BApp.h rename src/video/vita/{SDL_vitagl.c => SDL_vitagles.c} (91%) rename src/video/vita/{SDL_vitagl_c.h => SDL_vitagles_c.h} (67%) create mode 100644 src/video/vita/SDL_vitagles_pvr.c create mode 100644 src/video/vita/SDL_vitagles_pvr_c.h create mode 100644 wayland-protocols/tablet-unstable-v2.xml create mode 100644 wayland-protocols/viewporter.xml create mode 100644 wayland-protocols/xdg-output-unstable-v1.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index bb9f53680..0d20f99c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,12 +66,12 @@ include(${SDL2_SOURCE_DIR}/cmake/sdlchecks.cmake) # set SDL_BINARY_AGE and SDL_INTERFACE_AGE to 0. set(SDL_MAJOR_VERSION 2) set(SDL_MINOR_VERSION 0) -set(SDL_MICRO_VERSION 20) -set(SDL_INTERFACE_AGE 2) -set(SDL_BINARY_AGE 20) +set(SDL_MICRO_VERSION 22) +set(SDL_INTERFACE_AGE 0) +set(SDL_BINARY_AGE 22) set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}") # the following should match the versions in Xcode project file: -set(DYLIB_CURRENT_VERSION 19.2.0) +set(DYLIB_CURRENT_VERSION 23.0.0) set(DYLIB_COMPATIBILITY_VERSION 1.0.0) # Set defaults preventing destination file conflicts @@ -308,7 +308,7 @@ if(CYGWIN) # We build SDL on cygwin without the UNIX emulation layer target_include_directories(sdl-build-options INTERFACE "/usr/include/mingw") set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -mno-cygwin") - check_c_source_compiles("int main(int argc, char **argv) {}" + check_c_source_compiles("int main(int argc, char **argv) { return 0; }" HAVE_GCC_NO_CYGWIN) set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) if(HAVE_GCC_NO_CYGWIN) @@ -376,7 +376,7 @@ set(LONGESTOPTIONNAME 0) # set_option and friends will change this. set(SDL_SUBSYSTEMS Atomic Audio Video Render Events Joystick Haptic Hidapi Power Threads Timers - File Loadso CPUinfo Filesystem Dlopen Sensor Locale) + File Loadso CPUinfo Filesystem Sensor Locale Misc) foreach(_SUB ${SDL_SUBSYSTEMS}) string(TOUPPER ${_SUB} _OPT) if (NOT DEFINED SDL_${_OPT}_ENABLED_BY_DEFAULT) @@ -385,6 +385,11 @@ foreach(_SUB ${SDL_SUBSYSTEMS}) option(SDL_${_OPT} "Enable the ${_SUB} subsystem" ${SDL_${_OPT}_ENABLED_BY_DEFAULT}) endforeach() +# Allow some projects to be built conditionally. +set_option(SDL2_DISABLE_SDL2MAIN "Disable building/installation of SDL2main" OFF) +set_option(SDL2_DISABLE_INSTALL "Disable installation of SDL2" OFF) +set_option(SDL2_DISABLE_UNINSTALL "Disable uninstallation of SDL2" OFF) + option_string(SDL_ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto") #set_option(SDL_DEPENDENCY_TRACKING "Use gcc -MMD -MT dependency tracking" ON) set_option(SDL_LIBC "Use the system C library" ${OPT_DEF_LIBC}) @@ -440,7 +445,7 @@ foreach(_SUB ${SDL_X11_OPTIONS}) endforeach() set_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS}) dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND" OFF) -dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" ON) +dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF) dep_option(SDL_WAYLAND_LIBDECOR_SHARED "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR" OFF) dep_option(SDL_WAYLAND_QT_TOUCH "QtWayland server support for Wayland video driver" ON "SDL_WAYLAND" OFF) set_option(SDL_RPI "Use Raspberry Pi video driver" ${UNIX_SYS}) @@ -469,8 +474,8 @@ dep_option(SDL_STATIC_PIC "Static version of the library should be built wi set_option(SDL_TEST "Build the test directory" OFF) if(VITA) - set_option(VIDEO_VITA_PIB "Build with PSVita piglet gles2 support" OFF) - set_option(VIDEO_VITA_PVR "Build with PSVita PVR gles/gles2 support" OFF) + set_option(VIDEO_VITA_PIB "Build with PSVita piglet gles2 support" OFF) + set_option(VIDEO_VITA_PVR "Build with PSVita PVR gles/gles2 support" OFF) endif() # General source files @@ -482,6 +487,7 @@ file(GLOB SOURCE_FILES ${SDL2_SOURCE_DIR}/src/dynapi/*.c ${SDL2_SOURCE_DIR}/src/events/*.c ${SDL2_SOURCE_DIR}/src/file/*.c + ${SDL2_SOURCE_DIR}/src/joystick/*.c ${SDL2_SOURCE_DIR}/src/haptic/*.c ${SDL2_SOURCE_DIR}/src/hidapi/*.c ${SDL2_SOURCE_DIR}/src/libm/*.c @@ -555,7 +561,7 @@ if(USE_GCC OR USE_CLANG) #if !defined(__GNUC__) || __GNUC__ < 3 #error Dependency tracking requires GCC 3.0 or newer #endif - int main(int argc, char **argv) { }" HAVE_DEPENDENCY_TRACKING) + int main(int argc, char **argv) { return 0; }" HAVE_DEPENDENCY_TRACKING) endif() if(SDL_GCC_ATOMICS) @@ -566,17 +572,19 @@ if(USE_GCC OR USE_CLANG) __sync_lock_test_and_set(&x, y); __sync_fetch_and_add(&a, 1); __sync_bool_compare_and_swap(&a, 5, 10); - __sync_bool_compare_and_swap(&x, y, z); }" HAVE_GCC_ATOMICS) + __sync_bool_compare_and_swap(&x, y, z); + return 0; }" HAVE_GCC_ATOMICS) if(NOT HAVE_GCC_ATOMICS) check_c_source_compiles("int main(int argc, char **argv) { int a; __sync_lock_test_and_set(&a, 1); - __sync_lock_release(&a); }" HAVE_GCC_SYNC_LOCK_TEST_AND_SET) + __sync_lock_release(&a); + return 0; }" HAVE_GCC_SYNC_LOCK_TEST_AND_SET) endif() endif() set(CMAKE_REQUIRED_FLAGS "-mpreferred-stack-boundary=2") - check_c_source_compiles("int x = 0; int main(int argc, char **argv) {}" + check_c_source_compiles("int x = 0; int main(int argc, char **argv) { return 0; }" HAVE_GCC_PREFERRED_STACK_BOUNDARY) set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) @@ -585,7 +593,7 @@ if(USE_GCC OR USE_CLANG) #if !defined(__GNUC__) || __GNUC__ < 4 #error SDL only uses visibility attributes in GCC 4 or newer #endif - int main(int argc, char **argv) {}" HAVE_GCC_FVISIBILITY) + int main(int argc, char **argv) { return 0; }" HAVE_GCC_FVISIBILITY) if(HAVE_GCC_FVISIBILITY) list(APPEND EXTRA_CFLAGS "-fvisibility=hidden") endif() @@ -641,7 +649,7 @@ if(SDL_ASSEMBLY) #ifndef __MMX__ #error Assembler CPP flag not enabled #endif - int main(int argc, char **argv) { }" HAVE_MMX) + int main(int argc, char **argv) { return 0; }" HAVE_MMX) if(HAVE_MMX) list(APPEND EXTRA_CFLAGS "-mmmx") endif() @@ -658,6 +666,7 @@ if(SDL_ASSEMBLY) int main(int argc, char **argv) { void *p = 0; _m_prefetch(p); + return 0; }" HAVE_3DNOW) if(HAVE_3DNOW) list(APPEND EXTRA_CFLAGS "-m3dnow") @@ -681,7 +690,7 @@ if(SDL_ASSEMBLY) #ifndef __SSE__ #error Assembler CPP flag not enabled #endif - int main(int argc, char **argv) { }" HAVE_SSE) + int main(int argc, char **argv) { return 0; }" HAVE_SSE) if(HAVE_SSE) list(APPEND EXTRA_CFLAGS "-msse") endif() @@ -704,7 +713,7 @@ if(SDL_ASSEMBLY) #ifndef __SSE2__ #error Assembler CPP flag not enabled #endif - int main(int argc, char **argv) { }" HAVE_SSE2) + int main(int argc, char **argv) { return 0; }" HAVE_SSE2) if(HAVE_SSE2) list(APPEND EXTRA_CFLAGS "-msse2") endif() @@ -727,7 +736,7 @@ if(SDL_ASSEMBLY) #ifndef __SSE3__ #error Assembler CPP flag not enabled #endif - int main(int argc, char **argv) { }" HAVE_SSE3) + int main(int argc, char **argv) { return 0; }" HAVE_SSE3) if(HAVE_SSE3) list(APPEND EXTRA_CFLAGS "-msse3") endif() @@ -756,12 +765,12 @@ if(SDL_ASSEMBLY) vector unsigned int vzero() { return vec_splat_u32(0); } - int main(int argc, char **argv) { }" HAVE_ALTIVEC_H_HDR) + int main(int argc, char **argv) { return 0; }" HAVE_ALTIVEC_H_HDR) check_c_source_compiles(" vector unsigned int vzero() { return vec_splat_u32(0); } - int main(int argc, char **argv) { }" HAVE_ALTIVEC) + int main(int argc, char **argv) { return 0; }" HAVE_ALTIVEC) set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) if(HAVE_ALTIVEC OR HAVE_ALTIVEC_H_HDR) set(HAVE_ALTIVEC TRUE) # if only HAVE_ALTIVEC_H_HDR is set @@ -866,9 +875,7 @@ if(SDL_LIBC) string(TOUPPER ${_FN} _UPPER) set(HAVE_${_UPPER} 1) endforeach() - if(NOT CYGWIN AND NOT MINGW) - set(HAVE_ALLOCA 1) - endif() + set(HAVE_ALLOCA 1) set(HAVE_M_PI 1) target_compile_definitions(sdl-build-options INTERFACE "-D_USE_MATH_DEFINES") # needed for M_PI set(STDC_HEADERS 1) @@ -890,7 +897,7 @@ if(SDL_LIBC) # TODO: refine the mprotect check check_c_source_compiles("#include #include - int main() { }" HAVE_MPROTECT) + int main(void) { return 0; }" HAVE_MPROTECT) foreach(_FN strtod malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove memcmp strlen strlcpy strlcat @@ -974,10 +981,6 @@ foreach(_SUB ${SDL_SUBSYSTEMS}) set(SDL_${_OPT}_DISABLED 1) endif() endforeach() -if(SDL_JOYSTICK) - file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES}) -endif() if(SDL_HAPTIC) if(NOT SDL_JOYSTICK) # Haptic requires some private functions from the joystick subsystem. @@ -994,12 +997,14 @@ if(SDL_AUDIO) file(GLOB DUMMYAUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/dummy/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${DUMMYAUDIO_SOURCES}) set(HAVE_DUMMYAUDIO TRUE) + set(HAVE_SDL_AUDIO TRUE) endif() if(SDL_DISKAUDIO) set(SDL_AUDIO_DRIVER_DISK 1) file(GLOB DISKAUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/disk/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${DISKAUDIO_SOURCES}) set(HAVE_DISKAUDIO TRUE) + set(HAVE_SDL_AUDIO TRUE) endif() endif() @@ -1050,9 +1055,11 @@ if(ANDROID) file(GLOB ANDROID_CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/android/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${ANDROID_CORE_SOURCES} ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c) - file(GLOB ANDROID_MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/android/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${ANDROID_MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + if(SDL_MISC) + file(GLOB ANDROID_MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/android/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${ANDROID_MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() # SDL_spinlock.c Needs to be compiled in ARM mode. # There seems to be no better way currently to set the ARM mode. @@ -1163,17 +1170,17 @@ if(ANDROID) list(APPEND EXTRA_LIBS ${OpenGLES1_LIBRARY} ${OpenGLES2_LIBRARY}) endif() - CHECK_C_SOURCE_COMPILES(" - #if defined(__ARM_ARCH) && __ARM_ARCH < 7 - #error Vulkan doesn't work on this configuration - #endif - int main(void) { - return 0; - } - " VULKAN_PASSED_ANDROID_CHECKS) - if(NOT VULKAN_PASSED_ANDROID_CHECKS) - set(SDL_VULKAN OFF) - message(STATUS "Vulkan doesn't work on this configuration") + if(SDL_VULKAN) + CHECK_C_SOURCE_COMPILES(" + #if defined(__ARM_ARCH) && __ARM_ARCH < 7 + #error Vulkan doesn't work on this configuration + #endif + int main(int argc, char **argv) { return 0; } + " VULKAN_PASSED_ANDROID_CHECKS) + if(VULKAN_PASSED_ANDROID_CHECKS) + set(SDL_VIDEO_VULKAN 1) + set(HAVE_VULKAN TRUE) + endif() endif() endif() @@ -1183,6 +1190,12 @@ elseif(EMSCRIPTEN) # Hide noisy warnings that intend to aid mostly during initial stages of porting a new # project. Uncomment at will for verbose cross-compiling -I/../ path info. target_compile_options(sdl-build-options INTERFACE "-Wno-warn-absolute-paths") + + if(SDL_MISC) + file(GLOB EMSRIPTEN_MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/emscripten/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${EMSRIPTEN_MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_EMSCRIPTEN 1) file(GLOB EM_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/emscripten/*.c) @@ -1283,6 +1296,11 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS AND NOT HAIKU) CheckOpenGLES() CheckWayland() CheckVivante() + # FIXME: implement CheckVulkan() + if(SDL_VULKAN) + set(SDL_VIDEO_VULKAN 1) + set(HAVE_VULKAN TRUE) + endif() endif() if(UNIX) @@ -1294,28 +1312,26 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS AND NOT HAIKU) #ifndef EVIOCGNAME #error EVIOCGNAME() ioctl not available #endif - int main(int argc, char** argv) {}" HAVE_INPUT_EVENTS) + int main(int argc, char** argv) { return 0; }" HAVE_INPUT_EVENTS) if(LINUX) check_c_source_compiles(" #include #include - - int main(int argc, char **argv) - { + int main(int argc, char **argv) { struct kbentry kbe; kbe.kb_table = KG_CTRL; ioctl(0, KDGKBENT, &kbe); + return 0; }" HAVE_INPUT_KD) elseif(FREEBSD) check_c_source_compiles(" #include #include - - int main(int argc, char **argv) - { + int main(int argc, char **argv) { accentmap_t accTable; ioctl(0, KDENABIO, 1); + return 0; }" HAVE_INPUT_KBIO) endif() @@ -1380,7 +1396,7 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS AND NOT HAIKU) if(HAVE_LIBUNWIND_H) # We've already found the header, so REQUIRE the lib to be present pkg_search_module(UNWIND REQUIRED libunwind) - pkg_search_module(UNWIND_GENERIC REQUIRED libunwind-generic) + pkg_search_module(UNWIND_GENERIC libunwind-generic) list(APPEND EXTRA_LIBS ${UNWIND_LIBRARIES} ${UNWIND_GENERIC_LIBRARIES}) endif() endif() @@ -1457,9 +1473,11 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT RISCOS AND NOT HAIKU) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_LINUX_VERSION_H") endif() - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/unix/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + if(SDL_MISC) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/unix/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_POWER) if(LINUX) @@ -1513,7 +1531,7 @@ elseif(WINDOWS) check_c_source_compiles(" #include - int main(int argc, char **argv) { }" HAVE_WIN32_CC) + int main(int argc, char **argv) { return 0; }" HAVE_WIN32_CC) file(GLOB CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/windows/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${CORE_SOURCES}) @@ -1531,14 +1549,15 @@ elseif(WINDOWS) endif() endif() - if(WINDOWS_STORE) - file(GLOB WINRT_MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/winrt/*.cpp) - set(SOURCE_FILES ${SOURCE_FILES} ${WINRT_MISC_SOURCES}) - else() - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/windows/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + if(SDL_MISC) + if(WINDOWS_STORE) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/winrt/*.cpp) + else() + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/windows/*.c) + endif() + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) endif() - set(HAVE_SDL_MISC TRUE) # Check for DirectX if(SDL_DIRECTX) @@ -1577,42 +1596,44 @@ elseif(WINDOWS) check_c_source_compiles(" #include #include - int main(int argc, char **argv) { }" HAVE_XINPUT_H) + int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_H) check_c_source_compiles(" #include #include XINPUT_GAMEPAD_EX x1; - int main(int argc, char **argv) { }" HAVE_XINPUT_GAMEPAD_EX) + int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_GAMEPAD_EX) check_c_source_compiles(" #include #include XINPUT_STATE_EX s1; - int main(int argc, char **argv) { }" HAVE_XINPUT_STATE_EX) + int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_STATE_EX) check_c_source_compiles(" #define COBJMACROS #include __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2 *s2; - int main(int argc, char **argv) { }" HAVE_WINDOWS_GAMING_INPUT_H) + int main(int argc, char **argv) { return 0; }" HAVE_WINDOWS_GAMING_INPUT_H) endif() # headers needed elsewhere check_include_file(tpcshrd.h HAVE_TPCSHRD_H) + check_include_file(roapi.h HAVE_ROAPI_H) check_include_file(mmdeviceapi.h HAVE_MMDEVICEAPI_H) check_include_file(audioclient.h HAVE_AUDIOCLIENT_H) check_include_file(sensorsapi.h HAVE_SENSORSAPI_H) if(SDL_AUDIO) if(NOT WINDOWS_STORE) - set(SDL_AUDIO_DRIVER_WINMM 1) - file(GLOB WINMM_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/winmm/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${WINMM_AUDIO_SOURCES}) + set(SDL_AUDIO_DRIVER_WINMM 1) + file(GLOB WINMM_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/winmm/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${WINMM_AUDIO_SOURCES}) + set(HAVE_SDL_AUDIO TRUE) endif() - set(HAVE_SDL_AUDIO TRUE) if(HAVE_DSOUND_H AND NOT WINDOWS_STORE) set(SDL_AUDIO_DRIVER_DSOUND 1) file(GLOB DSOUND_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/directsound/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${DSOUND_AUDIO_SOURCES}) + set(HAVE_SDL_AUDIO TRUE) endif() if(SDL_WASAPI AND HAVE_AUDIOCLIENT_H AND HAVE_MMDEVICEAPI_H) @@ -1623,6 +1644,7 @@ elseif(WINDOWS) list(APPEND WASAPI_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/wasapi/SDL_wasapi_winrt.cpp) endif() set(SOURCE_FILES ${SOURCE_FILES} ${WASAPI_AUDIO_SOURCES}) + set(HAVE_SDL_AUDIO TRUE) endif() endif() @@ -1639,8 +1661,8 @@ elseif(WINDOWS) ${SDL2_SOURCE_DIR}/src/render/direct3d11/*.cpp ) else() - set(SDL_VIDEO_DRIVER_WINDOWS 1) - file(GLOB WIN_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/windows/*.c) + set(SDL_VIDEO_DRIVER_WINDOWS 1) + file(GLOB WIN_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/windows/*.c) endif() set(SOURCE_FILES ${SOURCE_FILES} ${WIN_VIDEO_SOURCES}) @@ -1752,6 +1774,11 @@ elseif(WINDOWS) set(SDL_VIDEO_RENDER_OGL_ES2 1) set(HAVE_OPENGLES TRUE) endif() + + if(SDL_VULKAN) + set(SDL_VIDEO_VULKAN 1) + set(HAVE_VULKAN TRUE) + endif() endif() if(SDL_HIDAPI) @@ -1770,8 +1797,10 @@ elseif(WINDOWS) list(APPEND EXTRA_LIBS dinput8) endif() if(HAVE_XINPUT_H) - set(SDL_JOYSTICK_XINPUT 1) - set(HAVE_XINPUT TRUE) + if(NOT WINDOWS_STORE) + set(SDL_JOYSTICK_XINPUT 1) + set(HAVE_XINPUT TRUE) + endif() if(HAVE_WINDOWS_GAMING_INPUT_H) set(SDL_JOYSTICK_WGI 1) endif() @@ -1779,7 +1808,7 @@ elseif(WINDOWS) set(HAVE_SDL_JOYSTICK TRUE) if(SDL_HAPTIC) - if(HAVE_DINPUT_H OR HAVE_XINPUT_H) + if((HAVE_DINPUT_H OR HAVE_XINPUT_H) AND NOT WINDOWS_STORE) file(GLOB HAPTIC_SOURCES ${SDL2_SOURCE_DIR}/src/haptic/windows/*.c) if(HAVE_DINPUT_H) set(SDL_HAPTIC_DINPUT 1) @@ -1801,8 +1830,11 @@ elseif(WINDOWS) if(MINGW OR CYGWIN) list(APPEND EXTRA_LIBS mingw32) list(APPEND EXTRA_LDFLAGS "-mwindows") - set(SDL_CFLAGS "${SDL_CFLAGS} -Dmain=SDL_main") - list(APPEND SDL_LIBS "-lmingw32" "-lSDL2main" "-mwindows") + list(APPEND SDL_LIBS "-lmingw32" "-mwindows") + if(NOT SDL2_DISABLE_SDL2MAIN) + set(SDL_CFLAGS "${SDL_CFLAGS} -Dmain=SDL_main") + list(APPEND SDL_LIBS "-lSDL2main") + endif(NOT SDL2_DISABLE_SDL2MAIN) endif() elseif(APPLE) @@ -1823,27 +1855,26 @@ elseif(APPLE) if(SDL_FILE) file(GLOB EXTRA_SOURCES ${SDL2_SOURCE_DIR}/src/file/cocoa/*.m) set(SOURCE_FILES ${EXTRA_SOURCES} ${SOURCE_FILES}) - # !!! FIXME: modern CMake doesn't need "LANGUAGE C" for Objective-C. - set_source_files_properties(${EXTRA_SOURCES} PROPERTIES LANGUAGE C) set(HAVE_SDL_FILE TRUE) - else() - message_error("SDL_FILE must be enabled to build on MacOS X") endif() if(IOS OR TVOS) - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/ios/*.m) file(GLOB SDLMAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/uikit/*.c) - else() - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/macosx/*.m) endif() - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + + if(SDL_MISC) + if(IOS OR TVOS) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/ios/*.m) + else() + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/macosx/*.m) + endif() + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_COREAUDIO 1) file(GLOB AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/coreaudio/*.m) - # !!! FIXME: modern CMake doesn't need "LANGUAGE C" for Objective-C. - set_source_files_properties(${AUDIO_SOURCES} PROPERTIES LANGUAGE C) set(SOURCE_FILES ${SOURCE_FILES} ${AUDIO_SOURCES}) set(HAVE_SDL_AUDIO TRUE) set(SDL_FRAMEWORK_COREAUDIO 1) @@ -1865,7 +1896,6 @@ elseif(APPLE) endif() set(SDL_FRAMEWORK_GAMECONTROLLER 1) set(SDL_FRAMEWORK_COREHAPTICS 1) - set(HAVE_SDL_SENSORS 1) else() file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/darwin/*.c) set_source_files_properties(${MFI_JOYSTICK_SOURCES} PROPERTIES COMPILE_FLAGS -fobjc-weak) @@ -1880,13 +1910,13 @@ elseif(APPLE) #if TARGET_CPU_X86 #error GameController framework doesn't work on this configuration #endif - int main() {}" HAVE_FRAMEWORK_GAMECONTROLLER) + int main() { return 0; }" HAVE_FRAMEWORK_GAMECONTROLLER) check_objc_source_compiles(" #include #include #import #import - int main() {}" HAVE_FRAMEWORK_COREHAPTICS) + int main() { return 0; }" HAVE_FRAMEWORK_COREHAPTICS) if(HAVE_FRAMEWORK_GAMECONTROLLER AND HAVE_FRAMEWORK_COREHAPTICS) # Only enable MFI if we also have CoreHaptics to ensure rumble works set(SDL_JOYSTICK_MFI 1) @@ -1913,9 +1943,6 @@ elseif(APPLE) endif() set(SOURCE_FILES ${SOURCE_FILES} ${HAPTIC_SOURCES}) set(HAVE_SDL_HAPTIC TRUE) - if(NOT SDL_JOYSTICK) - message(FATAL_ERROR "SDL_HAPTIC requires SDL_JOYSTICK to be enabled") - endif() endif() if(SDL_POWER) @@ -1947,8 +1974,6 @@ elseif(APPLE) if(SDL_FILESYSTEM) set(SDL_FILESYSTEM_COCOA 1) file(GLOB FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/cocoa/*.m) - # !!! FIXME: modern CMake doesn't need "LANGUAGE C" for Objective-C. - set_source_files_properties(${FILESYSTEM_SOURCES} PROPERTIES LANGUAGE C) set(SOURCE_FILES ${SOURCE_FILES} ${FILESYSTEM_SOURCES}) set(HAVE_SDL_FILESYSTEM TRUE) endif() @@ -1973,6 +1998,7 @@ elseif(APPLE) set(SDL_IPHONE_LAUNCHSCREEN 1) file(GLOB UIKITVIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/uikit/*.m) set(SOURCE_FILES ${SOURCE_FILES} ${UIKITVIDEO_SOURCES}) + set(HAVE_SDL_VIDEO TRUE) else() CheckCOCOA() if(SDL_OPENGL) @@ -1997,9 +2023,7 @@ elseif(APPLE) endif() if(SDL_VULKAN OR SDL_METAL OR SDL_RENDER_METAL) - set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -ObjC") - check_c_source_compiles(" + check_objc_source_compiles(" #include #import #import @@ -2007,32 +2031,26 @@ elseif(APPLE) #if (!TARGET_CPU_X86_64 && !TARGET_CPU_ARM64) #error Metal doesn't work on this configuration #endif - int main(void) { - return 0; - } - " HAVE_FRAMEWORK_METAL) - set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS}) + int main(int argc, char **argv) { return 0; }" HAVE_FRAMEWORK_METAL) if(HAVE_FRAMEWORK_METAL) set(SDL_FRAMEWORK_METAL 1) set(SDL_FRAMEWORK_QUARTZCORE 1) - else() - set(SDL_VULKAN 0) - set(SDL_METAL 0) - set(SDL_RENDER_METAL 0) + if(SDL_VULKAN) + set(SDL_VIDEO_VULKAN 1) + set(HAVE_VULKAN TRUE) + endif() + if(SDL_METAL) + set(SDL_VIDEO_METAL 1) + set(HAVE_METAL TRUE) + endif() + if(SDL_RENDER_METAL) + file(GLOB RENDER_METAL_SOURCES ${SDL2_SOURCE_DIR}/src/render/metal/*.m) + set(SOURCE_FILES ${SOURCE_FILES} ${RENDER_METAL_SOURCES}) + set(SDL_VIDEO_RENDER_METAL 1) + set(HAVE_RENDER_METAL TRUE) + endif() endif() endif() - - if(SDL_METAL) - set(SDL_VIDEO_METAL 1) - set(HAVE_METAL TRUE) - endif() - - if(SDL_RENDER_METAL) - file(GLOB RENDER_METAL_SOURCES ${SDL2_SOURCE_DIR}/src/render/metal/*.m) - set(SOURCE_FILES ${SOURCE_FILES} ${RENDER_METAL_SOURCES}) - set(SDL_VIDEO_RENDER_METAL 1) - set(HAVE_RENDER_METAL TRUE) - endif() endif() # Actually load the frameworks at the end so we don't duplicate include. @@ -2138,9 +2156,11 @@ elseif(HAIKU) set(HAVE_SDL_JOYSTICK TRUE) endif() - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/haiku/*.cc) - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + if(SDL_MISC) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/haiku/*.cc) + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_HAIKU 1) @@ -2192,9 +2212,11 @@ elseif(HAIKU) list(APPEND EXTRA_LIBS root be media game device textencoding) elseif(RISCOS) - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/riscos/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + if(SDL_MISC) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/riscos/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_RISCOS 1) @@ -2234,9 +2256,11 @@ elseif(VITA) set_source_files_properties(${SDL2_SOURCE_DIR}/src/atomic/SDL_spinlock.c PROPERTIES COMPILE_FLAGS -marm) endif() - file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/vita/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) - set(HAVE_SDL_MISC TRUE) + if(SDL_MISC) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/vita/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) + set(HAVE_SDL_MISC TRUE) + endif() if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_VITA 1) @@ -2272,6 +2296,11 @@ elseif(VITA) ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c) set(HAVE_SDL_THREADS TRUE) endif() + if(SDL_LOCALE) + file(GLOB LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/vita/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${LOCALE_SOURCES}) + set(HAVE_SDL_LOCALE TRUE) + endif() if(SDL_TIMERS) set(SDL_TIMER_VITA 1) file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/vita/*.c) @@ -2298,10 +2327,10 @@ elseif(VITA) list(APPEND EXTRA_LIBS pib ) - set(HAVE_VITA_PIB ON) + set(HAVE_VIDEO_VITA_PIB ON) set(SDL_VIDEO_VITA_PIB 1) else() - set(HAVE_VITA_PIB OFF) + set(HAVE_VIDEO_VITA_PIB OFF) endif() endif() @@ -2309,6 +2338,7 @@ elseif(VITA) check_include_file(gpu_es4/psp2_pvr_hint.h HAVE_PVR_H) if(HAVE_PVR_H) target_compile_definitions(sdl-build-options INTERFACE "-D__psp2__") + check_include_file(gl4esinit.h HAVE_GL4ES_H) set(SDL_VIDEO_OPENGL_EGL 1) set(HAVE_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES 1) @@ -2320,10 +2350,20 @@ elseif(VITA) libgpu_es4_ext_stub_weak libIMGEGL_stub_weak ) - set(HAVE_VITA_PVR ON) + + set(HAVE_VIDEO_VITA_PVR ON) set(SDL_VIDEO_VITA_PVR 1) + + if(HAVE_GL4ES_H) + set(HAVE_OPENGL TRUE) + set(SDL_VIDEO_OPENGL 1) + set(SDL_VIDEO_RENDER_OGL 1) + list(APPEND EXTRA_LIBS libGL_stub) + set(SDL_VIDEO_VITA_PVR_OGL 1) + endif() + else() - set(HAVE_VITA_PVR OFF) + set(HAVE_VIDEO_VITA_PVR OFF) endif() endif() @@ -2335,6 +2375,7 @@ elseif(VITA) SceCtrl_stub SceAppMgr_stub SceAudio_stub + SceAudioIn_stub SceSysmodule_stub SceDisplay_stub SceCtrl_stub @@ -2444,16 +2485,82 @@ elseif(PSP) pspvram GL ) -endif() -if(SDL_VULKAN AND NOT SDL_LOADSO) - message(STATUS "Vulkan support is available, but disabled because there's no loadso.") - set(SDL_VULKAN OFF) +elseif(OS2) + list(APPEND EXTRA_CFLAGS "-DOS2EMX_PLAIN_CHAR") + + file(GLOB CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${CORE_SOURCES}) + if(NOT (HAVE_ICONV AND HAVE_ICONV_H)) + file(GLOB CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/os2/geniconv/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${CORE_SOURCES}) + endif() + + if(SDL_THREADS) + set(SDL_THREAD_OS2 1) + file(GLOB OS2_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_THREAD_SOURCES}) + set(HAVE_SDL_THREADS TRUE) + endif() + + if(SDL_TIMERS) + set(SDL_TIMER_UNIX 1) + file(GLOB OS2_TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_TIMER_SOURCES}) + set(HAVE_SDL_TIMERS TRUE) + endif() + + if(SDL_LOADSO) + set(SDL_LOADSO_OS2 1) + file(GLOB OS2_LOADSO_SOURCES ${SDL2_SOURCE_DIR}/src/loadso/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_LOADSO_SOURCES}) + set(HAVE_SDL_LOADSO TRUE) + endif() + + if(SDL_FILESYSTEM) + set(SDL_FILESYSTEM_OS2 1) + file(GLOB FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${FILESYSTEM_SOURCES}) + set(HAVE_SDL_FILESYSTEM TRUE) + endif() + + if(SDL_LOCALE) + file(GLOB LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/unix/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${LOCALE_SOURCES}) + set(HAVE_SDL_LOCALE TRUE) + endif() + + if(SDL_VIDEO) + set(SDL_VIDEO_DRIVER_OS2 1) + file(GLOB OS2_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_VIDEO_SOURCES}) + set(HAVE_SDL_VIDEO TRUE) + endif() + + if(SDL_AUDIO) + set(SDL_AUDIO_DRIVER_OS2 1) + file(GLOB OS2_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_AUDIO_SOURCES}) + set(HAVE_SDL_AUDIO TRUE) + list(APPEND EXTRA_LIBS mmpm2) + endif() + + if(SDL_JOYSTICK) + set(SDL_JOYSTICK_OS2 1) + file(GLOB OS2_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/os2/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${OS2_JOYSTICK_SOURCES}) + set(HAVE_SDL_JOYSTICK TRUE) + endif() + + if(SDL_HIDAPI) + CheckHIDAPI() + endif() endif() -if(SDL_VULKAN) - set(SDL_VIDEO_VULKAN 1) - set(HAVE_VULKAN TRUE) +if(HAVE_VULKAN AND NOT SDL_LOADSO) + message(STATUS "Vulkan support is available, but disabled because there's no loadso.") + set(HAVE_VULKAN FALSE) + set(SDL_VIDEO_VULKAN 0) endif() # Dummies @@ -2464,12 +2571,20 @@ endif() # so it always adds a dummy, without checking, if it was actually requested. # This leads to missing internal references on building, since the # src/X/*.c does not get included. +if(NOT HAVE_SDL_AUDIO) + set(SDL_AUDIO_DRIVER_DUMMY 1) + file(GLOB AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/dummy/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${AUDIO_SOURCES}) +endif() +if(NOT HAVE_SDL_VIDEO) + set(SDL_VIDEO_DRIVER_DUMMY 1) + file(GLOB VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/dummy/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${VIDEO_SOURCES}) +endif() if(NOT HAVE_SDL_JOYSTICK) set(SDL_JOYSTICK_DUMMY 1) - if(SDL_JOYSTICK AND NOT APPLE) # results in unresolved symbols on OSX - file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/dummy/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES}) - endif() + file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/dummy/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES}) endif() if(NOT HAVE_SDL_HAPTIC) set(SDL_HAPTIC_DUMMY 1) @@ -2482,24 +2597,24 @@ if(NOT HAVE_SDL_SENSORS) set(SOURCE_FILES ${SOURCE_FILES} ${SENSORS_SOURCES}) endif() if(NOT HAVE_SDL_LOADSO) - set(SDL_LOADSO_DISABLED 1) + set(SDL_LOADSO_DUMMY 1) file(GLOB LOADSO_SOURCES ${SDL2_SOURCE_DIR}/src/loadso/dummy/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${LOADSO_SOURCES}) endif() if(NOT HAVE_SDL_FILESYSTEM) - set(SDL_FILESYSTEM_DISABLED 1) + set(SDL_FILESYSTEM_DUMMY 1) file(GLOB FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/dummy/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${FILESYSTEM_SOURCES}) endif() if(NOT HAVE_SDL_LOCALE) - set(SDL_LOCALE_DISABLED 1) + set(SDL_LOCALE_DUMMY 1) file(GLOB LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/dummy/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${LOCALE_SOURCES}) endif() if(NOT HAVE_SDL_MISC) - set(SDL_MISC_DISABLED 1) - file(GLOB LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/misc/dummy/*.c) - set(SOURCE_FILES ${SOURCE_FILES} ${LOCALE_SOURCES}) + set(SDL_MISC_DUMMY 1) + file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/dummy/*.c) + set(SOURCE_FILES ${SOURCE_FILES} ${MISC_SOURCES}) endif() # We always need to have threads and timers around @@ -2509,7 +2624,7 @@ if(NOT HAVE_SDL_THREADS) set(SOURCE_FILES ${SOURCE_FILES} ${THREADS_SOURCES}) endif() if(NOT HAVE_SDL_TIMERS) - set(SDL_TIMERS_DISABLED 1) + set(SDL_TIMER_DUMMY 1) file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/dummy/*.c) set(SOURCE_FILES ${SOURCE_FILES} ${TIMER_SOURCES}) endif() @@ -2762,8 +2877,8 @@ endif() # Ensure that the extra cflags are used at compile time set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") -# Always build SDLmain -if(NOT WINDOWS_STORE) +if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) + # Build SDLmain add_library(SDL2main STATIC ${SDLMAIN_SOURCES}) # alias target for in-tree builds add_library(SDL2::SDL2main ALIAS SDL2main) @@ -2799,6 +2914,9 @@ if(SDL_SHARED) if(WINDOWS OR CYGWIN) set_target_properties(SDL2 PROPERTIES DEFINE_SYMBOL DLL_EXPORT) + elseif(OS2) + set_target_properties(SDL2 PROPERTIES + DEFINE_SYMBOL BUILD_SDL) endif() set_target_properties(SDL2 PROPERTIES VERSION ${SDL_VERSION} @@ -2866,120 +2984,125 @@ if(SDL_TEST) endif() ##### Installation targets ##### -if(SDL_SHARED) - install(TARGETS SDL2 EXPORT SDL2Targets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() - -if(NOT WINDOWS_STORE) - install(TARGETS SDL2main EXPORT SDL2mainTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() +if(NOT SDL2_DISABLE_INSTALL) + if(SDL_SHARED) + install(TARGETS SDL2 EXPORT SDL2Targets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() -if(SDL_STATIC) - install(TARGETS SDL2-static EXPORT SDL2staticTargets - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") -endif() + if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) + install(TARGETS SDL2main EXPORT SDL2mainTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() -##### Export files ##### -if (WINDOWS AND NOT MINGW) - set(PKG_PREFIX "cmake") -else () - set(PKG_PREFIX "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2") -endif () + if(SDL_STATIC) + install(TARGETS SDL2-static EXPORT SDL2staticTargets + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + endif() + + ##### Export files ##### + if (WINDOWS AND NOT MINGW) + set(PKG_PREFIX "cmake") + else () + set(PKG_PREFIX "${CMAKE_INSTALL_LIBDIR}/cmake/SDL2") + endif () + + include(CMakePackageConfigHelpers) + write_basic_package_version_file("${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake" + VERSION ${SDL_VERSION} + COMPATIBILITY AnyNewerVersion + ) -include(CMakePackageConfigHelpers) -write_basic_package_version_file("${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake" - VERSION ${SDL_VERSION} - COMPATIBILITY AnyNewerVersion -) + if(SDL_SHARED) + install(EXPORT SDL2Targets + FILE SDL2Targets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() -if(SDL_SHARED) - install(EXPORT SDL2Targets - FILE SDL2Targets.cmake - NAMESPACE SDL2:: - DESTINATION ${PKG_PREFIX} - ) -endif() + if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN) + install(EXPORT SDL2mainTargets + FILE SDL2mainTargets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() -if(NOT WINDOWS_STORE) - install(EXPORT SDL2mainTargets - FILE SDL2mainTargets.cmake - NAMESPACE SDL2:: - DESTINATION ${PKG_PREFIX} - ) -endif() + if(SDL_STATIC) + install(EXPORT SDL2staticTargets + FILE SDL2staticTargets.cmake + NAMESPACE SDL2:: + DESTINATION ${PKG_PREFIX} + ) + endif() -if(SDL_STATIC) - install(EXPORT SDL2staticTargets - FILE SDL2staticTargets.cmake - NAMESPACE SDL2:: + install( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake + ${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake DESTINATION ${PKG_PREFIX} + COMPONENT Devel ) -endif() - -install( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake - ${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake - DESTINATION ${PKG_PREFIX} - COMPONENT Devel -) - -file(GLOB INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/*.h) -file(GLOB BIN_INCLUDE_FILES ${SDL2_BINARY_DIR}/include/*.h) -foreach(_FNAME ${BIN_INCLUDE_FILES}) - get_filename_component(_INCNAME ${_FNAME} NAME) - list(REMOVE_ITEM INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/${_INCNAME}) -endforeach() -list(APPEND INCLUDE_FILES ${BIN_INCLUDE_FILES}) -install(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SDL2) -string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) -if (UPPER_BUILD_TYPE MATCHES DEBUG) - set(SOPOSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}") -else() - set(SOPOSTFIX "") -endif() - -if(NOT (WINDOWS OR CYGWIN) OR MINGW) - if(SDL_SHARED) - set(SOEXT ${CMAKE_SHARED_LIBRARY_SUFFIX}) # ".so", ".dylib", etc. - get_target_property(SONAME SDL2 OUTPUT_NAME) - if(NOT ANDROID AND NOT MINGW) - install(CODE " - execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink - \"lib${SONAME}${SOPOSTFIX}${SOEXT}\" \"libSDL2${SOPOSTFIX}${SOEXT}\" - WORKING_DIRECTORY \"${SDL2_BINARY_DIR}\")") - install(FILES ${SDL2_BINARY_DIR}/libSDL2${SOPOSTFIX}${SOEXT} DESTINATION "${CMAKE_INSTALL_LIBDIR}") - endif() - endif() - if(FREEBSD) - # FreeBSD uses ${PREFIX}/libdata/pkgconfig - install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "libdata/pkgconfig") + file(GLOB INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/*.h) + file(GLOB BIN_INCLUDE_FILES ${SDL2_BINARY_DIR}/include/*.h) + foreach(_FNAME ${BIN_INCLUDE_FILES}) + get_filename_component(_INCNAME ${_FNAME} NAME) + list(REMOVE_ITEM INCLUDE_FILES ${SDL2_SOURCE_DIR}/include/${_INCNAME}) + endforeach() + list(APPEND INCLUDE_FILES ${BIN_INCLUDE_FILES}) + install(FILES ${INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/SDL2) + + string(TOUPPER "${CMAKE_BUILD_TYPE}" UPPER_BUILD_TYPE) + if (UPPER_BUILD_TYPE MATCHES DEBUG) + set(SOPOSTFIX "${SDL_CMAKE_DEBUG_POSTFIX}") else() - install(FILES ${SDL2_BINARY_DIR}/sdl2.pc - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + set(SOPOSTFIX "") + endif() + + if(NOT (WINDOWS OR CYGWIN) OR MINGW) + if(SDL_SHARED) + set(SOEXT ${CMAKE_SHARED_LIBRARY_SUFFIX}) # ".so", ".dylib", etc. + get_target_property(SONAME SDL2 OUTPUT_NAME) + if(NOT ANDROID AND NOT MINGW AND NOT OS2) + install(CODE " + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink + \"lib${SONAME}${SOPOSTFIX}${SOEXT}\" \"libSDL2${SOPOSTFIX}${SOEXT}\" + WORKING_DIRECTORY \"${SDL2_BINARY_DIR}\")") + install(FILES ${SDL2_BINARY_DIR}/libSDL2${SOPOSTFIX}${SOEXT} DESTINATION "${CMAKE_INSTALL_LIBDIR}") + endif() + endif() + if(FREEBSD) + # FreeBSD uses ${PREFIX}/libdata/pkgconfig + install(FILES ${SDL2_BINARY_DIR}/sdl2.pc DESTINATION "libdata/pkgconfig") + else() + install(FILES ${SDL2_BINARY_DIR}/sdl2.pc + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() + install(PROGRAMS ${SDL2_BINARY_DIR}/sdl2-config DESTINATION "${CMAKE_INSTALL_BINDIR}") + # TODO: what about the .spec file? Is it only needed for RPM creation? + install(FILES "${SDL2_SOURCE_DIR}/sdl2.m4" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/aclocal") endif() - install(PROGRAMS ${SDL2_BINARY_DIR}/sdl2-config DESTINATION "${CMAKE_INSTALL_BINDIR}") - # TODO: what about the .spec file? Is it only needed for RPM creation? - install(FILES "${SDL2_SOURCE_DIR}/sdl2.m4" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/aclocal") endif() ##### Uninstall target ##### -if(NOT TARGET uninstall) - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) +if(NOT SDL2_DISABLE_UNINSTALL) + if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) - add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) + endif() endif() + diff --git a/INSTALL.txt b/INSTALL.txt index efb01d26c..f570cb33f 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -8,10 +8,10 @@ To compile and install SDL: * Read the FAQ at https://wiki.libsdl.org/FAQWindows * Run './configure; make; make install' - Mac OS X with Xcode: + macOS with Xcode: * Read docs/README-macosx.md - Mac OS X from the command line: + macOS from the command line: * Run './configure; make; make install' Linux and other UNIX systems: diff --git a/Makefile.in b/Makefile.in index f72ef2f4d..69f5cb1e2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -19,6 +19,7 @@ distfile = $(distdir).tar.gz @SET_MAKE@ SHELL = @SHELL@ CC = @CC@ +CXX = @CXX@ INCLUDE = @INCLUDE@ CFLAGS = @BUILD_CFLAGS@ EXTRA_CFLAGS = @EXTRA_CFLAGS@ @@ -49,7 +50,7 @@ WAYLAND_SCANNER_CODE_MODE = @WAYLAND_SCANNER_CODE_MODE@ INSTALL_SDL2_CONFIG = @INSTALL_SDL2_CONFIG@ -SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac debian docs include Makefile.* sdl2-config.cmake.in sdl2-config-version.cmake.in sdl2-config.in sdl2.m4 sdl2.pc.in SDL2.spec.in SDL2Config.cmake src test VisualC VisualC-WinRT Xcode Xcode-iOS wayland-protocols +SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac docs include Makefile.* sdl2-config.cmake.in sdl2-config-version.cmake.in sdl2-config.in sdl2.m4 sdl2.pc.in SDL2.spec.in SDL2Config.cmake src test VisualC VisualC-WinRT Xcode Xcode-iOS wayland-protocols GEN_DIST = SDL2.spec ifneq ($V,1) diff --git a/Makefile.os2 b/Makefile.os2 index 6af282d52..cfd0d6562 100644 --- a/Makefile.os2 +++ b/Makefile.os2 @@ -11,7 +11,7 @@ # wmake -f Makefile.os2 HIDAPI=1 LIBNAME = SDL2 -VERSION = 2.0.20 +VERSION = 2.0.22 DESCRIPTION = Simple DirectMedia Layer 2 LIBICONV=0 @@ -28,7 +28,13 @@ INCPATH+= -Iinclude LIBM = SDL2libm.lib TLIB = SDL2test.lib LIBS = mmpm2.lib $(LIBM) -CFLAGS = -bt=os2 -d0 -q -bm -5s -fp5 -fpi87 -sg -oteanbmier -ei +CFLAGS = -bt=os2 -d0 -q -bm -5s -fp5 -fpi87 -sg -oeatxhn -ei +# Debug options: +# - debug messages from OS/2 related code to stdout: +#CFLAGS+= -DOS2DEBUG +# - debug messages from OS/2 code via SDL_LogDebug(): +#CFLAGS+= -DOS2DEBUG=2 + # max warnings: CFLAGS+= -wx # newer OpenWatcom versions enable W303 by default @@ -54,13 +60,7 @@ CFLAGS_DLL+= -DHAVE_LIBUSB_H=1 # building SDL itself (for DECLSPEC): CFLAGS_DLL+= -DBUILD_SDL -# Debug options: -# - debug messages from OS/2 related code to stdout: -#CFLAGS+= -DOS2DEBUG -# - debug messages from OS/2 code via SDL_LogDebug(): -#CFLAGS+= -DOS2DEBUG=2 - -SRCS = SDL.c SDL_assert.c SDL_error.c SDL_log.c SDL_dataqueue.c SDL_hints.c +SRCS = SDL.c SDL_assert.c SDL_error.c SDL_log.c SDL_dataqueue.c SDL_hints.c SDL_list.c SRCS+= SDL_getenv.c SDL_iconv.c SDL_malloc.c SDL_qsort.c SDL_stdlib.c SDL_string.c SDL_strtokr.c SDL_crc32.c SRCS+= SDL_cpuinfo.c SDL_atomic.c SDL_spinlock.c SDL_thread.c SDL_timer.c SRCS+= SDL_rwops.c SDL_power.c @@ -140,9 +140,11 @@ SDL_blendpoint.obj: SDL_blendpoint.c wcc386 $(CFLAGS_DLL) -wcd=200 -fo=$^@ $< SDL_RLEaccel.obj: SDL_RLEaccel.c wcc386 $(CFLAGS_DLL) -wcd=201 -fo=$^@ $< +!ifeq HIDAPI 1 # c99 mode needed because of structs with flexible array members in libusb.h SDL_hidapi.obj: SDL_hidapi.c wcc386 $(CFLAGS_DLL) -za99 -fo=$^@ $< +!endif $(LIBICONV_LIB): "src/core/os2/iconv2.lbc" @echo * Creating: $@ diff --git a/Makefile.psp b/Makefile.psp deleted file mode 100644 index 8e826dce0..000000000 --- a/Makefile.psp +++ /dev/null @@ -1,117 +0,0 @@ -# The threads code require a rather new PSP SDK with SceLwMutexWorkarea: -# https://github.com/pspdev/pspsdk/commit/276d9e3ca6fb26479ad050c21431b2a40f518365 -# -TARGET_LIB = libSDL2.a -EXTRA_TARGETS = libSDL2main.a -OBJS= src/SDL.o \ - src/SDL_assert.o \ - src/SDL_dataqueue.o \ - src/SDL_error.o \ - src/SDL_hints.o \ - src/SDL_log.o \ - src/atomic/SDL_atomic.o \ - src/atomic/SDL_spinlock.o \ - src/audio/SDL_audio.o \ - src/audio/SDL_audiocvt.o \ - src/audio/SDL_audiodev.o \ - src/audio/SDL_audiotypecvt.o \ - src/audio/SDL_mixer.o \ - src/audio/SDL_wave.o \ - src/audio/psp/SDL_pspaudio.o \ - src/cpuinfo/SDL_cpuinfo.o \ - src/events/SDL_clipboardevents.o \ - src/events/SDL_displayevents.o \ - src/events/SDL_dropevents.o \ - src/events/SDL_events.o \ - src/events/SDL_gesture.o \ - src/events/SDL_keyboard.o \ - src/events/SDL_mouse.o \ - src/events/SDL_quit.o \ - src/events/SDL_touch.o \ - src/events/SDL_windowevents.o \ - src/file/SDL_rwops.o \ - src/haptic/SDL_haptic.o \ - src/haptic/dummy/SDL_syshaptic.o \ - src/hidapi/SDL_hidapi.o \ - src/joystick/SDL_joystick.o \ - src/joystick/SDL_gamecontroller.o \ - src/joystick/psp/SDL_sysjoystick.o \ - src/joystick/virtual/SDL_virtualjoystick.o \ - src/power/SDL_power.o \ - src/power/psp/SDL_syspower.o \ - src/filesystem/psp/SDL_sysfilesystem.o \ - src/locale/SDL_locale.o \ - src/locale/dummy/SDL_syslocale.o \ - src/misc/SDL_url.o \ - src/misc/dummy/SDL_sysurl.o \ - src/render/SDL_render.o \ - src/render/SDL_yuv_sw.o \ - src/render/psp/SDL_render_psp.o \ - src/render/software/SDL_blendfillrect.o \ - src/render/software/SDL_blendline.o \ - src/render/software/SDL_blendpoint.o \ - src/render/software/SDL_drawline.o \ - src/render/software/SDL_drawpoint.o \ - src/render/software/SDL_render_sw.o \ - src/render/software/SDL_rotate.o \ - src/render/software/SDL_triangle.o \ - src/sensor/SDL_sensor.o \ - src/sensor/dummy/SDL_dummysensor.o \ - src/stdlib/SDL_getenv.o \ - src/stdlib/SDL_iconv.o \ - src/stdlib/SDL_malloc.o \ - src/stdlib/SDL_qsort.o \ - src/stdlib/SDL_stdlib.o \ - src/stdlib/SDL_string.o \ - src/stdlib/SDL_strtokr.o \ - src/thread/SDL_thread.o \ - src/thread/generic/SDL_systls.o \ - src/thread/psp/SDL_syssem.o \ - src/thread/psp/SDL_systhread.o \ - src/thread/psp/SDL_sysmutex.o \ - src/thread/psp/SDL_syscond.o \ - src/timer/SDL_timer.o \ - src/timer/psp/SDL_systimer.o \ - src/video/SDL_RLEaccel.o \ - src/video/SDL_blit.o \ - src/video/SDL_blit_0.o \ - src/video/SDL_blit_1.o \ - src/video/SDL_blit_A.o \ - src/video/SDL_blit_N.o \ - src/video/SDL_blit_auto.o \ - src/video/SDL_blit_copy.o \ - src/video/SDL_blit_slow.o \ - src/video/SDL_bmp.o \ - src/video/SDL_clipboard.o \ - src/video/SDL_fillrect.o \ - src/video/SDL_pixels.o \ - src/video/SDL_rect.o \ - src/video/SDL_stretch.o \ - src/video/SDL_surface.o \ - src/video/SDL_video.o \ - src/video/SDL_yuv.o \ - src/video/psp/SDL_pspevents.o \ - src/video/psp/SDL_pspvideo.o \ - src/video/psp/SDL_pspgl.o \ - src/video/psp/SDL_pspmouse.o \ - src/video/yuv2rgb/yuv_rgb.o - -SDLMAIN_OBJ = src/main/psp/SDL_psp_main.o -EXTRA_CLEAN = $(SDLMAIN_OBJ) - -INCDIR = ./include -CFLAGS = -g -O2 -G0 -Wall -D__PSP__ -DHAVE_OPENGL -CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti -ASFLAGS = $(CFLAGS) - -LIBDIR = -LIBS = -lGL -lGLU -lglut -lz \ - -lpspvfpu -lpsphprm -lpspsdk -lpspctrl -lpspumd -lpsprtc -lpsppower -lpspgum -lpspgu -lpspaudiolib -lpspaudio -lpsphttp -lpspssl -lpspwlan \ - -lpspnet_adhocmatching -lpspnet_adhoc -lpspnet_adhocctl -lm -lpspvram - -PSPSDK=$(shell psp-config --pspsdk-path) -include $(PSPSDK)/lib/build.mak - -libSDL2main.a: $(SDLMAIN_OBJ) - $(AR) cru $@ $^ - $(RANLIB) $@ diff --git a/Makefile.wiz b/Makefile.wiz deleted file mode 100644 index 34776dacf..000000000 --- a/Makefile.wiz +++ /dev/null @@ -1,88 +0,0 @@ -# Makefile to build the pandora SDL library -WIZSDK = /mythtv/media/devel/toolchains/openwiz/arm-openwiz-linux-gnu - -AR = $(WIZSDK)/bin/arm-openwiz-linux-gnu-ar -RANLIB = $(WIZSDK)/bin/arm-openwiz-linux-gnu-ranlib -CC = $(WIZSDK)/bin/arm-openwiz-linux-gnu-gcc -CXX = $(WIZSDK)/bin/arm-openwiz-linux-gnu-g++ -STRIP = $(WIZSDK)/bin/arm-openwiz-linux-gnu-strip - -CFLAGS = -Wall -fPIC -I./include -I$(WIZSDK)/include -DWIZ_GLES_LITE - -TARGET_STATIC = libSDL2.a -TARGET_SHARED = libSDL2.so - -SOURCES = \ - ./src/*.c \ - ./src/atomic/*.c \ - ./src/audio/*.c \ - ./src/audio/disk/*.c \ - ./src/audio/dsp/*.c \ - ./src/audio/dummy/*.c \ - ./src/cpuinfo/*.c \ - ./src/events/*.c \ - ./src/file/*.c \ - ./src/filesystem/unix/*.c \ - ./src/haptic/*.c \ - ./src/haptic/linux/*.c \ - ./src/hidapi/*.c \ - ./src/joystick/*.c \ - ./src/joystick/linux/*.c \ - ./src/loadso/dlopen/*.c \ - ./src/locale/*.c \ - ./src/locale/unix/*.c \ - ./src/misc/*.c \ - ./src/misc/unix/*.c \ - ./src/power/*.c \ - ./src/sensor/*.c \ - ./src/sensor/dummy/*.c \ - ./src/stdlib/*.c \ - ./src/thread/*.c \ - ./src/thread/pthread/SDL_syscond.c \ - ./src/thread/pthread/SDL_sysmutex.c \ - ./src/thread/pthread/SDL_syssem.c \ - ./src/thread/pthread/SDL_systhread.c \ - ./src/timer/*.c \ - ./src/timer/unix/*.c \ - ./src/video/*.c \ - ./src/video/yuv2rgb/*.c \ - ./src/video/dummy/*.c \ - ./src/video/pandora/*.c - -OBJECTS = $(shell echo $(SOURCES) | sed -e 's,\.c,\.o,g') - -all: config_copy $(TARGET_STATIC) $(TARGET_SHARED) - -$(TARGET_STATIC): $(OBJECTS) - $(AR) crv $@ $^ - $(RANLIB) $@ - -$(TARGET_SHARED): - $(CC) -shared -Wl,-soname,$(TARGET_SHARED).0 -o $(TARGET_SHARED).0.0.1 $(OBJECTS) - ln -s $(TARGET_SHARED).0.0.1 $(TARGET_SHARED).0 - ln -s $(TARGET_SHARED).0 $(TARGET_SHARED) - -config_copy: - cp include/SDL_config_wiz.h include/SDL_config.h - -clean: - rm -f $(TARGET_STATIC) $(TARGET_SHARED)* $(OBJECTS) - -install: - mkdir -p $(WIZSDK)/lib - mkdir -p $(WIZSDK)/include/SDL2 - cp -f $(TARGET_STATIC) $(WIZSDK)/lib - cp -f $(TARGET_SHARED).0.0.1 $(WIZSDK)/lib - rm -f $(WIZSDK)/lib/$(TARGET_SHARED).0 $(WIZSDK)/lib/$(TARGET_SHARED) - ln -s $(WIZSDK)/lib/$(TARGET_SHARED).0.0.1 $(WIZSDK)/lib/$(TARGET_SHARED).0 - ln -s $(WIZSDK)/lib/$(TARGET_SHARED).0 $(WIZSDK)/lib/$(TARGET_SHARED) - - cp $(TARGET_STATIC) ../../toolchain/libs - cp $(TARGET_SHARED).0.0.1 ../../toolchain/libs - rm -f ../../toolchain/libs/$(TARGET_SHARED).0 ../../toolchain/libs/$(TARGET_SHARED) - ln -s ../../toolchain/libs/$(TARGET_SHARED).0.0.1 ../../toolchain/libs/$(TARGET_SHARED).0 - ln -s ../../toolchain/libs/$(TARGET_SHARED).0 ../../toolchain/libs/$(TARGET_SHARED) - - cp $(TARGET_SHARED).0.0.1 ../nehe_demos/build/$(TARGET_SHARED).0 - cp -f include/*.h $(WIZSDK)/include/SDL2/ - cp -f include/*.h ../../toolchain/include/SDL2/ diff --git a/VisualC-WinRT/SDL-UWP.vcxproj b/VisualC-WinRT/SDL-UWP.vcxproj index e2dc5ebe3..c5c9aeeb5 100644 --- a/VisualC-WinRT/SDL-UWP.vcxproj +++ b/VisualC-WinRT/SDL-UWP.vcxproj @@ -144,6 +144,7 @@ + @@ -295,6 +296,7 @@ + @@ -414,10 +416,10 @@ true Windows Store 8.2 - 10.0.10069.0 - 10.0.10069.0 - 10.0.10240.0 - 10.0.10240.0 + 10.0.16299.0 + 10.0.16299.0 + 10.0.16299.0 + 10.0.16299.0 diff --git a/VisualC-WinRT/SDL-UWP.vcxproj.filters b/VisualC-WinRT/SDL-UWP.vcxproj.filters index 274244937..b9a9f823b 100644 --- a/VisualC-WinRT/SDL-UWP.vcxproj.filters +++ b/VisualC-WinRT/SDL-UWP.vcxproj.filters @@ -411,6 +411,9 @@ Source Files + + Source Files + Source Files @@ -780,6 +783,9 @@ Source Files + + Source Files + Source Files @@ -819,4 +825,4 @@ Source Files - \ No newline at end of file + diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj index 0e9062b56..0d1ab307c 100644 --- a/VisualC/SDL/SDL.vcxproj +++ b/VisualC/SDL/SDL.vcxproj @@ -369,6 +369,7 @@ + @@ -543,6 +544,7 @@ + diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters index da002cd3c..12162e458 100644 --- a/VisualC/SDL/SDL.vcxproj.filters +++ b/VisualC/SDL/SDL.vcxproj.filters @@ -401,6 +401,7 @@ + API Headers @@ -832,6 +833,7 @@ + audio diff --git a/WhatsNew.txt b/WhatsNew.txt index 922254315..2d4c5c7f4 100644 --- a/WhatsNew.txt +++ b/WhatsNew.txt @@ -1,6 +1,44 @@ This is a list of major changes in SDL's version history. +--------------------------------------------------------------------------- +2.0.22: +--------------------------------------------------------------------------- + +General: +* Added SDL_RenderGetWindow() to get the window associated with a renderer +* Added floating point rectangle functions: + * SDL_PointInFRect() + * SDL_FRectEmpty() + * SDL_FRectEquals() + * SDL_FRectEqualsEpsilon() + * SDL_HasIntersectionF() + * SDL_IntersectFRect() + * SDL_UnionFRect() + * SDL_EncloseFPoints() + * SDL_IntersectFRectAndLine() +* Added SDL_IsTextInputShown() which returns whether the IME window is currently shown +* Added SDL_ClearComposition() to dismiss the composition window without disabling IME input +* Added SDL_TEXTEDITING_EXT event for handling long composition text, and a hint SDL_HINT_IME_SUPPORT_EXTENDED_TEXT to enable it +* Added the hint SDL_HINT_MOUSE_RELATIVE_MODE_CENTER to control whether the mouse should be constrained to the whole window or the center of the window when relative mode is enabled +* The mouse is now automatically captured when mouse buttons are pressed, and the hint SDL_HINT_MOUSE_AUTO_CAPTURE allows you to control this behavior +* Added the hint SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL to let SDL know that a foreign window will be used with OpenGL +* Added the hint SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN to let SDL know that a foreign window will be used with Vulkan +* Added the hint SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE to specify whether an SDL_QUIT event will be delivered when the last application window is closed +* Added the hint SDL_HINT_JOYSTICK_ROG_CHAKRAM to control whether ROG Chakram mice show up as joysticks + +Windows: +* Added support for SDL_BLENDOPERATION_MINIMUM and SDL_BLENDOPERATION_MAXIMUM to the D3D9 renderer + +Linux: +* Compiling with Wayland support requires libwayland-client version 1.18.0 or later +* Added the hint SDL_HINT_X11_WINDOW_TYPE to specify the _NET_WM_WINDOW_TYPE of SDL windows +* Added the hint SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR to allow using libdecor with compositors that support xdg-decoration + +Android: +* Added SDL_AndroidSendMessage() to send a custom command to the SDL java activity + + --------------------------------------------------------------------------- 2.0.20: --------------------------------------------------------------------------- diff --git a/Xcode/SDL/Info-Framework.plist b/Xcode/SDL/Info-Framework.plist index 5f9ace084..49a711322 100644 --- a/Xcode/SDL/Info-Framework.plist +++ b/Xcode/SDL/Info-Framework.plist @@ -19,10 +19,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.0.20 + 2.0.22 CFBundleSignature SDLX CFBundleVersion - 2.0.20 + 2.0.22 diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj index b23a394b9..8858cfdd9 100644 --- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj @@ -111,6 +111,24 @@ A1626A582617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; A1626A592617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; A1626A5A2617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; }; + A1BB8B6327F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6427F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6527F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6627F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6727F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6827F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6927F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6A27F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6B27F6CF330057CFA8 /* SDL_list.c in Sources */ = {isa = PBXBuildFile; fileRef = A1BB8B6127F6CF320057CFA8 /* SDL_list.c */; }; + A1BB8B6C27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6D27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6E27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B6F27F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7027F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7127F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7227F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7327F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; + A1BB8B7427F6CF330057CFA8 /* SDL_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BB8B6227F6CF330057CFA8 /* SDL_list.h */; }; A7381E961D8B69D600B177DD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E951D8B69D600B177DD /* CoreAudio.framework */; }; A7381E971D8B6A0300B177DD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E931D8B69C300B177DD /* AudioToolbox.framework */; }; A75FCCFD23E25AB700529352 /* SDL_shaders_metal_tvos.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D8A8E323E2514000DCD162 /* SDL_shaders_metal_tvos.h */; }; @@ -3574,6 +3592,8 @@ 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = ""; }; A1626A3D2617006A003F1973 /* SDL_triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_triangle.c; sourceTree = ""; }; A1626A512617008C003F1973 /* SDL_triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_triangle.h; sourceTree = ""; }; + A1BB8B6127F6CF320057CFA8 /* SDL_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_list.c; sourceTree = ""; }; + A1BB8B6227F6CF330057CFA8 /* SDL_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_list.h; sourceTree = ""; }; A7381E931D8B69C300B177DD /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; A7381E951D8B69D600B177DD /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; A75FCEB323E25AB700529352 /* libSDL2.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libSDL2.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -4304,6 +4324,8 @@ A7D8A5AB23E2513D00DCD162 /* SDL_hints.c */, A7D8A58323E2513D00DCD162 /* SDL_internal.h */, A7D8A5DD23E2513D00DCD162 /* SDL_log.c */, + A1BB8B6127F6CF320057CFA8 /* SDL_list.c */, + A1BB8B6227F6CF330057CFA8 /* SDL_list.h */, A7D8A57123E2513D00DCD162 /* SDL.c */, ); name = "Library Source"; @@ -5284,6 +5306,7 @@ A75FCD4523E25AB700529352 /* SDL_gesture_c.h in Headers */, A75FCD4623E25AB700529352 /* SDL_shaders_gl.h in Headers */, A75FCD4723E25AB700529352 /* SDL_systhread_c.h in Headers */, + A1BB8B7327F6CF330057CFA8 /* SDL_list.h in Headers */, A75FCD4823E25AB700529352 /* SDL_keycode.h in Headers */, 5616CA63252BB35F005D5928 /* SDL_sysurl.h in Headers */, A75FCD4A23E25AB700529352 /* SDL_cocoakeyboard.h in Headers */, @@ -5509,6 +5532,7 @@ A75FCEFE23E25AC700529352 /* SDL_gesture_c.h in Headers */, A75FCEFF23E25AC700529352 /* SDL_shaders_gl.h in Headers */, A75FCF0023E25AC700529352 /* SDL_systhread_c.h in Headers */, + A1BB8B7427F6CF330057CFA8 /* SDL_list.h in Headers */, A75FCF0123E25AC700529352 /* SDL_keycode.h in Headers */, 5616CA66252BB361005D5928 /* SDL_sysurl.h in Headers */, A75FCF0323E25AC700529352 /* SDL_cocoakeyboard.h in Headers */, @@ -5707,6 +5731,7 @@ A769B0C623E259AE00872273 /* SDL_windowevents_c.h in Headers */, A769B0C823E259AE00872273 /* SDL_cocoavideo.h in Headers */, 5605721C2473688D00B46B66 /* SDL_syslocale.h in Headers */, + A1BB8B7127F6CF330057CFA8 /* SDL_list.h in Headers */, A769B0CA23E259AE00872273 /* SDL_uikitevents.h in Headers */, A769B0CB23E259AE00872273 /* SDL_gesture_c.h in Headers */, A769B0CC23E259AE00872273 /* SDL_shaders_gl.h in Headers */, @@ -5955,6 +5980,7 @@ A7D8A98E23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7423E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA5023E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6D27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98D23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99C23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A223E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6185,6 +6211,7 @@ A7D8A98F23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7523E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA5123E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6E27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98E23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99D23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A323E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6332,6 +6359,7 @@ A7D8BBAF23E2514500DCD162 /* SDL_windowevents_c.h in Headers */, A7D8AF0423E2514100DCD162 /* SDL_cocoavideo.h in Headers */, 5605721A2473688C00B46B66 /* SDL_syslocale.h in Headers */, + A1BB8B7027F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8ACC123E2514100DCD162 /* SDL_uikitevents.h in Headers */, A7D8BB3D23E2514500DCD162 /* SDL_gesture_c.h in Headers */, A7D8BA7723E2514400DCD162 /* SDL_shaders_gl.h in Headers */, @@ -6580,6 +6608,7 @@ A7D8A98D23E2514000DCD162 /* SDL_sensor_c.h in Headers */, A7D8BA7323E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8BA4F23E2514400DCD162 /* SDL_shaders_gles2.h in Headers */, + A1BB8B6C27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8B98C23E2514400DCD162 /* SDL_shaders_metal_ios.h in Headers */, A7D8B99B23E2514400DCD162 /* SDL_shaders_metal_osx.h in Headers */, A7D8B9A123E2514400DCD162 /* SDL_shaders_metal_tvos.h in Headers */, @@ -6796,6 +6825,7 @@ A7D8B29F23E2514200DCD162 /* vulkan_xlib.h in Headers */, A7D8B25D23E2514200DCD162 /* vulkan_vi.h in Headers */, A7D8B29923E2514200DCD162 /* vulkan_mir.h in Headers */, + A1BB8B6F27F6CF330057CFA8 /* SDL_list.h in Headers */, A7D8BB4E23E2514500DCD162 /* default_cursor.h in Headers */, A7D8B9FE23E2514400DCD162 /* SDL_render_sw_c.h in Headers */, A7D8BBED23E2574800DCD162 /* SDL_uikitappdelegate.h in Headers */, @@ -6918,6 +6948,7 @@ A7D8BB3E23E2514500DCD162 /* SDL_gesture_c.h in Headers */, A7D8BA7823E2514400DCD162 /* SDL_shaders_gl.h in Headers */, A7D8B42D23E2514300DCD162 /* SDL_systhread_c.h in Headers */, + A1BB8B7227F6CF330057CFA8 /* SDL_list.h in Headers */, DB313FDB17554B71006C0E22 /* SDL_keycode.h in Headers */, A7D8AE9323E2514100DCD162 /* SDL_cocoakeyboard.h in Headers */, A7D8ACE623E2514100DCD162 /* SDL_uikitvulkan.h in Headers */, @@ -7554,6 +7585,7 @@ A75FCE8423E25AB700529352 /* e_exp.c in Sources */, A75FCE8523E25AB700529352 /* SDL_quit.c in Sources */, A75FCE8623E25AB700529352 /* SDL_cocoawindow.m in Sources */, + A1BB8B6A27F6CF330057CFA8 /* SDL_list.c in Sources */, A75FCE8723E25AB700529352 /* SDL_sysmutex.c in Sources */, A75FCE8823E25AB700529352 /* SDL_syshaptic.c in Sources */, F3F07D61269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -7741,6 +7773,7 @@ A75FD03D23E25AC700529352 /* e_exp.c in Sources */, A75FD03E23E25AC700529352 /* SDL_quit.c in Sources */, A75FD03F23E25AC700529352 /* SDL_cocoawindow.m in Sources */, + A1BB8B6B27F6CF330057CFA8 /* SDL_list.c in Sources */, A75FD04023E25AC700529352 /* SDL_sysmutex.c in Sources */, A75FD04123E25AC700529352 /* SDL_syshaptic.c in Sources */, F3F07D62269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -7927,6 +7960,7 @@ A769B20F23E259AE00872273 /* SDL_syshaptic.c in Sources */, A769B21023E259AE00872273 /* e_exp.c in Sources */, F395C1A12569C68F00942BFF /* SDL_iokitjoystick.c in Sources */, + A1BB8B6827F6CF330057CFA8 /* SDL_list.c in Sources */, A769B21123E259AE00872273 /* SDL_quit.c in Sources */, A769B21223E259AE00872273 /* SDL_cocoawindow.m in Sources */, A769B21323E259AE00872273 /* SDL_sysmutex.c in Sources */, @@ -8116,6 +8150,7 @@ A7D8B43B23E2514300DCD162 /* SDL_sysmutex.c in Sources */, A7D8AAB123E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8B5CA23E2514300DCD162 /* SDL_rwopsbundlesupport.m in Sources */, + A1BB8B6427F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8AC1023E2514100DCD162 /* SDL_video.c in Sources */, 560572062473687700B46B66 /* SDL_syslocale.m in Sources */, F3F07D5B269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -8303,6 +8338,7 @@ A7D8B43C23E2514300DCD162 /* SDL_sysmutex.c in Sources */, A7D8AAB223E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8B5CB23E2514300DCD162 /* SDL_rwopsbundlesupport.m in Sources */, + A1BB8B6527F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8AC1123E2514100DCD162 /* SDL_video.c in Sources */, 560572072473687800B46B66 /* SDL_syslocale.m in Sources */, F3F07D5C269640160074468B /* SDL_hidapi_luna.c in Sources */, @@ -8489,6 +8525,7 @@ A7D8AADE23E2514100DCD162 /* SDL_syshaptic.c in Sources */, A7D8BAE923E2514500DCD162 /* e_exp.c in Sources */, F395C1A02569C68F00942BFF /* SDL_iokitjoystick.c in Sources */, + A1BB8B6727F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8BB8523E2514500DCD162 /* SDL_quit.c in Sources */, A7D8AEAA23E2514100DCD162 /* SDL_cocoawindow.m in Sources */, A7D8B43E23E2514300DCD162 /* SDL_sysmutex.c in Sources */, @@ -8665,6 +8702,7 @@ A7D8B55123E2514300DCD162 /* SDL_hidapi_switch.c in Sources */, A7D8B96223E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7523E2514500DCD162 /* SDL_clipboardevents.c in Sources */, + A1BB8B6327F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8BAB523E2514400DCD162 /* k_cos.c in Sources */, A7D8B54523E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97423E2514400DCD162 /* SDL_malloc.c in Sources */, @@ -8850,6 +8888,7 @@ A7D8B96523E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7823E2514500DCD162 /* SDL_clipboardevents.c in Sources */, A7D8BAB823E2514400DCD162 /* k_cos.c in Sources */, + A1BB8B6627F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8B54823E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97723E2514400DCD162 /* SDL_malloc.c in Sources */, A7D8BBF023E2574800DCD162 /* SDL_uikitclipboard.m in Sources */, @@ -9035,6 +9074,7 @@ A7D8B96723E2514400DCD162 /* SDL_strtokr.c in Sources */, A7D8BB7A23E2514500DCD162 /* SDL_clipboardevents.c in Sources */, A7D8BABA23E2514400DCD162 /* k_cos.c in Sources */, + A1BB8B6927F6CF330057CFA8 /* SDL_list.c in Sources */, A7D8B54A23E2514300DCD162 /* SDL_hidapijoystick.c in Sources */, A7D8B97923E2514400DCD162 /* SDL_malloc.c in Sources */, A7D8B8CB23E2514400DCD162 /* SDL_audio.c in Sources */, @@ -9111,7 +9151,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEPLOYMENT_POSTPROCESSING = YES; DYLIB_COMPATIBILITY_VERSION = 1.0.0; - DYLIB_CURRENT_VERSION = 19.2.0; + DYLIB_CURRENT_VERSION = 23.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_ALTIVEC_EXTENSIONS = YES; @@ -9195,7 +9235,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 1.0.0; - DYLIB_CURRENT_VERSION = 19.2.0; + DYLIB_CURRENT_VERSION = 23.0.0; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -9387,6 +9427,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_LINK_OBJC_RUNTIME = NO; + GCC_PREPROCESSOR_DEFINITIONS = GLES_SILENCE_DEPRECATION; GCC_SYMBOLS_PRIVATE_EXTERN = YES; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; @@ -9398,6 +9439,7 @@ buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; CLANG_LINK_OBJC_RUNTIME = NO; + GCC_PREPROCESSOR_DEFINITIONS = GLES_SILENCE_DEPRECATION; GCC_SYMBOLS_PRIVATE_EXTERN = YES; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; diff --git a/acinclude/libtool.m4 b/acinclude/libtool.m4 index df6496ee7..3236ddab0 100644 --- a/acinclude/libtool.m4 +++ b/acinclude/libtool.m4 @@ -1068,7 +1068,7 @@ _LT_EOF darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) - case ${MACOSX_DEPLOYMENT_TARGET},$host in + case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[[012]],*|,*powerpc*-darwin[[5-8]]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) diff --git a/android-project/app/build.gradle b/android-project/app/build.gradle index 8e59d9eb4..baa0edc8d 100644 --- a/android-project/app/build.gradle +++ b/android-project/app/build.gradle @@ -35,6 +35,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + applicationVariants.all { variant -> + tasks["merge${variant.name.capitalize()}Assets"] + .dependsOn("externalNativeBuild${variant.name.capitalize()}") + } if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) { sourceSets.main { jniLibs.srcDir 'libs' diff --git a/android-project/app/jni/src/Android.mk b/android-project/app/jni/src/Android.mk index 1adcb6e9a..04e006ae9 100644 --- a/android-project/app/jni/src/Android.mk +++ b/android-project/app/jni/src/Android.mk @@ -13,6 +13,6 @@ LOCAL_SRC_FILES := YourSourceHere.c LOCAL_SHARED_LIBRARIES := SDL2 -LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog +LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid include $(BUILD_SHARED_LIBRARY) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 8641ccf80..28f3c6776 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -63,6 +63,106 @@ */ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener { private static final String TAG = "SDL"; +/* + // Display InputType.SOURCE/CLASS of events and devices + // + // SDLActivity.debugSource(device.getSources(), "device[" + device.getName() + "]"); + // SDLActivity.debugSource(event.getSource(), "event"); + public static void debugSource(int sources, String prefix) { + int s = sources; + int s_copy = sources; + String cls = ""; + String src = ""; + int tst = 0; + int FLAG_TAINTED = 0x80000000; + + if ((s & InputDevice.SOURCE_CLASS_BUTTON) != 0) cls += " BUTTON"; + if ((s & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) cls += " JOYSTICK"; + if ((s & InputDevice.SOURCE_CLASS_POINTER) != 0) cls += " POINTER"; + if ((s & InputDevice.SOURCE_CLASS_POSITION) != 0) cls += " POSITION"; + if ((s & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) cls += " TRACKBALL"; + + + int s2 = s_copy & ~InputDevice.SOURCE_ANY; // keep class bits + s2 &= ~( InputDevice.SOURCE_CLASS_BUTTON + | InputDevice.SOURCE_CLASS_JOYSTICK + | InputDevice.SOURCE_CLASS_POINTER + | InputDevice.SOURCE_CLASS_POSITION + | InputDevice.SOURCE_CLASS_TRACKBALL); + + if (s2 != 0) cls += "Some_Unkown"; + + s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class; + + tst = InputDevice.SOURCE_BLUETOOTH_STYLUS; + if ((s & tst) == tst) src += " BLUETOOTH_STYLUS"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_DPAD; + if ((s & tst) == tst) src += " DPAD"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_GAMEPAD; + if ((s & tst) == tst) src += " GAMEPAD"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_HDMI; + if ((s & tst) == tst) src += " HDMI"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_JOYSTICK; + if ((s & tst) == tst) src += " JOYSTICK"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_KEYBOARD; + if ((s & tst) == tst) src += " KEYBOARD"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_MOUSE; + if ((s & tst) == tst) src += " MOUSE"; + s2 &= ~tst; + + if (Build.VERSION.SDK_INT >= 26) { + tst = InputDevice.SOURCE_MOUSE_RELATIVE; + if ((s & tst) == tst) src += " MOUSE_RELATIVE"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_ROTARY_ENCODER; + if ((s & tst) == tst) src += " ROTARY_ENCODER"; + s2 &= ~tst; + } + tst = InputDevice.SOURCE_STYLUS; + if ((s & tst) == tst) src += " STYLUS"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_TOUCHPAD; + if ((s & tst) == tst) src += " TOUCHPAD"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_TOUCHSCREEN; + if ((s & tst) == tst) src += " TOUCHSCREEN"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_TOUCH_NAVIGATION; + if ((s & tst) == tst) src += " TOUCH_NAVIGATION"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_TRACKBALL; + if ((s & tst) == tst) src += " TRACKBALL"; + s2 &= ~tst; + + tst = InputDevice.SOURCE_ANY; + if ((s & tst) == tst) src += " ANY"; + s2 &= ~tst; + + if (s == FLAG_TAINTED) src += " FLAG_TAINTED"; + s2 &= ~FLAG_TAINTED; + + if (s2 != 0) src += " Some_Unkown"; + + Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src); + } +*/ public static boolean mIsResumedCalled, mHasFocus; public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24); @@ -1204,8 +1304,21 @@ public static void initTouch() { for (int id : ids) { InputDevice device = InputDevice.getDevice(id); - if (device != null && (device.getSources() & InputDevice.SOURCE_TOUCHSCREEN) != 0) { - nativeAddTouch(device.getId(), device.getName()); + /* Allow SOURCE_TOUCHSCREEN and also Virtual InputDevices because they can send TOUCHSCREEN events */ + if (device != null && ((device.getSources() & InputDevice.SOURCE_TOUCHSCREEN) == InputDevice.SOURCE_TOUCHSCREEN + || device.isVirtual())) { + + int touchDevId = device.getId(); + /* + * Prevent id to be -1, since it's used in SDL internal for synthetic events + * Appears when using Android emulator, eg: + * adb shell input mouse tap 100 100 + * adb shell input touchscreen tap 100 100 + */ + if (touchDevId < 0) { + touchDevId -= 1; + } + nativeAddTouch(touchDevId, device.getName()); } } } @@ -1895,7 +2008,7 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { } } - if ((source & InputDevice.SOURCE_KEYBOARD) != 0) { + if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD) { if (event.getAction() == KeyEvent.ACTION_DOWN) { if (SDLActivity.isTextInputEvent(event)) { SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1); @@ -1908,7 +2021,7 @@ public boolean onKey(View v, int keyCode, KeyEvent event) { } } - if ((source & InputDevice.SOURCE_MOUSE) != 0) { + if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses // they are ignored here because sending them as mouse input to SDL is messy if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) { diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index 05e0f0cac..82373d9d6 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -255,23 +255,21 @@ protected SDLJoystick getJoystick(int device_id) { @Override public boolean handleMotionEvent(MotionEvent event) { - if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) { - int actionPointerIndex = event.getActionIndex(); - int action = event.getActionMasked(); - if (action == MotionEvent.ACTION_MOVE) { - SDLJoystick joystick = getJoystick(event.getDeviceId()); - if (joystick != null) { - for (int i = 0; i < joystick.axes.size(); i++) { - InputDevice.MotionRange range = joystick.axes.get(i); - /* Normalize the value to -1...1 */ - float value = (event.getAxisValue(range.getAxis(), actionPointerIndex) - range.getMin()) / range.getRange() * 2.0f - 1.0f; - SDLControllerManager.onNativeJoy(joystick.device_id, i, value); - } - for (int i = 0; i < joystick.hats.size() / 2; i++) { - int hatX = Math.round(event.getAxisValue(joystick.hats.get(2 * i).getAxis(), actionPointerIndex)); - int hatY = Math.round(event.getAxisValue(joystick.hats.get(2 * i + 1).getAxis(), actionPointerIndex)); - SDLControllerManager.onNativeHat(joystick.device_id, i, hatX, hatY); - } + int actionPointerIndex = event.getActionIndex(); + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_MOVE) { + SDLJoystick joystick = getJoystick(event.getDeviceId()); + if (joystick != null) { + for (int i = 0; i < joystick.axes.size(); i++) { + InputDevice.MotionRange range = joystick.axes.get(i); + /* Normalize the value to -1...1 */ + float value = (event.getAxisValue(range.getAxis(), actionPointerIndex) - range.getMin()) / range.getRange() * 2.0f - 1.0f; + SDLControllerManager.onNativeJoy(joystick.device_id, i, value); + } + for (int i = 0; i < joystick.hats.size() / 2; i++) { + int hatX = Math.round(event.getAxisValue(joystick.hats.get(2 * i).getAxis(), actionPointerIndex)); + int hatY = Math.round(event.getAxisValue(joystick.hats.get(2 * i + 1).getAxis(), actionPointerIndex)); + SDLControllerManager.onNativeHat(joystick.device_id, i, hatX, hatY); } } } @@ -319,6 +317,7 @@ public int getButtonMask(InputDevice joystickDevice) { KeyEvent.KEYCODE_BUTTON_X, KeyEvent.KEYCODE_BUTTON_Y, KeyEvent.KEYCODE_BACK, + KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_BUTTON_MODE, KeyEvent.KEYCODE_BUTTON_START, KeyEvent.KEYCODE_BUTTON_THUMBL, @@ -360,6 +359,7 @@ public int getButtonMask(InputDevice joystickDevice) { (1 << 2), // X -> X (1 << 3), // Y -> Y (1 << 4), // BACK -> BACK + (1 << 6), // MENU -> START (1 << 5), // MODE -> GUIDE (1 << 6), // START -> START (1 << 7), // THUMBL -> LEFTSTICK @@ -560,8 +560,6 @@ public boolean onGenericMotion(View v, MotionEvent event) { switch ( event.getSource() ) { case InputDevice.SOURCE_JOYSTICK: - case InputDevice.SOURCE_GAMEPAD: - case InputDevice.SOURCE_DPAD: return SDLControllerManager.handleJoystickMotionEvent(event); case InputDevice.SOURCE_MOUSE: @@ -691,8 +689,6 @@ public boolean onGenericMotion(View v, MotionEvent event) { switch ( event.getSource() ) { case InputDevice.SOURCE_JOYSTICK: - case InputDevice.SOURCE_GAMEPAD: - case InputDevice.SOURCE_DPAD: return SDLControllerManager.handleJoystickMotionEvent(event); case InputDevice.SOURCE_MOUSE: diff --git a/build-scripts/ltmain.sh b/build-scripts/ltmain.sh index c10d13d89..70a3e8253 100644 --- a/build-scripts/ltmain.sh +++ b/build-scripts/ltmain.sh @@ -7081,8 +7081,20 @@ func_mode_link () prev=xcompiler continue ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + # Solaris ld rejects as of 11.4. Refer to Oracle bug 22985199. + -pthread) + case $host in + *solaris2*) ;; + *) + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + ;; + esac + continue + ;; + -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" diff --git a/build-scripts/os2-buildbot.sh b/build-scripts/os2-buildbot.sh deleted file mode 100755 index ff4b5f64b..000000000 --- a/build-scripts/os2-buildbot.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# This is the script buildbot.libsdl.org uses to cross-compile SDL2 from -# x86 Linux to OS/2, using OpenWatcom. - -# The final zipfile can be unpacked on any machine that supports OpenWatcom -# (Windows, Linux, OS/2, etc). Point the compiler at the include directory -# and link against the SDL2.lib file. Ship the SDL2.dll with your app. - -if [ -z "$WATCOM" ]; then - echo "This script expects \$WATCOM to be set to the OpenWatcom install dir." 1>&2 - echo "This is often something like '/usr/local/share/watcom'" 1>&2 - exit 1 -fi -export PATH="$WATCOM/binl:$PATH" - -ZIPFILE="$1" -if [ -z $1 ]; then - ZIPFILE=sdl-os2.zip -fi -ZIPDIR=buildbot/SDL - -set -e -set -x - -cd `dirname "$0"` -cd .. - -rm -f $ZIPFILE -wmake -f Makefile.os2 -rm -rf $ZIPDIR -mkdir -p $ZIPDIR -chmod 644 SDL2.dll SDL2.lib SDL2test.lib -mv SDL2.dll SDL2.lib SDL2test.lib $ZIPDIR/ -cp -R include $ZIPDIR/ -zip -9r "buildbot/$ZIPFILE" $ZIPDIR - -wmake -f Makefile.os2 distclean - -set +x -echo "All done. Final installable is in $ZIPFILE ..."; diff --git a/build-scripts/winrtbuild.ps1 b/build-scripts/winrtbuild.ps1 index d03cccaf1..736e6e006 100644 --- a/build-scripts/winrtbuild.ps1 +++ b/build-scripts/winrtbuild.ps1 @@ -39,7 +39,7 @@ # # Base version of SDL, used for packaging purposes -$SDLVersion = "2.0.20" +$SDLVersion = "2.0.22" # Gets the .bat file that sets up an MSBuild environment, given one of # Visual Studio's, "PlatformToolset"s. diff --git a/cmake/macros.cmake b/cmake/macros.cmake index 84cb4c6dc..62621ddfa 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -92,12 +92,19 @@ macro(LISTTOSTRREV _LIST _OUTPUT) endforeach() endmacro() -macro(CHECK_OBJC_SOURCE_COMPILES SOURCE VAR) - set(PREV_REQUIRED_DEFS "${CMAKE_REQUIRED_DEFINITIONS}") - set(CMAKE_REQUIRED_DEFINITIONS "-x objective-c ${PREV_REQUIRED_DEFS}") - CHECK_C_SOURCE_COMPILES(${SOURCE} ${VAR}) - set(CMAKE_REQUIRED_DEFINITIONS "${PREV_REQUIRED_DEFS}") -endmacro() +if(${CMAKE_VERSION} VERSION_LESS "3.16.0") + macro(CHECK_OBJC_SOURCE_COMPILES SOURCE VAR) + set(PREV_REQUIRED_DEFS "${CMAKE_REQUIRED_DEFINITIONS}") + set(CMAKE_REQUIRED_DEFINITIONS "-x objective-c ${PREV_REQUIRED_DEFS}") + CHECK_C_SOURCE_COMPILES(${SOURCE} ${VAR}) + set(CMAKE_REQUIRED_DEFINITIONS "${PREV_REQUIRED_DEFS}") + endmacro() +else() + include(CheckOBJCSourceCompiles) + if (APPLE) + enable_language(OBJC) + endif() +endif() if(CMAKE_VERSION VERSION_LESS 3.13.0) macro(target_link_directories _TARGET _SCOPE) diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index a5c0ec1a9..8dcb39265 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -48,6 +48,7 @@ macro(CheckDLOPEN) int main(int argc, char **argv) { void *handle = dlopen(\"\", RTLD_NOW); const char *loaderror = (char *) dlerror(); + return 0; }" HAVE_DLOPEN) set(CMAKE_REQUIRED_LIBRARIES) endif() @@ -57,8 +58,7 @@ macro(CheckO_CLOEXEC) check_c_source_compiles(" #include int flag = O_CLOEXEC; - int main(void) { - }" HAVE_O_CLOEXEC) + int main(int argc, char **argv) { return 0; }" HAVE_O_CLOEXEC) endmacro() # Requires: @@ -68,12 +68,12 @@ macro(CheckOSS) set(OSS_HEADER_FILE "sys/soundcard.h") check_c_source_compiles(" #include - int main() { int arg = SNDCTL_DSP_SETFRAGMENT; }" OSS_FOUND) + int main(int argc, char **argv) { int arg = SNDCTL_DSP_SETFRAGMENT; return 0; }" OSS_FOUND) if(NOT OSS_FOUND) set(OSS_HEADER_FILE "soundcard.h") check_c_source_compiles(" #include - int main() { int arg = SNDCTL_DSP_SETFRAGMENT; }" OSS_FOUND) + int main(int argc, char **argv) { int arg = SNDCTL_DSP_SETFRAGMENT; return 0; }" OSS_FOUND) endif() if(OSS_FOUND) @@ -174,7 +174,7 @@ macro(CheckPulseAudio) set(SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC "\"${PULSE_SIMPLE_LIB_SONAME}\"") set(HAVE_PULSEAUDIO_SHARED TRUE) else() - list(APPEND EXTRA_LDFLAGS ${PKG_sPULSEAUDIO_LDFLAGS}) + list(APPEND EXTRA_LDFLAGS ${PKG_PULSEAUDIO_LDFLAGS}) endif() set(HAVE_SDL_AUDIO TRUE) endif() @@ -467,6 +467,8 @@ macro(CheckX11) else() list(APPEND EXTRA_LIBS ${X11_LIB} ${XEXT_LIB}) endif() + else() + list(APPEND EXTRA_LIBS ${X11_LIB} ${XEXT_LIB}) endif() set(CMAKE_REQUIRED_LIBRARIES ${X11_LIB} ${X11_LIB}) @@ -479,7 +481,8 @@ macro(CheckX11) XGenericEventCookie *cookie = &event.xcookie; XNextEvent(display, &event); XGetEventData(display, cookie); - XFreeEventData(display, cookie); }" HAVE_XGENERICEVENT) + XFreeEventData(display, cookie); + return 0; }" HAVE_XGENERICEVENT) if(HAVE_XGENERICEVENT) set(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1) endif() @@ -527,11 +530,10 @@ macro(CheckX11) #include int event_type = XI_TouchBegin; XITouchClassInfo *t; - Status XIAllowTouchEvents(Display *a,int b,unsigned int c,Window d,int f) - { + Status XIAllowTouchEvents(Display *a,int b,unsigned int c,Window d,int f) { return (Status)0; } - int main(int argc, char **argv) {}" HAVE_XINPUT2_MULTITOUCH) + int main(int argc, char **argv) { return 0; }" HAVE_XINPUT2_MULTITOUCH) if(HAVE_XINPUT2_MULTITOUCH) set(SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1) endif() @@ -545,7 +547,7 @@ macro(CheckX11) #include #include BarrierEventID b; - int main(void) { }" HAVE_XFIXES_H) + int main(int argc, char **argv) { return 0; }" HAVE_XFIXES_H) endif() if(SDL_X11_XFIXES AND HAVE_XFIXES_H AND HAVE_XINPUT2_H) if(HAVE_X11_SHARED AND XFIXES_LIB) @@ -630,7 +632,7 @@ endmacro() # - HAVE_SDL_LOADSO opt macro(CheckWayland) if(SDL_WAYLAND) - pkg_check_modules(WAYLAND wayland-client wayland-egl wayland-cursor egl "xkbcommon>=0.5.0") + pkg_check_modules(WAYLAND "wayland-client>=1.18" wayland-egl wayland-cursor egl "xkbcommon>=0.5.0") if(WAYLAND_FOUND) find_program(WAYLAND_SCANNER NAMES wayland-scanner REQUIRED) @@ -775,12 +777,12 @@ macro(CheckVivante) if(SDL_VIVANTE) check_c_source_compiles(" #include - int main(int argc, char** argv) {}" HAVE_VIVANTE_VDK) + int main(int argc, char** argv) { return 0; }" HAVE_VIVANTE_VDK) check_c_source_compiles(" #define LINUX #define EGL_API_FB #include - int main(int argc, char** argv) {}" HAVE_VIVANTE_EGL_FB) + int main(int argc, char** argv) { return 0; }" HAVE_VIVANTE_EGL_FB) if(HAVE_VIVANTE_VDK OR HAVE_VIVANTE_EGL_FB) set(HAVE_VIVANTE TRUE) set(HAVE_SDL_VIDEO TRUE) @@ -790,7 +792,9 @@ macro(CheckVivante) set(SDL_VIDEO_DRIVER_VIVANTE 1) if(HAVE_VIVANTE_VDK) set(SDL_VIDEO_DRIVER_VIVANTE_VDK 1) - list(APPEND EXTRA_LIBS VDK VIVANTE) + find_library(VIVANTE_LIBRARY REQUIRED NAMES VIVANTE vivante drm_vivante) + find_library(VIVANTE_VDK_LIBRARY VDK REQUIRED) + list(APPEND EXTRA_LIBS ${VIVANTE_LIBRARY} ${VIVANTE_VDK_LIBRARY}) else() set(SDL_CFLAGS "${SDL_CFLAGS} -DLINUX -DEGL_API_FB") list(APPEND EXTRA_LIBS EGL) @@ -805,7 +809,7 @@ macro(CheckGLX) if(SDL_OPENGL) check_c_source_compiles(" #include - int main(int argc, char** argv) {}" HAVE_OPENGL_GLX) + int main(int argc, char** argv) { return 0; }" HAVE_OPENGL_GLX) if(HAVE_OPENGL_GLX) set(SDL_VIDEO_OPENGL_GLX 1) endif() @@ -817,15 +821,14 @@ endmacro() macro(CheckEGL) if (SDL_OPENGL OR SDL_OPENGLES) pkg_check_modules(EGL egl) - string(REPLACE "-D_THREAD_SAFE;" "-D_THREAD_SAFE=1;" EGL_CFLAGS "${EGL_CFLAGS}") - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${EGL_CFLAGS}") + set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} ${EGL_CFLAGS}") check_c_source_compiles(" #define EGL_API_FB #define MESA_EGL_NO_X11_HEADERS #define EGL_NO_X11 #include #include - int main (int argc, char** argv) {}" HAVE_OPENGL_EGL) + int main (int argc, char** argv) { return 0; }" HAVE_OPENGL_EGL) if(HAVE_OPENGL_EGL) set(SDL_VIDEO_OPENGL_EGL 1) endif() @@ -839,7 +842,7 @@ macro(CheckOpenGL) check_c_source_compiles(" #include #include - int main(int argc, char** argv) {}" HAVE_OPENGL) + int main(int argc, char** argv) { return 0; }" HAVE_OPENGL) if(HAVE_OPENGL) set(SDL_VIDEO_OPENGL 1) set(SDL_VIDEO_RENDER_OGL 1) @@ -854,7 +857,7 @@ macro(CheckOpenGLES) check_c_source_compiles(" #include #include - int main (int argc, char** argv) {}" HAVE_OPENGLES_V1) + int main (int argc, char** argv) { return 0; }" HAVE_OPENGLES_V1) if(HAVE_OPENGLES_V1) set(HAVE_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES 1) @@ -863,7 +866,7 @@ macro(CheckOpenGLES) check_c_source_compiles(" #include #include - int main (int argc, char** argv) {}" HAVE_OPENGLES_V2) + int main (int argc, char** argv) { return 0; }" HAVE_OPENGLES_V2) if(HAVE_OPENGLES_V2) set(HAVE_OPENGLES TRUE) set(SDL_VIDEO_OPENGL_ES2 1) @@ -1170,10 +1173,12 @@ macro(CheckHIDAPI) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBUSB_CFLAGS}") if(HIDAPI_ONLY_LIBUSB) list(APPEND EXTRA_LIBS ${LIBUSB_LIBS}) + elseif(OS2) + set(SDL_LIBUSB_DYNAMIC "\"usb100.dll\"") else() # libusb is loaded dynamically, so don't add it to EXTRA_LIBS FindLibraryAndSONAME("usb-1.0") - set(SDL_LIBUSB_DYNAMIC "\"${USB_LIB_SONAME}\"") + set(SDL_LIBUSB_DYNAMIC "\"${USB_1.0_LIB_SONAME}\"") endif() endif() endif() diff --git a/configure b/configure index a02b8f93b..f3ea813eb 100755 --- a/configure +++ b/configure @@ -673,6 +673,8 @@ X_CFLAGS XMKMF RPI_LIBS RPI_CFLAGS +DECOR_LIBS +DECOR_CFLAGS FUSIONSOUND_LIBS FUSIONSOUND_CFLAGS ARTSCONFIG @@ -822,6 +824,8 @@ enable_filesystem enable_threads enable_timers enable_file +enable_misc +enable_locale enable_loadso enable_cpuinfo enable_assembly @@ -942,6 +946,8 @@ PULSEAUDIO_CFLAGS PULSEAUDIO_LIBS FUSIONSOUND_CFLAGS FUSIONSOUND_LIBS +DECOR_CFLAGS +DECOR_LIBS RPI_CFLAGS RPI_LIBS XMKMF @@ -1599,6 +1605,8 @@ Optional Features: --enable-threads Enable the threading subsystem [default=yes] --enable-timers Enable the timer subsystem [default=yes] --enable-file Enable the file subsystem [default=yes] + --enable-misc Enable the misc subsystem [default=yes] + --enable-locale Enable the locale subsystem [default=yes] --enable-loadso Enable the shared object loading subsystem [default=yes] --enable-cpuinfo Enable the cpuinfo subsystem [default=yes] @@ -1775,6 +1783,9 @@ Some influential environment variables: C compiler flags for FUSIONSOUND, overriding pkg-config FUSIONSOUND_LIBS linker flags for FUSIONSOUND, overriding pkg-config + DECOR_CFLAGS + C compiler flags for DECOR, overriding pkg-config + DECOR_LIBS linker flags for DECOR, overriding pkg-config RPI_CFLAGS C compiler flags for RPI, overriding pkg-config RPI_LIBS linker flags for RPI, overriding pkg-config XMKMF Path to xmkmf, Makefile generator for X Window System @@ -2855,9 +2866,9 @@ orig_CFLAGS="$CFLAGS" # SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=0 -SDL_MICRO_VERSION=20 -SDL_INTERFACE_AGE=2 -SDL_BINARY_AGE=20 +SDL_MICRO_VERSION=22 +SDL_INTERFACE_AGE=0 +SDL_BINARY_AGE=22 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION @@ -7120,7 +7131,7 @@ $as_echo "$lt_cv_ld_force_load" >&6; } darwin1.*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; darwin*) - case ${MACOSX_DEPLOYMENT_TARGET},$host in + case $MACOSX_DEPLOYMENT_TARGET,$host in 10.[012],*|,*powerpc*-darwin[5-8]*) _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; *) @@ -16999,9 +17010,8 @@ fi $as_echo_n "checking for linker option --no-undefined... " >&6; } have_no_undefined=no case "$host" in - *-*-openbsd*) + *-*-openbsd*) ;; - *) save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--no-undefined" @@ -17138,7 +17148,7 @@ if test x$enable_libc = xyes; then $as_echo "#define HAVE_LIBC 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 @@ -17264,7 +17274,7 @@ fi done - ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" + ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else @@ -17276,7 +17286,7 @@ _ACEOF fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for M_PI in math.h" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for M_PI in math.h" >&5 $as_echo_n "checking for M_PI in math.h... " >&6; } if ${ac_cv_define_M_PI+:} false; then : $as_echo_n "(cached) " >&6 @@ -17309,11 +17319,7 @@ $as_echo "#define HAVE_M_PI /**/" >>confdefs.h fi - case "$host" in - *-*-cygwin* | *-*-mingw*) - ;; - *) - # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works + # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } @@ -17499,8 +17505,6 @@ _ACEOF fi - ;; - esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } @@ -17840,7 +17844,7 @@ $as_echo "#define HAVE_SA_SIGACTION 1" >>confdefs.h fi - for ac_header in libunwind.h + for ac_header in libunwind.h do : ac_fn_c_check_header_mongrel "$LINENO" "libunwind.h" "ac_cv_header_libunwind_h" "$ac_includes_default" if test "x$ac_cv_header_libunwind_h" = xyes; then : @@ -17953,11 +17957,20 @@ SOURCES="$SOURCES $srcdir/src/video/yuv2rgb/*.c" SOURCES="$SOURCES $srcdir/src/locale/*.c" +case "$host" in + *-*-emscripten*) + default_atomic=no + ;; + *) + default_atomic=yes + ;; +esac + # Check whether --enable-atomic was given. if test "${enable_atomic+set}" = set; then : enableval=$enable_atomic; else - enable_atomic=yes + enable_atomic=$default_atomic fi if test x$enable_atomic != xyes; then @@ -18149,6 +18162,34 @@ $as_echo "#define SDL_FILE_DISABLED 1" >>confdefs.h else SUMMARY_modules="${SUMMARY_modules} file" fi +# Check whether --enable-misc was given. +if test "${enable_misc+set}" = set; then : + enableval=$enable_misc; +else + enable_misc=yes +fi + +if test x$enable_misc != xyes; then + +$as_echo "#define SDL_MISC_DISABLED 1" >>confdefs.h + +else + SUMMARY_modules="${SUMMARY_modules} misc" +fi +# Check whether --enable-locale was given. +if test "${enable_locale+set}" = set; then : + enableval=$enable_locale; +else + enable_locale=yes +fi + +if test x$enable_locale != xyes; then + +$as_echo "#define SDL_LOCALE_DISABLED 1" >>confdefs.h + +else + SUMMARY_modules="${SUMMARY_modules} locale" +fi # Check whether --enable-loadso was given. if test "${enable_loadso+set}" = set; then : enableval=$enable_loadso; @@ -18219,7 +18260,7 @@ fi fi fi - # Check whether --enable-mmx was given. + # Check whether --enable-mmx was given. if test "${enable_mmx+set}" = set; then : enableval=$enable_mmx; else @@ -20150,6 +20191,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_DISK 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/audio/disk/*.c" SUMMARY_audio="${SUMMARY_audio} disk" + have_audio=yes fi } @@ -20168,6 +20210,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_DUMMY 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/audio/dummy/*.c" SUMMARY_audio="${SUMMARY_audio} dummy" + have_audio=yes fi } @@ -20496,7 +20539,7 @@ $as_echo "$have_gcc_Wall" >&6; } if test x$have_gcc_Wall = xyes; then EXTRA_CFLAGS="$EXTRA_CFLAGS -Wall" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for necessary GCC -Wno-multichar option" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for necessary GCC -Wno-multichar option" >&5 $as_echo_n "checking for necessary GCC -Wno-multichar option... " >&6; } need_gcc_Wno_multichar=no case "$host" in @@ -20536,7 +20579,7 @@ $as_echo_n "checking for Wayland support... " >&6; } video_wayland=no if test x$video_opengl_egl = xyes && \ test x$video_opengles_v2 = xyes; then - if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then + if $PKG_CONFIG --exists 'wayland-client >= 1.18' wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` @@ -20577,7 +20620,8 @@ fi wayland_client_lib=`find_lib "libwayland-client.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` wayland_egl_lib=`find_lib "libwayland-egl.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` if test x$wayland_egl_lib = x; then - wayland_egl_lib=`find_lib "mesa-egl/libwayland-egl.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` + # This works in Ubuntu 13.10, maybe others + wayland_egl_lib=`find_lib "mesa-egl/libwayland-egl.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` fi wayland_cursor_lib=`find_lib "libwayland-cursor.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` xkbcommon_lib=`find_lib "libxkbcommon.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` @@ -20639,17 +20683,79 @@ else fi if test x$enable_libdecor = xyes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdecor support" >&5 -$as_echo_n "checking for libdecor support... " >&6; } - if $PKG_CONFIG --exists libdecor-0; then : - video_libdecor=yes + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libdecor-0" >&5 +$as_echo_n "checking for libdecor-0... " >&6; } + +if test -n "$DECOR_CFLAGS"; then + pkg_cv_DECOR_CFLAGS="$DECOR_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdecor-0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libdecor-0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DECOR_CFLAGS=`$PKG_CONFIG --cflags "libdecor-0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$DECOR_LIBS"; then + pkg_cv_DECOR_LIBS="$DECOR_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libdecor-0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "libdecor-0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_DECOR_LIBS=`$PKG_CONFIG --libs "libdecor-0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes else - video_libdecor=no + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + DECOR_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libdecor-0" 2>&1` + else + DECOR_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libdecor-0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$DECOR_PKG_ERRORS" >&5 + + video_libdecor=no +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + video_libdecor=no +else + DECOR_CFLAGS=$pkg_cv_DECOR_CFLAGS + DECOR_LIBS=$pkg_cv_DECOR_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + video_libdecor=yes fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $video_libdecor" >&5 -$as_echo "$video_libdecor" >&6; } if test x$video_libdecor = xyes; then - EXTRA_CFLAGS="$EXTRA_CFLAGS `$PKG_CONFIG --cflags libdecor-0`" + EXTRA_CFLAGS="$EXTRA_CFLAGS $DECOR_CFLAGS" $as_echo "#define HAVE_LIBDECOR_H 1" >>confdefs.h @@ -20662,18 +20768,16 @@ else fi + decor_lib=`find_lib "libdecor-0.so.*" "$DECOR_LIBS" | sed 's/.*\/\(.*\)/\1/; q'` + if test x$enable_wayland_shared != xyes; then enable_libdecor_shared=no fi - - decor_lib=`find_lib "libdecor-0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'` - if test x$have_loadso != xyes && \ test x$enable_libdecor_shared = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You must have SDL_LoadObject() support for dynamic libdecor loading" >&5 $as_echo "$as_me: WARNING: You must have SDL_LoadObject() support for dynamic libdecor loading" >&2;} fi - if test x$have_loadso = xyes && \ test x$enable_libdecor_shared = xyes && test x$decor_lib != x; then echo "-- dynamic libdecor -> $decor_lib" @@ -20683,7 +20787,7 @@ cat >>confdefs.h <<_ACEOF _ACEOF else - EXTRA_LDFLAGS="$EXTRA_LDFLAGS `$PKG_CONFIG --libs libdecor-0`" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS $DECOR_LIBS" fi fi fi @@ -20734,8 +20838,10 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.c" SOURCES="$SOURCES $srcdir/src/audio/nacl/*.c" SUMMARY_audio="${SUMMARY_audio} nacl" + have_audio=yes SOURCES="$SOURCES $srcdir/src/video/nacl/*.c" SUMMARY_video="${SUMMARY_video} nacl opengles2" + have_video=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext @@ -20880,6 +20986,7 @@ $as_echo "$have_video_rpi" >&6; } $as_echo "#define SDL_VIDEO_DRIVER_RPI 1" >>confdefs.h SUMMARY_video="${SUMMARY_video} rpi" + have_video=yes fi fi } @@ -21731,7 +21838,7 @@ _ACEOF fi have_video=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XGenericEvent" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XGenericEvent" >&5 $as_echo_n "checking for XGenericEvent... " >&6; } have_XGenericEvent=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22219,7 +22326,7 @@ else fi if test x$enable_video_x11_xrandr = xyes; then - definitely_enable_video_x11_xrandr=no + definitely_enable_video_x11_xrandr=no have_xrandr_h_hdr=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22601,7 +22708,7 @@ fi if test x$enable_video = xyes -a x$enable_video_cocoa = xyes; then save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -x objective-c" + CFLAGS="$CFLAGS -x objective-c" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Cocoa framework" >&5 $as_echo_n "checking for Cocoa framework... " >&6; } have_cocoa=no @@ -22654,7 +22761,7 @@ fi if test x$enable_video = xyes -a x$enable_video_metal = xyes; then save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -x objective-c" + CFLAGS="$CFLAGS -x objective-c" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Metal framework" >&5 $as_echo_n "checking for Metal framework... " >&6; } have_metal=no @@ -23592,7 +23699,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; *-*-darwin*) save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -x objective-c" + CFLAGS="$CFLAGS -x objective-c" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23645,7 +23752,7 @@ $as_echo "#define SDL_VIDEO_VULKAN 1" >>confdefs.h CheckInputEvents() { - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux 2.4 unified input interface" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux 2.4 unified input interface" >&5 $as_echo_n "checking for Linux 2.4 unified input interface... " >&6; } use_input_events=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -23681,7 +23788,6 @@ $as_echo "#define SDL_INPUT_LINUXEV 1" >>confdefs.h CheckInputKD() { - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux kd.h" >&5 $as_echo_n "checking for Linux kd.h... " >&6; } use_input_kd=no @@ -24161,7 +24267,7 @@ fi if test x$enable_joystick_mfi = xyes; then save_CFLAGS="$CFLAGS" save_LDFLAGS="$LDFLAGS" - CFLAGS="$CFLAGS -x objective-c -fobjc-weak" + CFLAGS="$CFLAGS -x objective-c -fobjc-weak" LDFLAGS="$LDFLAGS -Wl,-weak_framework,CoreHaptics -Wl,-weak_framework,GameController" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GameController framework" >&5 $as_echo_n "checking for GameController framework... " >&6; } @@ -24228,7 +24334,7 @@ else enable_pthreads=maybe fi - # Check whether --enable-pthread-sem was given. + # Check whether --enable-pthread-sem was given. if test "${enable_pthread_sem+set}" = set; then : enableval=$enable_pthread_sem; else @@ -24673,6 +24779,30 @@ $as_echo "$have_wince" >&6; } # This fixes Windows stack alignment with newer GCC CheckStackBoundary + + # headers needed elsewhere + ac_fn_c_check_header_mongrel "$LINENO" "tpcshrd.h" "ac_cv_header_tpcshrd_h" "$ac_includes_default" +if test "x$ac_cv_header_tpcshrd_h" = xyes; then : + have_tpcshrd_h=yes +fi + + + if test x$have_tpcshrd_h = xyes; then + +$as_echo "#define HAVE_TPCSHRD_H 1" >>confdefs.h + + fi + ac_fn_c_check_header_mongrel "$LINENO" "roapi.h" "ac_cv_header_roapi_h" "$ac_includes_default" +if test "x$ac_cv_header_roapi_h" = xyes; then : + have_roapi_h=yes +fi + + + if test x$have_roapi_h = xyes; then + +$as_echo "#define HAVE_ROAPI_H 1" >>confdefs.h + + fi } CheckOS2() @@ -25744,6 +25874,7 @@ case "$host" in $as_echo "#define SDL_VIDEO_DRIVER_ANDROID 1" >>confdefs.h SUMMARY_video="${SUMMARY_video} android" + have_video=yes fi ;; *-*-linux*) ARCH=linux ;; @@ -25825,12 +25956,16 @@ $as_echo "#define SDL_VIDEO_DRIVER_ANDROID 1" >>confdefs.h CheckRPATH CheckVivanteVideo - SOURCES="$SOURCES $srcdir/src/misc/unix/*.c" - have_misc=yes - - SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" - have_locale=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/unix/*.c" + have_misc=yes + fi + # Set up files for the locale library + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then case $ARCH in @@ -26042,12 +26177,16 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h # Set up the core platform files SOURCES="$SOURCES $srcdir/src/core/windows/*.c" - SOURCES="$SOURCES $srcdir/src/misc/windows/*.c" - have_misc=yes + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/windows/*.c" + have_misc=yes + fi # Use the Windows locale APIs. - SOURCES="$SOURCES $srcdir/src/locale/windows/*.c" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/windows/*.c" + have_locale=yes + fi # Set up files for the video library if test x$enable_video = xyes; then @@ -26140,17 +26279,6 @@ $as_echo "#define SDL_HAPTIC_DINPUT 1" >>confdefs.h have_haptic=yes fi fi - ac_fn_c_check_header_mongrel "$LINENO" "tpcshrd.h" "ac_cv_header_tpcshrd_h" "$ac_includes_default" -if test "x$ac_cv_header_tpcshrd_h" = xyes; then : - have_tpcshrd_h=yes -fi - - - if test x$have_tpcshrd_h = xyes; then - -$as_echo "#define HAVE_TPCSHRD_H 1" >>confdefs.h - - fi # Set up files for the sensor library ac_fn_c_check_header_mongrel "$LINENO" "sensorsapi.h" "ac_cv_header_sensorsapi_h" "$ac_includes_default" if test "x$ac_cv_header_sensorsapi_h" = xyes; then : @@ -26271,13 +26399,11 @@ fi SDL_LIBS="-lcygwin $SDL_LIBS" fi ;; - - *-*-beos*) + *-*-beos*) as_fn_error $? " *** BeOS support has been removed as of SDL 2.0.2. " "$LINENO" 5 ;; - *-*-haiku*) ARCH=haiku ac_default_prefix=/boot/system @@ -26332,14 +26458,16 @@ $as_echo "#define SDL_FILESYSTEM_HAIKU 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/filesystem/haiku/*.cc" have_filesystem=yes fi - - SOURCES="$SOURCES $srcdir/src/misc/haiku/*.cc" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/haiku/*.cc" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/haiku/*.cc" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/haiku/*.cc" + have_locale=yes + fi # The Haiku platform requires special setup. SOURCES="$srcdir/src/main/haiku/*.cc $SOURCES" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lroot -lbe -lmedia -lgame -ldevice -ltextencoding" @@ -26359,13 +26487,16 @@ $as_echo "#define SDL_FILESYSTEM_HAIKU 1" >>confdefs.h CheckVulkan CheckPTHREAD - SOURCES="$SOURCES $srcdir/src/misc/ios/*.m" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/ios/*.m" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then @@ -26448,6 +26579,8 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES 1" >>confdefs.h $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/video/uikit/*.m" + SUMMARY_video="${SUMMARY_video} uikit" + have_video=yes EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm -liconv -lobjc" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AVFoundation" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox" @@ -26493,13 +26626,16 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h CheckPTHREAD CheckHIDAPI - SOURCES="$SOURCES $srcdir/src/misc/macosx/*.m" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/macosx/*.m" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then @@ -26627,6 +26763,12 @@ $as_echo "#define SDL_AUDIO_DRIVER_EMSCRIPTEN 1" >>confdefs.h CheckClockGettime CheckEmscriptenGLES + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/emscripten/*.c" + have_misc=yes + fi + # Set up files for the power library if test x$enable_power = xyes; then @@ -26636,7 +26778,7 @@ $as_echo "#define SDL_POWER_EMSCRIPTEN 1" >>confdefs.h have_power=yes fi - # Set up files for the power library + # Set up files for the joystick library if test x$enable_joystick = xyes; then $as_echo "#define SDL_JOYSTICK_EMSCRIPTEN 1" >>confdefs.h @@ -26662,8 +26804,10 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h have_timers=yes fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/emscripten/*.c" - have_locale=yes + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/emscripten/*.c" + have_locale=yes + fi ;; *-*-riscos*) ARCH=riscos @@ -26679,9 +26823,11 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h CheckPTHREAD CheckClockGettime - SOURCES="$SOURCES $srcdir/src/misc/riscos/*.c" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/riscos/*.c" + have_misc=yes + fi # Set up files for the video library if test x$enable_video = xyes; then @@ -26734,8 +26880,10 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h SOURCES="$SOURCES $srcdir/src/core/os2/geniconv/*.c" fi # Use the Unix locale APIs. - SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" - have_locale=yes + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" + have_locale=yes + fi # Set up files for the video library if test x$enable_video = xyes; then @@ -26832,10 +26980,36 @@ INSTALL_SDL2_CONFIG=$enable_sdl2_config # Verify that we have all the platform specific files we need +if test x$have_audio != xyes; then + if test x$enable_audio = xyes; then + +$as_echo "#define SDL_AUDIO_DRIVER_DUMMY 1" >>confdefs.h + + fi + SOURCES="$SOURCES $srcdir/src/audio/dummy/*.c" +fi +if test x$have_video != xyes; then + if test x$enable_video = xyes; then + +$as_echo "#define SDL_VIDEO_DRIVER_DUMMY 1" >>confdefs.h + + fi + SOURCES="$SOURCES $srcdir/src/video/dummy/*.c" +fi if test x$have_misc != xyes; then + if test x$enable_misc = xyes; then + +$as_echo "#define SDL_MISC_DUMMY 1" >>confdefs.h + + fi SOURCES="$SOURCES $srcdir/src/misc/dummy/*.c" fi if test x$have_locale != xyes; then + if test x$enable_locale = xyes; then + +$as_echo "#define SDL_LOCALE_DUMMY 1" >>confdefs.h + + fi SOURCES="$SOURCES $srcdir/src/locale/dummy/*.c" fi if test x$have_joystick != xyes; then @@ -26873,7 +27047,7 @@ fi if test x$have_timers != xyes; then if test x$enable_timers = xyes; then -$as_echo "#define SDL_TIMERS_DISABLED 1" >>confdefs.h +$as_echo "#define SDL_TIMER_DUMMY 1" >>confdefs.h fi SOURCES="$SOURCES $srcdir/src/timer/dummy/*.c" @@ -26881,7 +27055,7 @@ fi if test x$have_filesystem != xyes; then if test x$enable_filesystem = xyes; then -$as_echo "#define SDL_FILESYSTEM_DISABLED 1" >>confdefs.h +$as_echo "#define SDL_FILESYSTEM_DUMMY 1" >>confdefs.h fi SOURCES="$SOURCES $srcdir/src/filesystem/dummy/*.c" @@ -26889,7 +27063,7 @@ fi if test x$have_loadso != xyes; then if test x$enable_loadso = xyes; then -$as_echo "#define SDL_LOADSO_DISABLED 1" >>confdefs.h +$as_echo "#define SDL_LOADSO_DUMMY 1" >>confdefs.h fi SOURCES="$SOURCES $srcdir/src/loadso/dummy/*.c" diff --git a/configure.ac b/configure.ac index 3c1c6c858..2209c04d7 100644 --- a/configure.ac +++ b/configure.ac @@ -22,9 +22,9 @@ dnl Set various version strings - taken gratefully from the GTk sources # SDL_MAJOR_VERSION=2 SDL_MINOR_VERSION=0 -SDL_MICRO_VERSION=20 -SDL_INTERFACE_AGE=2 -SDL_BINARY_AGE=20 +SDL_MICRO_VERSION=22 +SDL_INTERFACE_AGE=0 +SDL_BINARY_AGE=22 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION AC_SUBST(SDL_MAJOR_VERSION) @@ -241,10 +241,9 @@ fi AC_MSG_CHECKING(for linker option --no-undefined) have_no_undefined=no case "$host" in - dnl Skip this on platforms where it is just simply busted. +dnl Skip this on platforms where it is just simply busted. *-*-openbsd*) ;; - *) save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -Wl,--no-undefined" @@ -309,25 +308,19 @@ AC_ARG_ENABLE(libc, if test x$enable_libc = xyes; then AC_DEFINE(HAVE_LIBC, 1, [ ]) - dnl Check for C library headers +dnl Check for C library headers AC_HEADER_STDC AC_CHECK_HEADERS(sys/types.h stdio.h stdlib.h stddef.h stdarg.h malloc.h memory.h string.h strings.h wchar.h inttypes.h stdint.h limits.h ctype.h math.h float.h iconv.h signal.h) - dnl Check for typedefs, structures, etc. +dnl Check for typedefs, structures, etc. AC_TYPE_SIZE_T - dnl Check for defines +dnl Check for defines AC_CHECK_DEFINE(M_PI, math.h) - dnl Checks for library functions. - case "$host" in - *-*-cygwin* | *-*-mingw*) - ;; - *) - AC_FUNC_ALLOCA - ;; - esac + AC_FUNC_ALLOCA +dnl Checks for library functions. AC_FUNC_MEMCMP if test x$ac_cv_func_memcmp_working = xyes; then AC_DEFINE(HAVE_MEMCMP, 1, [ ]) @@ -354,7 +347,7 @@ if test x$enable_libc = xyes; then AC_CHECK_MEMBER(struct sigaction.sa_sigaction,[AC_DEFINE([HAVE_SA_SIGACTION], 1, [ ])], ,[#include ]) - dnl Check for additional non-standard headers +dnl Check for additional non-standard headers AC_CHECK_HEADERS(libunwind.h) fi @@ -422,9 +415,18 @@ SOURCES="$SOURCES $srcdir/src/locale/*.c" dnl Enable/disable various subsystems of the SDL library +case "$host" in + *-*-emscripten*) + default_atomic=no + ;; + *) + default_atomic=yes + ;; +esac + AC_ARG_ENABLE(atomic, [AS_HELP_STRING([--enable-atomic], [Enable the atomic operations subsystem [default=yes]])], - , enable_atomic=yes) + , enable_atomic=$default_atomic) if test x$enable_atomic != xyes; then AC_DEFINE(SDL_ATOMIC_DISABLED, 1, [ ]) else @@ -534,6 +536,22 @@ if test x$enable_file != xyes; then else SUMMARY_modules="${SUMMARY_modules} file" fi +AC_ARG_ENABLE(misc, +[AS_HELP_STRING([--enable-misc], [Enable the misc subsystem [default=yes]])], + , enable_misc=yes) +if test x$enable_misc != xyes; then + AC_DEFINE(SDL_MISC_DISABLED, 1, [ ]) +else + SUMMARY_modules="${SUMMARY_modules} misc" +fi +AC_ARG_ENABLE(locale, +[AS_HELP_STRING([--enable-locale], [Enable the locale subsystem [default=yes]])], + , enable_locale=yes) +if test x$enable_locale != xyes; then + AC_DEFINE(SDL_LOCALE_DISABLED, 1, [ ]) +else + SUMMARY_modules="${SUMMARY_modules} locale" +fi AC_ARG_ENABLE(loadso, [AS_HELP_STRING([--enable-loadso], [Enable the shared object loading subsystem [default=yes]])], , enable_loadso=yes) @@ -582,7 +600,7 @@ if test x$enable_assembly = xyes; then fi fi - dnl Check for various instruction support +dnl Check for various instruction support AC_ARG_ENABLE(mmx, [AS_HELP_STRING([--enable-mmx], [use MMX assembly routines [default=yes]])], , enable_mmx=yes) @@ -1280,6 +1298,7 @@ CheckDiskAudio() AC_DEFINE(SDL_AUDIO_DRIVER_DISK, 1, [ ]) SOURCES="$SOURCES $srcdir/src/audio/disk/*.c" SUMMARY_audio="${SUMMARY_audio} disk" + have_audio=yes fi } @@ -1293,6 +1312,7 @@ CheckDummyAudio() AC_DEFINE(SDL_AUDIO_DRIVER_DUMMY, 1, [ ]) SOURCES="$SOURCES $srcdir/src/audio/dummy/*.c" SUMMARY_audio="${SUMMARY_audio} dummy" + have_audio=yes fi } @@ -1504,7 +1524,7 @@ CheckWarnAll() if test x$have_gcc_Wall = xyes; then EXTRA_CFLAGS="$EXTRA_CFLAGS -Wall" - dnl Haiku headers use multicharacter constants all over the place. Ignore these warnings when using -Wall. +dnl Haiku headers use multicharacter constants all over the place. Ignore these warnings when using -Wall. AC_MSG_CHECKING(for necessary GCC -Wno-multichar option) need_gcc_Wno_multichar=no case "$host" in @@ -1535,7 +1555,7 @@ CheckWayland() video_wayland=no if test x$video_opengl_egl = xyes && \ test x$video_opengles_v2 = xyes; then - if $PKG_CONFIG --exists wayland-client wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then + if $PKG_CONFIG --exists 'wayland-client >= 1.18' wayland-scanner wayland-egl wayland-cursor egl 'xkbcommon >= 0.5.0'; then WAYLAND_CFLAGS=`$PKG_CONFIG --cflags wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_LIBS=`$PKG_CONFIG --libs wayland-client wayland-egl wayland-cursor xkbcommon` WAYLAND_SCANNER=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` @@ -1566,7 +1586,7 @@ dnl FIXME: Do BSD and OS X need special cases? wayland_client_lib=[`find_lib "libwayland-client.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] wayland_egl_lib=[`find_lib "libwayland-egl.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] if test x$wayland_egl_lib = x; then - dnl This works in Ubuntu 13.10, maybe others + # This works in Ubuntu 13.10, maybe others wayland_egl_lib=[`find_lib "mesa-egl/libwayland-egl.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] fi wayland_cursor_lib=[`find_lib "libwayland-cursor.so.*" "$WAYLAND_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] @@ -1606,39 +1626,31 @@ dnl FIXME: Do BSD and OS X need special cases? dnl See if libdecor is available AC_ARG_ENABLE(libdecor, -[AS_HELP_STRING([--enable-libdecor], [use libdecor for Wayland client-side decorations [default=yes]])], - , enable_libdecor=yes) +[AS_HELP_STRING([--enable-libdecor], [use libdecor for Wayland client-side decorations [default=yes]])],, enable_libdecor=yes) if test x$enable_libdecor = xyes; then - AC_MSG_CHECKING(for libdecor support) - AS_IF([$PKG_CONFIG --exists libdecor-0], - [video_libdecor=yes], - [video_libdecor=no]) - AC_MSG_RESULT($video_libdecor) + PKG_CHECK_MODULES([DECOR], [libdecor-0], video_libdecor=yes, video_libdecor=no) if test x$video_libdecor = xyes; then - EXTRA_CFLAGS="$EXTRA_CFLAGS `$PKG_CONFIG --cflags libdecor-0`" + EXTRA_CFLAGS="$EXTRA_CFLAGS $DECOR_CFLAGS" AC_DEFINE(HAVE_LIBDECOR_H, 1, [ ]) AC_ARG_ENABLE(libdecor-shared, -[AS_HELP_STRING([--enable-libdecor-shared], [dynamically load libdecor [default=yes]])], - , enable_libdecor_shared=yes) +[AS_HELP_STRING([--enable-libdecor-shared], [dynamically load libdecor [default=yes]])],, enable_libdecor_shared=yes) + + decor_lib=[`find_lib "libdecor-0.so.*" "$DECOR_LIBS" | sed 's/.*\/\(.*\)/\1/; q'`] if test x$enable_wayland_shared != xyes; then enable_libdecor_shared=no fi - - decor_lib=[`find_lib "libdecor-0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'`] - if test x$have_loadso != xyes && \ test x$enable_libdecor_shared = xyes; then AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic libdecor loading]) fi - if test x$have_loadso = xyes && \ test x$enable_libdecor_shared = xyes && test x$decor_lib != x; then echo "-- dynamic libdecor -> $decor_lib" AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR, "$decor_lib", [ ]) else - EXTRA_LDFLAGS="$EXTRA_LDFLAGS `$PKG_CONFIG --libs libdecor-0`" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS $DECOR_LIBS" fi fi fi @@ -1666,8 +1678,10 @@ CheckNativeClient() SDLMAIN_SOURCES="$srcdir/src/main/nacl/*.c" SOURCES="$SOURCES $srcdir/src/audio/nacl/*.c" SUMMARY_audio="${SUMMARY_audio} nacl" + have_audio=yes SOURCES="$SOURCES $srcdir/src/video/nacl/*.c" SUMMARY_video="${SUMMARY_video} nacl opengles2" + have_video=yes ],[]) } @@ -1717,6 +1731,7 @@ CheckRPI() SOURCES="$SOURCES $srcdir/src/video/raspberry/*.c" AC_DEFINE(SDL_VIDEO_DRIVER_RPI, 1, [ ]) SUMMARY_video="${SUMMARY_video} rpi" + have_video=yes fi fi } @@ -1834,7 +1849,6 @@ CheckX11() fi have_video=yes - dnl AC_CHECK_LIB(X11, XGetEventData, AC_DEFINE(SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS, 1, [Have XGenericEvent])) AC_MSG_CHECKING([for XGenericEvent]) have_XGenericEvent=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -2005,7 +2019,7 @@ XITouchClassInfo *t; [AS_HELP_STRING([--enable-video-x11-xrandr], [enable X11 Xrandr extension for fullscreen [default=yes]])], , enable_video_x11_xrandr=yes) if test x$enable_video_x11_xrandr = xyes; then - dnl XRRScreenResources is only present in Xrandr >= 1.2, we use that as a test. +dnl XRRScreenResources is only present in Xrandr >= 1.2, we use that as a test. definitely_enable_video_x11_xrandr=no have_xrandr_h_hdr=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -2167,7 +2181,7 @@ CheckCOCOA() , enable_video_cocoa=yes) if test x$enable_video = xyes -a x$enable_video_cocoa = xyes; then save_CFLAGS="$CFLAGS" - dnl Work around that we don't have Objective-C support in autoconf +dnl Work around that we don't have Objective-C support in autoconf CFLAGS="$CFLAGS -x objective-c" AC_MSG_CHECKING(for Cocoa framework) have_cocoa=no @@ -2195,7 +2209,7 @@ CheckMETAL() , enable_render_metal=yes) if test x$enable_video = xyes -a x$enable_video_metal = xyes; then save_CFLAGS="$CFLAGS" - dnl Work around that we don't have Objective-C support in autoconf +dnl Work around that we don't have Objective-C support in autoconf CFLAGS="$CFLAGS -x objective-c" AC_MSG_CHECKING(for Metal framework) have_metal=no @@ -2619,7 +2633,7 @@ CheckVulkan() ;; *-*-darwin*) save_CFLAGS="$CFLAGS" - dnl Work around that we don't have Objective-C support in autoconf +dnl Work around that we don't have Objective-C support in autoconf CFLAGS="$CFLAGS -x objective-c" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include @@ -2654,7 +2668,7 @@ CheckVulkan() dnl See if we can use the new unified event interface in Linux 2.4 CheckInputEvents() { - dnl Check for Linux 2.4 unified input event interface support +dnl Check for Linux 2.4 unified input event interface support AC_MSG_CHECKING(for Linux 2.4 unified input interface) use_input_events=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -2674,7 +2688,6 @@ CheckInputEvents() dnl See if we can use the kernel kd.h header CheckInputKD() { - AC_MSG_CHECKING(for Linux kd.h) use_input_kd=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @@ -2876,7 +2889,7 @@ CheckJoystickMFI() if test x$enable_joystick_mfi = xyes; then save_CFLAGS="$CFLAGS" save_LDFLAGS="$LDFLAGS" - dnl Work around that we don't have Objective-C support in autoconf +dnl Work around that we don't have Objective-C support in autoconf CFLAGS="$CFLAGS -x objective-c -fobjc-weak" LDFLAGS="$LDFLAGS -Wl,-weak_framework,CoreHaptics -Wl,-weak_framework,GameController" AC_MSG_CHECKING(for GameController framework) @@ -2908,15 +2921,15 @@ CheckJoystickMFI() dnl See what type of thread model to use on Linux and Solaris CheckPTHREAD() { - dnl Check for pthread support +dnl Check for pthread support - dnl Emscripten pthreads work, but you need to have a non-pthread fallback build - dnl for systems without support. It's not currently enough to not use - dnl pthread functions in a pthread-build; it won't start up on unsupported - dnl browsers. As such, you have to explicitly enable it on Emscripten builds - dnl for the time being. This default with change to ON once this becomes - dnl commonly supported in browsers or the Emscripten teams makes a single - dnl binary work everywhere. +dnl Emscripten pthreads work, but you need to have a non-pthread fallback build +dnl for systems without support. It's not currently enough to not use +dnl pthread functions in a pthread-build; it won't start up on unsupported +dnl browsers. As such, you have to explicitly enable it on Emscripten builds +dnl for the time being. This default with change to ON once this becomes +dnl commonly supported in browsers or the Emscripten teams makes a single +dnl binary work everywhere. case "$host" in *-*-emscripten*) @@ -2930,7 +2943,7 @@ CheckPTHREAD() AC_ARG_ENABLE(pthreads, [AS_HELP_STRING([--enable-pthreads], [use POSIX threads for multi-threading [default=maybe]])], , enable_pthreads=maybe) - dnl This is used on Linux for glibc binary compatibility (Doh!) +dnl This is used on Linux for glibc binary compatibility (Doh!) AC_ARG_ENABLE(pthread-sem, [AS_HELP_STRING([--enable-pthread-sem], [use pthread semaphores [default=maybe]])], , enable_pthread_sem=maybe) @@ -3185,6 +3198,16 @@ CheckWINDOWS() # This fixes Windows stack alignment with newer GCC CheckStackBoundary + + # headers needed elsewhere + AC_CHECK_HEADER(tpcshrd.h,have_tpcshrd_h=yes) + if test x$have_tpcshrd_h = xyes; then + AC_DEFINE(HAVE_TPCSHRD_H, 1, [ ]) + fi + AC_CHECK_HEADER(roapi.h,have_roapi_h=yes) + if test x$have_roapi_h = xyes; then + AC_DEFINE(HAVE_ROAPI_H, 1, [ ]) + fi } dnl Determine whether the compiler can produce OS/2 executables @@ -3643,6 +3666,7 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/core/android/*.c $srcdir/src/video/android/*.c" AC_DEFINE(SDL_VIDEO_DRIVER_ANDROID, 1, [ ]) SUMMARY_video="${SUMMARY_video} android" + have_video=yes fi ;; *-*-linux*) ARCH=linux ;; @@ -3724,12 +3748,16 @@ case "$host" in CheckRPATH CheckVivanteVideo - SOURCES="$SOURCES $srcdir/src/misc/unix/*.c" - have_misc=yes - - SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" - have_locale=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/unix/*.c" + have_misc=yes + fi + # Set up files for the locale library + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then case $ARCH in @@ -3907,12 +3935,16 @@ case "$host" in # Set up the core platform files SOURCES="$SOURCES $srcdir/src/core/windows/*.c" - SOURCES="$SOURCES $srcdir/src/misc/windows/*.c" - have_misc=yes + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/windows/*.c" + have_misc=yes + fi # Use the Windows locale APIs. - SOURCES="$SOURCES $srcdir/src/locale/windows/*.c" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/windows/*.c" + have_locale=yes + fi # Set up files for the video library if test x$enable_video = xyes; then AC_DEFINE(SDL_VIDEO_DRIVER_WINDOWS, 1, [ ]) @@ -3977,10 +4009,6 @@ case "$host" in have_haptic=yes fi fi - AC_CHECK_HEADER(tpcshrd.h,have_tpcshrd_h=yes) - if test x$have_tpcshrd_h = xyes; then - AC_DEFINE(HAVE_TPCSHRD_H, 1, [ ]) - fi # Set up files for the sensor library AC_CHECK_HEADER(sensorsapi.h,have_winsensors=yes,have_winsensors=no) if test x$have_winsensors = xyes; then @@ -4045,14 +4073,12 @@ case "$host" in SDL_LIBS="-lcygwin $SDL_LIBS" fi ;; - - dnl BeOS support removed after SDL 2.0.1. Haiku still works. --ryan. +dnl BeOS support removed after SDL 2.0.1. Haiku still works. --ryan. *-*-beos*) AC_MSG_ERROR([ *** BeOS support has been removed as of SDL 2.0.2. ]) ;; - *-*-haiku*) ARCH=haiku ac_default_prefix=/boot/system @@ -4097,14 +4123,16 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/filesystem/haiku/*.cc" have_filesystem=yes fi - - SOURCES="$SOURCES $srcdir/src/misc/haiku/*.cc" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/haiku/*.cc" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/haiku/*.cc" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/haiku/*.cc" + have_locale=yes + fi # The Haiku platform requires special setup. SOURCES="$srcdir/src/main/haiku/*.cc $SOURCES" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lroot -lbe -lmedia -lgame -ldevice -ltextencoding" @@ -4124,13 +4152,16 @@ case "$host" in CheckVulkan CheckPTHREAD - SOURCES="$SOURCES $srcdir/src/misc/ios/*.m" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/ios/*.m" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then AC_DEFINE(SDL_AUDIO_DRIVER_COREAUDIO, 1, [ ]) @@ -4191,6 +4222,8 @@ case "$host" in AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES, 1, [ ]) AC_DEFINE(SDL_VIDEO_RENDER_OGL_ES2, 1, [ ]) SOURCES="$SOURCES $srcdir/src/video/uikit/*.m" + SUMMARY_video="${SUMMARY_video} uikit" + have_video=yes EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm -liconv -lobjc" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AVFoundation" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox" @@ -4236,13 +4269,16 @@ case "$host" in CheckPTHREAD CheckHIDAPI - SOURCES="$SOURCES $srcdir/src/misc/macosx/*.m" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/macosx/*.m" + have_misc=yes + fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" - have_locale=yes - + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/macosx/*.m" + have_locale=yes + fi # Set up files for the audio library if test x$enable_audio = xyes; then AC_DEFINE(SDL_AUDIO_DRIVER_COREAUDIO, 1, [ ]) @@ -4350,6 +4386,12 @@ case "$host" in CheckClockGettime CheckEmscriptenGLES + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/emscripten/*.c" + have_misc=yes + fi + # Set up files for the power library if test x$enable_power = xyes; then AC_DEFINE(SDL_POWER_EMSCRIPTEN, 1, [ ]) @@ -4357,7 +4399,7 @@ case "$host" in have_power=yes fi - # Set up files for the power library + # Set up files for the joystick library if test x$enable_joystick = xyes; then AC_DEFINE(SDL_JOYSTICK_EMSCRIPTEN, 1, [ ]) SOURCES="$SOURCES $srcdir/src/joystick/emscripten/*.c" @@ -4377,8 +4419,10 @@ case "$host" in have_timers=yes fi # Set up files for the locale library - SOURCES="$SOURCES $srcdir/src/locale/emscripten/*.c" - have_locale=yes + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/emscripten/*.c" + have_locale=yes + fi ;; *-*-riscos*) ARCH=riscos @@ -4394,9 +4438,11 @@ case "$host" in CheckPTHREAD CheckClockGettime - SOURCES="$SOURCES $srcdir/src/misc/riscos/*.c" - have_misc=yes - + # Set up files for the misc library + if test x$enable_misc = xyes; then + SOURCES="$SOURCES $srcdir/src/misc/riscos/*.c" + have_misc=yes + fi # Set up files for the video library if test x$enable_video = xyes; then AC_DEFINE(SDL_VIDEO_DRIVER_RISCOS, 1, [ ]) @@ -4443,8 +4489,10 @@ case "$host" in SOURCES="$SOURCES $srcdir/src/core/os2/geniconv/*.c" fi # Use the Unix locale APIs. - SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" - have_locale=yes + if test x$enable_locale = xyes; then + SOURCES="$SOURCES $srcdir/src/locale/unix/*.c" + have_locale=yes + fi # Set up files for the video library if test x$enable_video = xyes; then AC_DEFINE(SDL_VIDEO_DRIVER_OS2, 1, [ ]) @@ -4520,10 +4568,28 @@ AC_SUBST([INSTALL_SDL2_CONFIG], [$enable_sdl2_config]) # Verify that we have all the platform specific files we need +if test x$have_audio != xyes; then + if test x$enable_audio = xyes; then + AC_DEFINE(SDL_AUDIO_DRIVER_DUMMY, 1, [ ]) + fi + SOURCES="$SOURCES $srcdir/src/audio/dummy/*.c" +fi +if test x$have_video != xyes; then + if test x$enable_video = xyes; then + AC_DEFINE(SDL_VIDEO_DRIVER_DUMMY, 1, [ ]) + fi + SOURCES="$SOURCES $srcdir/src/video/dummy/*.c" +fi if test x$have_misc != xyes; then + if test x$enable_misc = xyes; then + AC_DEFINE(SDL_MISC_DUMMY, 1, [ ]) + fi SOURCES="$SOURCES $srcdir/src/misc/dummy/*.c" fi if test x$have_locale != xyes; then + if test x$enable_locale = xyes; then + AC_DEFINE(SDL_LOCALE_DUMMY, 1, [ ]) + fi SOURCES="$SOURCES $srcdir/src/locale/dummy/*.c" fi if test x$have_joystick != xyes; then @@ -4552,19 +4618,19 @@ if test x$have_threads != xyes; then fi if test x$have_timers != xyes; then if test x$enable_timers = xyes; then - AC_DEFINE(SDL_TIMERS_DISABLED, 1, [ ]) + AC_DEFINE(SDL_TIMER_DUMMY, 1, [ ]) fi SOURCES="$SOURCES $srcdir/src/timer/dummy/*.c" fi if test x$have_filesystem != xyes; then if test x$enable_filesystem = xyes; then - AC_DEFINE(SDL_FILESYSTEM_DISABLED, 1, [ ]) + AC_DEFINE(SDL_FILESYSTEM_DUMMY, 1, [ ]) fi SOURCES="$SOURCES $srcdir/src/filesystem/dummy/*.c" fi if test x$have_loadso != xyes; then if test x$enable_loadso = xyes; then - AC_DEFINE(SDL_LOADSO_DISABLED, 1, [ ]) + AC_DEFINE(SDL_LOADSO_DUMMY, 1, [ ]) fi SOURCES="$SOURCES $srcdir/src/loadso/dummy/*.c" fi diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 85d815852..000000000 --- a/debian/changelog +++ /dev/null @@ -1,186 +0,0 @@ -libsdl2 (2.0.20) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.20 - - -- Sam Lantinga Fri, 7 Jan 2022 18:24:41 -0800 - -libsdl2 (2.0.19) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.19 - - -- Sam Lantinga Tue, 30 Nov 2021 09:57:40 -0800 - -libsdl2 (2.0.18) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.18 - - -- Sam Lantinga Fri, 26 Nov 2021 08:07:21 -0800 - -libsdl2 (2.0.17) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.17 - - -- Sam Lantinga Tue, 10 Aug 2021 15:00:14 -0800 - -libsdl2 (2.0.16) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.16 - - -- Sam Lantinga Sat, 31 Jul 2021 13:27:38 -0800 - -libsdl2 (2.0.15) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.15 for development builds - - -- Sam Lantinga Tue, 22 Dec 2020 10:29:01 -0800 - -libsdl2 (2.0.14) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.14 - - -- Sam Lantinga Tue, 8 Dec 2020 17:54:33 -0800 - -libsdl2 (2.0.13) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.13 for development builds - - -- Sam Lantinga Tue, 10 Mar 2020 18:24:22 -0800 - -libsdl2 (2.0.12) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.12 - - -- Sam Lantinga Sun, 1 Mar 2020 14:57:07 -0800 - -libsdl2 (2.0.11) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.11 for development builds - - -- Sam Lantinga Sun, 22 Sep 2019 10:33:03 -0800 - -libsdl2 (2.0.10) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.10 - - -- Sam Lantinga Mon, 17 Jun 2019 08:48:47 -0800 - -libsdl2 (2.0.9) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.9 - - -- Sam Lantinga Wed, 26 Sep 2018 10:02:21 -0800 - -libsdl2 (2.0.8) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.8 - - -- Sam Lantinga Sat, 4 Nov 2017 21:21:53 -0800 - -libsdl2 (2.0.7) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.7 - - -- Sam Lantinga Thu, 12 Oct 2017 08:01:16 -0800 - -libsdl2 (2.0.6) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.6 - - -- Sam Lantinga Sat, 9 Sep 2017 07:29:36 -0800 - -libsdl2 (2.0.5) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.5 - - -- Sam Lantinga Mon, 28 Nov 2016 07:32:52 -0800 - -libsdl2 (2.0.4) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.4 - - -- Sam Lantinga Thu, 07 Jan 2016 11:02:39 -0800 - -libsdl2 (2.0.3) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.3 - - -- Sam Lantinga Sun, 9 Mar 2014 10:35:54 -0800 - -libsdl2 (2.0.2) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.2 - - -- Sam Lantinga Sun, 9 Feb 2014 2:55:59 -0800 - -libsdl2 (2.0.1) UNRELEASED; urgency=low - - * Updated SDL to version 2.0.1 - - -- Sam Lantinga Wed, 23 Oct 2013 16:31:38 -0800 - -libsdl2 (2.0.0) UNRELEASED; urgency=low - - * SDL is now a native debian package. - * Removed udeb package - * Disabled DirectFB support by default, to avoid runtime dependencies - - -- Sam Lantinga Fri, 15 Feb 2013 08:55:04 -0800 - -libsdl2 (2.0.0~20130127-1) UNRELEASED; urgency=low - - * New upstream snapshot. - - -- Sam Hocevar Wed, 30 Jan 2013 23:01:12 +0100 - -libsdl2 (2.0.0~20130103-1) unstable; urgency=low - - [ Manuel A. Fernandez Montecelo ] - * debian/control: - - Updating maintainers/permissions: - - Add myself and Felix Geyer - - Update Build-Depends: - - Remove a few obsolete items - - Add items added lately to libsdl1.2, such as libts (touch screen) - support - - Add "libsdl2-dbg", analog to libsdl1.2-dbg - - Change "XC-Package-Type: udeb" to "Package-Type" - * debian/compat: set level 9 - * debian/source/format: Set to "3.0 (quilt)" - - Remove README.source, not needed with new format - * debian/sdl2-config.1: Fix typo, "progams"->"programs" - * debian/libsdl2-dev.install: - - Remove "usr/lib/*/*.la", discouraged - - Add man pages: "usr/share/man/man3/*" - * debian/libsdl2-dev.manpages: add file to install local "sdl2-config.1" - * debian/sources: Removed, possible obsolete file from long ago? - * debian/copyright: - - Upstream updated to zlib/libpng - - Copyright-file format conversion to 1.0 - - Complete revamp and detailed research about copyright and licenses used, - it's very messy but hopefully complete - - [ Felix Geyer ] - * Simplify debian/rules by using dh(1). - - -- Manuel A. Fernandez Montecelo Sun, 27 Jan 2013 16:40:49 +0100 - -libsdl2 (2.0~20120220c-1) experimental; urgency=low - - * Upstream version was renamed to 2.0 (Closes: #669367). - * New upstream snapshot (Closes: #671506). - * This package no longer conflicts with libsdl-1.2. - * debian/rules: add multiarch support (Closes: #669364). - - * debian/patches/fix_joystick_misc_axes.diff: fix a joystick remapping - bug causing some axes to malfunction. - * debian/patches/external_header_paths.diff: provide additional CFLAGS - so that headers such as SDL_syswm.h can be included (Closes: #669363). - - -- Sam Hocevar Thu, 17 May 2012 19:03:59 +0200 - -libsdl-1.3 (1.3.0~20111204-1) experimental; urgency=low - - * Initial upload from upstream snapshot. - - -- Sam Hocevar Sun, 04 Dec 2011 14:35:05 +0100 - diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec635144f..000000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 6c778fe59..000000000 --- a/debian/control +++ /dev/null @@ -1,91 +0,0 @@ -Source: libsdl2 -Priority: optional -Section: libs -Maintainer: Debian SDL packages maintainers -Uploaders: Barry deFreese , - Sam Hocevar , - Manuel A. Fernandez Montecelo , - Felix Geyer , - Sam Lantinga -Standards-Version: 3.9.3 -Build-Depends: debhelper (>= 9), - dh-autoreconf, - dpkg-dev (>= 1.16.1~), - fcitx-libs-dev [linux-any], - libasound2-dev [linux-any], - libdbus-1-dev, - libegl1-mesa-dev [!hurd-any], - libdrm-dev [linux-any], - libgl1-mesa-dev, - libgles-dev [!hurd-any], - libpulse-dev, - libudev-dev [linux-any], - libdbus-1-dev [linux-any], - libibus-1.0-dev[linux-any], - libpulse-dev, - libsndio-dev, - libudev-dev [linux-any], - libusb2-dev [kfreebsd-any], - libusbhid-dev [kfreebsd-any], - libwayland-dev [linux-any], - libx11-dev, - libxcursor-dev, - libxext-dev, - libxfixes-dev, - libxi-dev, - libxinerama-dev, - libxkbcommon-dev, - libxrandr-dev, - libxss-dev, - libxxf86vm-dev, - libxt-dev, - libxv-dev, - pkg-config, - libsamplerate0-dev, - wayland-protocols -Homepage: http://www.libsdl.org/ - -Package: libsdl2-2.0-0 -Architecture: any -Multi-Arch: same -Pre-Depends: ${misc:Pre-Depends} -Depends: ${misc:Depends}, - ${shlibs:Depends}, - libudev1 [linux-any], - libdbus-1-3 [linux-any] -Conflicts: libsdl-1.3-0 -Replaces: libsdl-1.3-0 -Description: Simple DirectMedia Layer - SDL is a library that allows programs portable low level access to - a video framebuffer, audio output, mouse, and keyboard. - . - This package contains the shared library, compiled with X11 graphics drivers and OSS, ALSA and PulseAudio sound drivers. - -Package: libsdl2-dev -Section: libdevel -Architecture: any -Multi-Arch: same -Depends: ${misc:Depends}, - libsdl2-2.0-0 (= ${binary:Version}), - libc6-dev, - libgl1-mesa-dev -Conflicts: libsdl-1.3-dev -Replaces: libsdl-1.3-dev -Description: Simple DirectMedia Layer development files - SDL is a library that allows programs portable low level access to a video - framebuffer, audio output, mouse, and keyboard. - . - This package contains files needed if you wish to use the SDL library in your own programs. - -Package: libsdl2-dbg -Priority: extra -Section: debug -Architecture: any -Multi-Arch: same -Depends: ${misc:Depends}, - libsdl2-2.0-0 (= ${binary:Version}), -Description: Simple DirectMedia Layer debug files - SDL is a library that allows programs portable low level access to a video - framebuffer, audio output, mouse, and keyboard. - . - This package contains the debug symbols for the SDL library. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index ffc41afc1..000000000 --- a/debian/copyright +++ /dev/null @@ -1,351 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: SDL -Upstream-Contact: Sam Lantinga -Source: http://www.libsdl.org/ - -Files: * -Copyright: 1997-2022 Sam Lantinga -License: zlib/libpng - -Files: src/libm/* -Copyright: 1993 by Sun Microsystems, Inc. All rights reserved. -License: SunPro - -Files: src/main/windows/SDL_windows_main.c -Copyright: 2022 Sam Lantinga -License: PublicDomain_Sam_Lantinga -Comment: SDL_main.c, placed in the public domain by Sam Lantinga 4/13/98 - -Files: src/render/mmx.h -Copyright: 1997-99 by H. Dietz and R. Fisher -License: zlib/libpng -Comment: - Copyright but no mention to license. - . - Included since long ago with SDL (and its Debian package) under directory - src/video/mmx.h - -Files: src/render/SDL_yuv_sw.c -Copyright: 1995 Erik Corry - 1995 The Regents of the University of California - 1995 Brown University -License: BrownUn_UnCalifornia_ErikCorry - -Files: src/test/SDL_test_md5.c -Copyright: 1997-2022 Sam Lantinga - 1990 RSA Data Security, Inc. -License: zlib/libpng and RSA_Data_Security - -Files: src/thread/windows/win_ce_semaphore.c -Copyright: 1998, Johnson M. Hart (with corrections 2001 by Rainer Loritz) -License: Johnson_M._Hart - -Files: src/video/x11/imKStoUCS.c - src/video/x11/imKStoUCS.h -Copyright: 1994-2003 The XFree86 Project, Inc. -License: MIT/X11 - -Files: test/testhaptic.c -Copyright: 1997-2022 Sam Lantinga - 2008 Edgar Simo Serra -License: BSD_3_clause - -Files: test/testrumble.c -Copyright: 1997-2022 Sam Lantinga - 2011 Edgar Simo Serra -License: BSD_3_clause - -Files: test/shapes/* -Copyright: none -License: zlib/libpng -Comment: No specific information about the images - -Files: Xcode/TemplatesForXcode*/*/main.c -Copyright: none -License: zlib/libpng -Comment: SDL files, no copyright or license notice - -Files: Xcode/TemplatesForXcode*/*/atlantis/* -Copyright: 1993, 1994, Silicon Graphics, Inc. -License: SGI_atlantis - -Files: Xcode/TemplatesForXcode*/*/atlantis/atlantis.c -Copyright: 1994 Mark J. Kilgard - 1993, 1994, Silicon Graphics, Inc. -License: SGI_atlantis -Comment: See license for full copyright notice, this one is the same except for - the additional copyright holder - -Files: Xcode/SDLTest/sdlcommon_prefix.h -Copyright: 2003 Darrell Walisser -License: zlib/libpng -Comment: - Created by Darrell Walisser on Wed Aug 06 2003. - Copyright (c) 2003 __MyCompanyName__. All rights reserved. - -Files: debian/* -Copyright: 2011-2012, Manuel A. Fernandez Montecelo - 2011-2012, Felix Geyer - 2011, Roman Vasiyarov - 2010, Jon Dowland - 2009, Barry deFreese - 2007-2008, Aurelien Jarno - 2007-2008, Sam Hocevar (Debian packages) - 2002-2007, Josselin Mouette - 2001, Christian T. Steigies - 2001, Branden Robinson -License: LGPL-2.1+ - - -License: zlib/libpng - 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. - -License: LGPL-2.1+ - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or (at - your option) any later version. - . - On Debian systems, the complete text of version 2.1 of the GNU Lesser - Public License can be found in '/usr/share/common-licenses/LGPL-2.1'. - -License: MIT/X11 - 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: - . - The above copyright notice and this permission notice 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. - -License: BSD_3_clause - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the LibQxt project nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Comment: - Copyright (C) 1997-2022 Sam Lantinga - . - 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. - . - . - Copyright (c) 2011, Edgar Simo Serra - All rights reserved. - . - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - . - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the Simple Directmedia Layer (SDL) nor the names of - its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -License: BrownUn_UnCalifornia_ErikCorry - /* This code was derived from code carrying the following copyright notices: - * Copyright (c) 1995 The Regents of the University of California. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose, without fee, and without written agreement is - * hereby granted, provided that the above copyright notice and the following - * two paragraphs appear in all copies of this software. - * - * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT - * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF - * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Copyright (c) 1995 Erik Corry - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose, without fee, and without written agreement is - * hereby granted, provided that the above copyright notice and the following - * two paragraphs appear in all copies of this software. - * - * IN NO EVENT SHALL ERIK CORRY BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF - * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ERIK CORRY HAS BEEN ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * ERIK CORRY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" - * BASIS, AND ERIK CORRY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, - * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Portions of this software Copyright (c) 1995 Brown University. - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose, without fee, and without written agreement - * is hereby granted, provided that the above copyright notice and the - * following two paragraphs appear in all copies of this software. - * - * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT - * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN - * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" - * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, - * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -License: Johnson_M._Hart - Permission is granted for any and all use providing that this - copyright is properly acknowledged. - There are no assurances of suitability for any use whatsoever. - -License: SunPro - Developed at SunPro, a Sun Microsystems, Inc. business. - Permission to use, copy, modify, and distribute this - software is freely granted, provided that this notice - is preserved. - -License: PublicDomain_Sam_Lantinga - Placed in the public domain by Sam Lantinga 4/13/98 - -License: PublicDomain_Edgar_Simo - Written by Edgar Simo "bobbens" - . - Released under Public Domain. - -License: RSA_Data_Security - *********************************************************************** - ** utl_md5.c -- the source code for MD5 routines ** - ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** - ** Created: 2/17/90 RLR ** - ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** - *********************************************************************** - *********************************************************************** - ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** - ** ** - ** License to copy and use this software is granted provided that ** - ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** - ** Digest Algorithm" in all material mentioning or referencing this ** - ** software or this function. ** - ** ** - ** License is also granted to make and use derivative works ** - ** provided that such works are identified as "derived from the RSA ** - ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** - ** material mentioning or referencing the derived work. ** - ** ** - ** RSA Data Security, Inc. makes no representations concerning ** - ** either the merchantability of this software or the suitability ** - ** of this software for any particular purpose. It is provided "as ** - ** is" without express or implied warranty of any kind. ** - ** ** - ** These notices must be retained in any copies of any part of this ** - ** documentation and/or software. ** - *********************************************************************** - -License: SGI_atlantis - (c) Copyright 1993, 1994, Silicon Graphics, Inc. - ALL RIGHTS RESERVED - Permission to use, copy, modify, and distribute this software for - any purpose and without fee is hereby granted, provided that the above - copyright notice appear in all copies and that both the copyright notice - and this permission notice appear in supporting documentation, and that - the name of Silicon Graphics, Inc. not be used in advertising - or publicity pertaining to distribution of the software without specific, - written prior permission. - . - THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" - AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, - INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR - FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON - GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, - SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY - KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, - LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF - THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE - POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. - . - US Government Users Restricted Rights - Use, duplication, or disclosure by the Government is subject to - restrictions set forth in FAR 52.227.19(c)(2) or subparagraph - (c)(1)(ii) of the Rights in Technical Data and Computer Software - clause at DFARS 252.227-7013 and/or in similar or successor - clauses in the FAR or the DOD or NASA FAR Supplement. - Unpublished-- rights reserved under the copyright laws of the - United States. Contractor/manufacturer is Silicon Graphics, - Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. - . - OpenGL(TM) is a trademark of Silicon Graphics, Inc. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index b4b55eeb7..000000000 --- a/debian/docs +++ /dev/null @@ -1,4 +0,0 @@ -BUGS.txt -CREDITS.txt -README.md -README-SDL.txt diff --git a/debian/libsdl2-2.0-0-udeb.install b/debian/libsdl2-2.0-0-udeb.install deleted file mode 100644 index e4193c74c..000000000 --- a/debian/libsdl2-2.0-0-udeb.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libSDL2-2.0.so.0* diff --git a/debian/libsdl2-2.0-0.install b/debian/libsdl2-2.0-0.install deleted file mode 100644 index e4193c74c..000000000 --- a/debian/libsdl2-2.0-0.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libSDL2-2.0.so.0* diff --git a/debian/libsdl2-dev.install b/debian/libsdl2-dev.install deleted file mode 100644 index 40a9754c7..000000000 --- a/debian/libsdl2-dev.install +++ /dev/null @@ -1,9 +0,0 @@ -usr/bin/sdl2-config -usr/include/SDL2 -usr/lib/*/*.a -usr/lib/*/*.la -usr/lib/*/*.so -usr/lib/*/pkgconfig/sdl2.pc -usr/lib/*/cmake/SDL2/sdl2-config.cmake -usr/lib/*/cmake/SDL2/sdl2-config-version.cmake -usr/share/aclocal/sdl2.m4 diff --git a/debian/libsdl2-dev.manpages b/debian/libsdl2-dev.manpages deleted file mode 100644 index 150752ce9..000000000 --- a/debian/libsdl2-dev.manpages +++ /dev/null @@ -1 +0,0 @@ -debian/sdl2-config.1 diff --git a/debian/rules b/debian/rules deleted file mode 100755 index b065aca0f..000000000 --- a/debian/rules +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/make -f - -DEB_HOST_ARCH_CPU ?= $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU) -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) - -confflags = --disable-rpath --disable-video-directfb \ - --disable-nas --disable-esd --disable-arts - -# These flags can be used to create a package directly linking with external libraries and having the appropriate package dependencies -#confflags += --disable-alsa-shared -#confflags += --disable-arts-shared -#confflags += --disable-directfb-shared -#confflags += --disable-esd-shared -#confflags += --disable-fusionsound-shared -#confflags += --disable-jack-shared -#confflags += --disable-kmsdrm-shared -#confflags += --disable-libsamplerate-shared -#confflags += --disable-nas-shared -#confflags += --disable-pulseaudio-shared -#confflags += --disable-sndio-shared -#confflags += --disable-wayland-shared -#confflags += --disable-x11-shared - -%: - dh $@ --parallel - -override_dh_auto_configure: - dh_auto_configure -Bbuilddir/all -- $(confflags) - -override_dh_auto_build: - dh_auto_build -Bbuilddir/all - tar czf debian/examples.tar.gz test - -override_dh_auto_install: - dh_auto_install -Bbuilddir/all - -override_dh_auto_clean: - dh_auto_clean -Bbuilddir/all - rm -f debian/examples.tar.gz - -override_dh_install: - dh_install --remaining-packages --fail-missing -XlibSDL2.la - -override_dh_installexamples: - dh_installexamples -plibsdl2-dev debian/examples.tar.gz - dh_installexamples --remaining-packages - -override_dh_link: - # to address lintian warning - # W: libsdl2-2.0-0: dev-pkg-without-shlib-symlink usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.0.0 usr/lib/x86_64-linux-gnu/libSDL2-2.0.so - dh_link -plibsdl2-dev usr/lib/$(DEB_HOST_MULTIARCH)/libSDL2-2.0.so.0.0.0 usr/lib/$(DEB_HOST_MULTIARCH)/libSDL2-2.0.so - -override_dh_strip: - dh_strip --dbg-package=libsdl2-dbg diff --git a/debian/sdl2-config.1 b/debian/sdl2-config.1 deleted file mode 100644 index c4f4106fa..000000000 --- a/debian/sdl2-config.1 +++ /dev/null @@ -1,86 +0,0 @@ -.TH sdl2-config 1 "2012-02-20" "SDL 2.0" -.SH NAME -sdl2-config \- script to get information about the installed version of SDL -.SH SYNOPSIS -.B sdl2-config -[ --prefix= -.IR DIR ] -[ --exec-prefix= -.IR DIR ] -[ --version ] [ --libs | --library-libs | --plugin-libs ] [ --cflags ] -.SH DESCRIPTION -.B sdl2-config -is a tool that is used to configure and determine the compiler and linker -flags that should be used to compile and link programs, libraries, and -plugins that use SDL. It is also used internally by the m4 macros that are -included with SDL. -.SH OPTIONS -.TP -.B --cflags -Print the compiler flags that are necessary to compile a program or library -that uses SDL. -.TP -.BI --exec-prefix= DIR -If specified, use -.I DIR -instead of the installation exec prefix that SDL was build with when -computing the output for the --cflags, --libs, --library-libs, and ---plugin-libs options. This option must be specified before any of the ---cflags, --libs, --library-libs, and --plugin-libs options. -.TP -.B --libs -Print the linker flags that are necessary to link a program that uses SDL. -.TP -.B --static-libs -Print the linker flags that are necessary to statically link a program that uses SDL. -.TP -.B --library-libs -Print the linker flags that are necessary to link a library that uses SDL. -(This excludes any static objects required for linking, since these must be -linked only by executable programs.) -.TP -.B --plugin-libs -Print the linker flags that are necessary to link an SDL-using object that -is to be accessed via -.IR dlopen (3). -This may include static objects with PIC symbol information. This option -should -.B not -be used for ordinary shared libraries or standalone applications. -.TP -.BI --prefix= DIR -If specified, use PREFIX instead of the installation prefix that SDL was -built with when computing the output for the --cflags, --libs, ---library-libs, and --plugin-libs options. This option is also used for -the exec prefix if --exec-prefix was not specified. This option must be -specified before any of the --cflags, --libs, --library-libs, and ---plugin-libs options. -.TP -.B --version -Prints the currently installed version of SDL on standard output. -.SH EXAMPLES -.TP -gcc -o main.o $(sdl2-config --cflags) main.c -is how you might use -.B sdl2-config -to compile a C source file for an executable program. -.TP -gcc -o my_app $(sdl2-config --libs) main.o util.o -is how you might use -.B sdl2-config -to link compiled objects into an executable program. -.TP -gcc -o libSDL_nifty-2.0.so.0.0.1 $(sdl --library-libs) read.o write.o munge.o -is how you might use -.B sdl2-config -to link compiled objects into a shared library. -.TP -gcc -o libnifty_xmms.so $(sdl --plugin-libs) stream.o blit.o deinterlace.o -is how you might use -.B sdl2-config -to link compiled objects into a plugin for use by another program. -.SH AUTHOR -The Simple DirectMedia Layer (SDL) library was written by Sam Lantinga. -.PP -This manual page was written by Branden Robinson, originally for Progeny -Linux Systems, Inc., and the Debian Project. diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db8f..000000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/debian/watch b/debian/watch deleted file mode 100644 index 07dc20117..000000000 --- a/debian/watch +++ /dev/null @@ -1,2 +0,0 @@ -version=3 -http://www.libsdl.org/release/SDL-([\d.]+)\.tar\.gz diff --git a/docs/README-android.md b/docs/README-android.md index 9ad8627b3..39db67ad6 100644 --- a/docs/README-android.md +++ b/docs/README-android.md @@ -206,6 +206,9 @@ You should not use the SDL renderer API while the app going in background: after you read this message, GL context gets backed-up and you should not use the SDL renderer API. + When this event is received, you have to set the render target to NULL, if you're using it. + (eg call SDL_SetRenderTarget(renderer, NULL)) + - SDL_APP_DIDENTERFOREGROUND: GL context is restored, and the SDL renderer API is available (unless you receive SDL_RENDER_DEVICE_RESET). diff --git a/docs/README-directfb.md b/docs/README-directfb.md index eeac42806..3b28eef34 100644 --- a/docs/README-directfb.md +++ b/docs/README-directfb.md @@ -15,29 +15,34 @@ What you need: * Kernel-Framebuffer support: required: vesafb, radeonfb .... * Mesa 7.0.x - optional for OpenGL -/etc/directfbrc - -This file should contain the following lines to make +The `/etc/directfbrc` file should contain the following lines to make your joystick work and avoid crashes: ------------------------- + +``` disable-module=joystick disable-module=cle266 disable-module=cyber5k no-linux-input-grab ------------------------- +``` To disable to use x11 backend when DISPLAY variable is found use +``` export SDL_DIRECTFB_X11_CHECK=0 +``` To disable the use of linux input devices, i.e. multimice/multikeyboard support, use +``` export SDL_DIRECTFB_LINUX_INPUT=0 +``` To use hardware accelerated YUV-overlays for YUV-textures, use: +``` export SDL_DIRECTFB_YUV_DIRECT=1 +``` This is disabled by default. It will only support one YUV texture, namely the first. Every other YUV texture will be @@ -45,7 +50,9 @@ rendered in software. In addition, you may use (directfb-1.2.x) +``` export SDL_DIRECTFB_YUV_UNDERLAY=1 +``` to make the YUV texture an underlay. This will make the cursor to be shown. @@ -54,14 +61,18 @@ Simple Window Manager ===================== The driver has support for a very, very basic window manager you may -want to use when running with "wm=default". Use +want to use when running with `wm=default`. Use +``` export SDL_DIRECTFB_WM=1 +``` to enable basic window borders. In order to have the window title rendered, you need to have the following font installed: +``` /usr/share/fonts/truetype/freefont/FreeSans.ttf +``` OpenGL Support ============== @@ -71,21 +82,25 @@ works at least on all directfb supported platforms. As of this writing 20100802 you need to pull Mesa from git and do the following: ------------------------- +``` git clone git://anongit.freedesktop.org/git/mesa/mesa cd mesa git checkout 2c9fdaf7292423c157fc79b5ce43f0f199dd753a ------------------------- +``` + +Edit `configs/linux-directfb` so that the Directories-section looks like this: -Edit configs/linux-directfb so that the Directories-section looks like ------------------------- +``` # Directories SRC_DIRS = mesa glu GLU_DIRS = sgi DRIVER_DIRS = directfb PROGRAM_DIRS = ------------------------- +``` +Then do the following: + +``` make linux-directfb make @@ -95,13 +110,14 @@ sudo make install INSTALL_DIR=/usr/local/dfb_GL cd src/mesa/drivers/directfb make sudo make install INSTALL_DIR=/usr/local/dfb_GL ------------------------- +``` To run the SDL - testprograms: +``` export SDL_VIDEODRIVER=directfb export LD_LIBRARY_PATH=/usr/local/dfb_GL/lib export LD_PRELOAD=/usr/local/dfb_GL/libGL.so.7 ./testgl - +``` diff --git a/docs/README-psp.md b/docs/README-psp.md index 8e781f4cb..0c84f866b 100644 --- a/docs/README-psp.md +++ b/docs/README-psp.md @@ -1,31 +1,36 @@ PSP ====== -SDL port for the Sony PSP contributed by - Captian Lex +SDL2 port for the Sony PSP contributed by: +- Captian Lex +- Francisco Javier Trujillo Mata +- Wouter Wijsman + Credit to Marcus R.Brown,Jim Paris,Matthew H for the original SDL 1.2 for PSP Geecko for his PSP GU lib "Glib2d" -Building --------- -To build SDL2 library for the PSP, make sure psp-config is in the path and run: - make -f Makefile.psp +## Building +To build SDL2 library for the PSP, make sure you have the latest PSPDev status and run: +```bash +cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=$PSPDEV/psp/share/pspdev.cmake +cmake --build build +cmake --install build +``` + + +## Getting PSP Dev +[Installing PSP Dev](https://github.com/pspdev/pspdev) +## Running on PPSSPP Emulator +[PPSSPP](https://github.com/hrydgard/ppsspp) -Getting PSP toolchain ---------------------- -https://github.com/pspdev/psptoolchain +[Build Instructions](https://github.com/hrydgard/ppsspp/wiki/Build-instructions) -Running on PPSSPP Emulator --------------------------- -https://github.com/hrydgard/ppsspp -( https://github.com/hrydgard/ppsspp/wiki/Build-instructions ) -Compiling an HelloWorld ------------------------ -https://psp-dev.org/doku.php?id=tutorial:hello_world +## Compiling a HelloWorld +[PSP Hello World](https://psp-dev.org/doku.php?id=tutorial:hello_world) -To Do ------- -PSP Screen Keyboard +## To Do +- PSP Screen Keyboard +- Dialogs \ No newline at end of file diff --git a/docs/README-visualc.md b/docs/README-visualc.md index ea2bc1852..759752a56 100644 --- a/docs/README-visualc.md +++ b/docs/README-visualc.md @@ -1,7 +1,7 @@ Using SDL with Microsoft Visual C++ =================================== -### by [Lion Kimbro](mailto:snowlion@sprynet.com) with additions by [James Turk](mailto:james@conceptofzero.net) +### by Lion Kimbro with additions by James Turk You can either use the precompiled libraries from the [SDL](https://www.libsdl.org/download.php) web site, or you can build SDL yourself. diff --git a/docs/README-vita.md b/docs/README-vita.md index aefa19703..503fef7d5 100644 --- a/docs/README-vita.md +++ b/docs/README-vita.md @@ -3,7 +3,7 @@ PS Vita SDL port for the Sony Playstation Vita and Sony Playstation TV Credit to -* xerpi and rsn8887 for initial (vita2d) port +* xerpi, cpasjuste and rsn8887 for initial (vita2d) port * vitasdk/dolcesdk devs * CBPS discord (Namely Graphene and SonicMastr) @@ -22,6 +22,9 @@ Notes * gles1/gles2 support and renderers are disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PVR=ON` These renderers support 720p and 1080i resolutions. These can be specified with: `SDL_setenv("VITA_RESOLUTION", "720", 1);` and `SDL_setenv("VITA_RESOLUTION", "1080", 1);` +* Desktop GL 1.X and 2.X support and renderers are also disabled by default and also can be enabled with `-DVIDEO_VITA_PVR=ON` as long as gl4es4vita is present in your SDK. + They support the same resolutions as the gles1/gles2 backends and require specifying `SDL_setenv("VITA_PVR_OGL", "1", 1);` + anytime before video subsystem initialization. * gles2 support via PIB is disabled by default and can be enabled by configuring with `-DVIDEO_VITA_PIB=ON` * By default SDL emits mouse events for touch events on every touchscreen. Vita has two touchscreens, so it's recommended to use `SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");` and handle touch events instead. diff --git a/docs/README-windows.md b/docs/README-windows.md index 71f968eeb..ed0c93e2c 100644 --- a/docs/README-windows.md +++ b/docs/README-windows.md @@ -1,45 +1,58 @@ -Windows -================================================================================ - -================================================================================ -OpenGL ES 2.x support -================================================================================ - -SDL has support for OpenGL ES 2.x under Windows via two alternative -implementations. -The most straightforward method consists in running your app in a system with -a graphic card paired with a relatively recent (as of November of 2013) driver -which supports the WGL_EXT_create_context_es2_profile extension. Vendors known +# Windows + +## LLVM and Intel C++ compiler support + +SDL will build with the Visual Studio project files with LLVM-based compilers, such as the Intel oneAPI C++ +compiler, but you'll have to manually add the "-msse3" command line option +to at least the SDL_audiocvt.c source file, and possibly others. This may +not be necessary if you build SDL with CMake instead of the included Visual +Studio solution. + +Details are here: https://github.com/libsdl-org/SDL/issues/5186 + + +## OpenGL ES 2.x support + +SDL has support for OpenGL ES 2.x under Windows via two alternative +implementations. + +The most straightforward method consists in running your app in a system with +a graphic card paired with a relatively recent (as of November of 2013) driver +which supports the WGL_EXT_create_context_es2_profile extension. Vendors known to ship said extension on Windows currently include nVidia and Intel. -The other method involves using the ANGLE library (https://code.google.com/p/angleproject/) -If an OpenGL ES 2.x context is requested and no WGL_EXT_create_context_es2_profile -extension is found, SDL will try to load the libEGL.dll library provided by -ANGLE. +The other method involves using the +[ANGLE library](https://code.google.com/p/angleproject/). If an OpenGL ES 2.x +context is requested and no WGL_EXT_create_context_es2_profile extension is +found, SDL will try to load the libEGL.dll library provided by ANGLE. + To obtain the ANGLE binaries, you can either compile from source from -https://chromium.googlesource.com/angle/angle or copy the relevant binaries from -a recent Chrome/Chromium install for Windows. The files you need are: - - * libEGL.dll - * libGLESv2.dll - * d3dcompiler_46.dll (supports Windows Vista or later, better shader compiler) - or... - * d3dcompiler_43.dll (supports Windows XP or later) +https://chromium.googlesource.com/angle/angle or copy the relevant binaries +from a recent Chrome/Chromium install for Windows. The files you need are: + +- libEGL.dll +- libGLESv2.dll +- d3dcompiler_46.dll (supports Windows Vista or later, better shader + compiler) *or* d3dcompiler_43.dll (supports Windows XP or later) If you compile ANGLE from source, you can configure it so it does not need the -d3dcompiler_* DLL at all (for details on this, see their documentation). +d3dcompiler_* DLL at all (for details on this, see their documentation). However, by default SDL will try to preload the d3dcompiler_46.dll to -comply with ANGLE's requirements. If you wish SDL to preload d3dcompiler_43.dll (to -support Windows XP) or to skip this step at all, you can use the -SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more details). +comply with ANGLE's requirements. If you wish SDL to preload +d3dcompiler_43.dll (to support Windows XP) or to skip this step at all, you +can use the SDL_HINT_VIDEO_WIN_D3DCOMPILER hint (see SDL_hints.h for more +details). Known Bugs: - - * SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears - that there's a bug in the library which prevents the window contents from - refreshing if this is set to anything other than the default value. - -Vulkan Surface Support -============== - -Support for creating Vulkan surfaces is configured on by default. To disable it change the value of `SDL_VIDEO_VULKAN` to 0 in `SDL_config_windows.h`. You must install the [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) in order to use Vulkan graphics in your application. + +- SDL_GL_SetSwapInterval is currently a no op when using ANGLE. It appears + that there's a bug in the library which prevents the window contents from + refreshing if this is set to anything other than the default value. + +## Vulkan Surface Support + +Support for creating Vulkan surfaces is configured on by default. To disable +it change the value of `SDL_VIDEO_VULKAN` to 0 in `SDL_config_windows.h`. You +must install the [Vulkan SDK](https://www.lunarg.com/vulkan-sdk/) in order to +use Vulkan graphics in your application. + diff --git a/docs/README.md b/docs/README.md index 2dd8f1d66..efbe3ad0e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,7 +14,7 @@ hardware via OpenGL and Direct3D. It is used by video playback software, emulators, and popular games including Valve's award winning catalog and many Humble Bundle games. -SDL officially supports Windows, Mac OS X, Linux, iOS, and Android. +SDL officially supports Windows, macOS, Linux, iOS, and Android. Support for other platforms may be found in the source code. SDL is written in C, works natively with C++, and there are bindings @@ -38,7 +38,7 @@ More documentation and FAQs are available online at [the wiki](http://wiki.libsd - [Git](README-git.md) - [iOS](README-ios.md) - [Linux](README-linux.md) -- [OS X](README-macosx.md) +- [macOS](README-macos.md) - [OS/2](README-os2.md) - [Native Client](README-nacl.md) - [Pandora](README-pandora.md) diff --git a/include/SDL_audio.h b/include/SDL_audio.h index 181f66c57..ab25ec93d 100644 --- a/include/SDL_audio.h +++ b/include/SDL_audio.h @@ -500,9 +500,7 @@ extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index, * hardware. * * `spec` will be filled with the sample rate, sample format, and channel - * count. All other values in the structure are filled with 0. When the - * supported struct members are 0, SDL was unable to get the property from the - * backend. + * count. * * \param index the index of the audio device; valid values range from 0 to * SDL_GetNumAudioDevices() - 1 diff --git a/include/SDL_blendmode.h b/include/SDL_blendmode.h index b6d140dbb..08c9f9dd6 100644 --- a/include/SDL_blendmode.h +++ b/include/SDL_blendmode.h @@ -67,9 +67,8 @@ typedef enum SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */ SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< dst - src : supported by D3D9, D3D11, OpenGL, OpenGLES */ SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< src - dst : supported by D3D9, D3D11, OpenGL, OpenGLES */ - SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D11 */ - SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D11 */ - + SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D9, D3D11 */ + SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D9, D3D11 */ } SDL_BlendOperation; /** @@ -87,7 +86,6 @@ typedef enum SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */ SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */ SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */ - } SDL_BlendFactor; /** @@ -135,10 +133,10 @@ typedef enum * SDL 2.0.6. All renderers support the four blend modes listed in the * SDL_BlendMode enumeration. * - * - **direct3d**: Supports `SDL_BLENDOPERATION_ADD` with all factors. - * - **direct3d11**: Supports all operations with all factors. However, some + * - **direct3d**: Supports all operations with all factors. However, some * factors produce unexpected results with `SDL_BLENDOPERATION_MINIMUM` and * `SDL_BLENDOPERATION_MAXIMUM`. + * - **direct3d11**: Same as Direct3D 9. * - **opengl**: Supports the `SDL_BLENDOPERATION_ADD` operation with all * factors. OpenGL versions 1.1, 1.2, and 1.3 do not work correctly with SDL * 2.0.6. diff --git a/include/SDL_config.h b/include/SDL_config.h index 13014df8f..7afefabe2 100644 --- a/include/SDL_config.h +++ b/include/SDL_config.h @@ -39,8 +39,6 @@ #include "SDL_config_iphoneos.h" #elif defined(__ANDROID__) #include "SDL_config_android.h" -#elif defined(__PSP__) -#include "SDL_config_psp.h" #elif defined(__OS2__) #include "SDL_config_os2.h" #elif defined(__EMSCRIPTEN__) diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index 7f96bbe2f..fcd18e57d 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -253,6 +253,7 @@ #cmakedefine HAVE_AUDIOCLIENT_H @HAVE_AUDIOCLIENT_H@ #cmakedefine HAVE_TPCSHRD_H @HAVE_TPCSHRD_H@ #cmakedefine HAVE_SENSORSAPI_H @HAVE_SENSORSAPI_H@ +#cmakedefine HAVE_ROAPI_H @HAVE_ROAPI_H@ #cmakedefine HAVE_XINPUT_GAMEPAD_EX @HAVE_XINPUT_GAMEPAD_EX@ #cmakedefine HAVE_XINPUT_STATE_EX @HAVE_XINPUT_STATE_EX@ @@ -277,6 +278,8 @@ #cmakedefine SDL_VIDEO_DISABLED @SDL_VIDEO_DISABLED@ #cmakedefine SDL_POWER_DISABLED @SDL_POWER_DISABLED@ #cmakedefine SDL_FILESYSTEM_DISABLED @SDL_FILESYSTEM_DISABLED@ +#cmakedefine SDL_LOCALE_DISABLED @SDL_LOCALE_DISABLED@ +#cmakedefine SDL_MISC_DISABLED @SDL_MISC_DISABLED@ /* Enable various audio drivers */ #cmakedefine SDL_AUDIO_DRIVER_ALSA @SDL_AUDIO_DRIVER_ALSA@ @@ -491,6 +494,12 @@ #cmakedefine SDL_FILESYSTEM_VITA @SDL_FILESYSTEM_VITA@ #cmakedefine SDL_FILESYSTEM_PSP @SDL_FILESYSTEM_PSP@ +/* Enable misc subsystem */ +#cmakedefine SDL_MISC_DUMMY @SDL_MISC_DUMMY@ + +/* Enable locale subsystem */ +#cmakedefine SDL_LOCALE_DUMMY @SDL_LOCALE_DUMMY@ + /* Enable assembly routines */ #cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@ #cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@ @@ -512,6 +521,7 @@ #cmakedefine SDL_VIDEO_VITA_PIB @SDL_VIDEO_VITA_PIB@ #cmakedefine SDL_VIDEO_VITA_PVR @SDL_VIDEO_VITA_PVR@ +#cmakedefine SDL_VIDEO_VITA_PVR_OGL @SDL_VIDEO_VITA_PVR_OGL@ #if !defined(__WIN32__) && !defined(__WINRT__) # if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H) diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 0d981b410..f912e4112 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -242,6 +242,7 @@ #undef HAVE_AUDIOCLIENT_H #undef HAVE_TPCSHRD_H #undef HAVE_SENSORSAPI_H +#undef HAVE_ROAPI_H /* SDL internal assertion support */ #undef SDL_DEFAULT_ASSERT_LEVEL @@ -263,6 +264,8 @@ #undef SDL_VIDEO_DISABLED #undef SDL_POWER_DISABLED #undef SDL_FILESYSTEM_DISABLED +#undef SDL_LOCALE_DISABLED +#undef SDL_MISC_DISABLED /* Enable various audio drivers */ #undef SDL_AUDIO_DRIVER_AAUDIO @@ -445,16 +448,24 @@ #undef SDL_POWER_HARDWIRED /* Enable system filesystem support */ +#undef SDL_FILESYSTEM_ANDROID #undef SDL_FILESYSTEM_HAIKU #undef SDL_FILESYSTEM_COCOA #undef SDL_FILESYSTEM_DUMMY +#undef SDL_FILESYSTEM_RISCOS #undef SDL_FILESYSTEM_UNIX #undef SDL_FILESYSTEM_WINDOWS #undef SDL_FILESYSTEM_NACL -#undef SDL_FILESYSTEM_ANDROID #undef SDL_FILESYSTEM_EMSCRIPTEN #undef SDL_FILESYSTEM_OS2 -#undef SDL_FILESYSTEM_RISCOS +#undef SDL_FILESYSTEM_VITA +#undef SDL_FILESYSTEM_PSP + +/* Enable misc subsystem */ +#undef SDL_MISC_DUMMY + +/* Enable locale subsystem */ +#undef SDL_LOCALE_DUMMY /* Enable assembly routines */ #undef SDL_ASSEMBLY_ROUTINES diff --git a/include/SDL_config_emscripten.h b/include/SDL_config_emscripten.h index 7efe32373..028777df1 100644 --- a/include/SDL_config_emscripten.h +++ b/include/SDL_config_emscripten.h @@ -185,6 +185,7 @@ /* Enable various threading systems */ #ifdef __EMSCRIPTEN_PTHREADS__ #define SDL_THREAD_PTHREAD 1 +#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1 #endif /* Enable various timer systems */ diff --git a/include/SDL_config_psp.h b/include/SDL_config_psp.h deleted file mode 100644 index 72c1eb668..000000000 --- a/include/SDL_config_psp.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2022 Sam Lantinga - - 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_config_psp_h_ -#define SDL_config_psp_h_ -#define SDL_config_h_ - -#include "SDL_platform.h" - -#ifdef __GNUC__ -#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1 -#endif - -#define HAVE_GCC_ATOMICS 1 - -#define STDC_HEADERS 1 -#define HAVE_ALLOCA_H 1 -#define HAVE_CTYPE_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LIMITS_H 1 -#define HAVE_MATH_H 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDIO_H 1 -#define HAVE_STRING_H 1 -#define HAVE_SYS_TYPES_H 1 - -/* C library functions */ -#define HAVE_MALLOC 1 -#define HAVE_CALLOC 1 -#define HAVE_REALLOC 1 -#define HAVE_FREE 1 -#define HAVE_ALLOCA 1 -#define HAVE_GETENV 1 -#define HAVE_SETENV 1 -#define HAVE_PUTENV 1 -#define HAVE_SETENV 1 -#define HAVE_UNSETENV 1 -#define HAVE_QSORT 1 -#define HAVE_ABS 1 -#define HAVE_BCOPY 1 -#define HAVE_MEMSET 1 -#define HAVE_MEMCPY 1 -#define HAVE_MEMMOVE 1 -#define HAVE_MEMCMP 1 -#define HAVE_STRLEN 1 -#define HAVE_STRLCPY 1 -#define HAVE_STRLCAT 1 -#define HAVE_STRCHR 1 -#define HAVE_STRRCHR 1 -#define HAVE_STRSTR 1 -#define HAVE_STRTOL 1 -#define HAVE_STRTOUL 1 -#define HAVE_STRTOLL 1 -#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 -#define HAVE_STRNCASECMP 1 -#define HAVE_VSSCANF 1 -#define HAVE_VSNPRINTF 1 -#define HAVE_M_PI 1 -#define HAVE_ACOS 1 -#define HAVE_ACOSF 1 -#define HAVE_ASIN 1 -#define HAVE_ASINF 1 -#define HAVE_ATAN 1 -#define HAVE_ATANF 1 -#define HAVE_ATAN2 1 -#define HAVE_ATAN2F 1 -#define HAVE_CEIL 1 -#define HAVE_CEILF 1 -#define HAVE_COPYSIGN 1 -#define HAVE_COPYSIGNF 1 -#define HAVE_COS 1 -#define HAVE_COSF 1 -#define HAVE_EXP 1 -#define HAVE_EXPF 1 -#define HAVE_FABS 1 -#define HAVE_FABSF 1 -#define HAVE_FLOOR 1 -#define HAVE_FLOORF 1 -#define HAVE_FMOD 1 -#define HAVE_FMODF 1 -#define HAVE_LOG 1 -#define HAVE_LOGF 1 -#define HAVE_LOG10 1 -#define HAVE_LOG10F 1 -#define HAVE_POW 1 -#define HAVE_POWF 1 -#define HAVE_SCALBN 1 -#define HAVE_SCALBNF 1 -#define HAVE_SIN 1 -#define HAVE_SINF 1 -#define HAVE_SQRT 1 -#define HAVE_SQRTF 1 -#define HAVE_TAN 1 -#define HAVE_TANF 1 -#define HAVE_SETJMP 1 -#define HAVE_NANOSLEEP 1 -/* #define HAVE_SYSCONF 1 */ -/* #define HAVE_SIGACTION 1 */ - - -/* PSP isn't that sophisticated */ -#define LACKS_SYS_MMAN_H 1 - -/* Enable the PSP thread support (src/thread/psp/\*.c) */ -#define SDL_THREAD_PSP 1 - -/* Enable the PSP timer support (src/timer/psp/\*.c) */ -#define SDL_TIMER_PSP 1 - -/* Enable the PSP joystick driver (src/joystick/psp/\*.c) */ -#define SDL_JOYSTICK_PSP 1 -#define SDL_JOYSTICK_VIRTUAL 1 - -/* Enable the dummy sensor driver */ -#define SDL_SENSOR_DUMMY 1 - -/* Enable the PSP audio driver (src/audio/psp/\*.c) */ -#define SDL_AUDIO_DRIVER_PSP 1 - -/* PSP video driver */ -#define SDL_VIDEO_DRIVER_PSP 1 - -/* PSP render driver */ -#define SDL_VIDEO_RENDER_PSP 1 - -#define SDL_POWER_PSP 1 - -/* Enable the PSP filesystem support (src/filesystem/psp/\*.c) */ -#define SDL_FILESYSTEM_PSP 1 - -/* PSP doesn't have haptic device (src/haptic/dummy/\*.c) */ -#define SDL_HAPTIC_DISABLED 1 - -/* PSP doesn't have HIDAPI available */ -#define SDL_HIDAPI_DISABLED 1 - -/* PSP can't load shared object (src/loadso/dummy/\*.c) */ -#define SDL_LOADSO_DISABLED 1 - -#endif /* SDL_config_psp_h_ */ diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h index c9ed1cfea..770b19039 100644 --- a/include/SDL_config_windows.h +++ b/include/SDL_config_windows.h @@ -90,6 +90,10 @@ typedef unsigned int uintptr_t; # define SIZEOF_VOIDP 4 #endif +#ifdef __clang__ +# define HAVE_GCC_ATOMICS 1 +#endif + #define HAVE_DDRAW_H 1 #define HAVE_DINPUT_H 1 #define HAVE_DSOUND_H 1 @@ -100,6 +104,7 @@ typedef unsigned int uintptr_t; #endif #if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0602 /* Windows 8 SDK */ #define HAVE_D3D11_H 1 +#define HAVE_ROAPI_H 1 #endif #define HAVE_MMDEVICEAPI_H 1 #define HAVE_AUDIOCLIENT_H 1 diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index 690ffe159..f3901a597 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -92,6 +92,10 @@ typedef unsigned int uintptr_t; # define SIZEOF_VOIDP 4 #endif +#ifdef __clang__ +# define HAVE_GCC_ATOMICS 1 +#endif + /* Useful headers */ #define HAVE_DXGI_H 1 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP @@ -191,6 +195,8 @@ typedef unsigned int uintptr_t; #define HAVE_TRUNCF 1 #define HAVE__FSEEKI64 1 +#define HAVE_ROAPI_H 1 + /* Enable various audio drivers */ #define SDL_AUDIO_DRIVER_WASAPI 1 #define SDL_AUDIO_DRIVER_DISK 1 diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h deleted file mode 100644 index 29b8242ec..000000000 --- a/include/SDL_config_wiz.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2022 Sam Lantinga - - 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_config_wiz_h_ -#define SDL_config_wiz_h_ -#define SDL_config_h_ - -/* This is a set of defines to configure the SDL features */ - -/* General platform specific identifiers */ -#include "SDL_platform.h" - -#define SDL_BYTEORDER 1234 - -#define STDC_HEADERS 1 -#define HAVE_ALLOCA_H 1 -#define HAVE_CTYPE_H 1 -#define HAVE_ICONV_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LIMITS_H 1 -#define HAVE_MALLOC_H 1 -#define HAVE_MATH_H 1 -#define HAVE_MEMORY_H 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_STDARG_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDIO_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRINGS_H 1 -#define HAVE_STRING_H 1 -#define HAVE_SYS_TYPES_H 1 - -#define HAVE_DLOPEN 1 -#define HAVE_MALLOC 1 -#define HAVE_CALLOC 1 -#define HAVE_REALLOC 1 -#define HAVE_FREE 1 -#define HAVE_ALLOCA 1 -#define HAVE_GETENV 1 -#define HAVE_SETENV 1 -#define HAVE_PUTENV 1 -#define HAVE_UNSETENV 1 -#define HAVE_QSORT 1 -#define HAVE_ABS 1 -#define HAVE_BCOPY 1 -#define HAVE_MEMSET 1 -#define HAVE_MEMCPY 1 -#define HAVE_MEMMOVE 1 -#define HAVE_STRLEN 1 -#define HAVE_STRCHR 1 -#define HAVE_STRRCHR 1 -#define HAVE_STRSTR 1 -#define HAVE_STRTOK_R 1 -#define HAVE_STRTOL 1 -#define HAVE_STRTOUL 1 -#define HAVE_STRTOLL 1 -#define HAVE_STRTOULL 1 -#define HAVE_ATOI 1 -#define HAVE_ATOF 1 -#define HAVE_STRCMP 1 -#define HAVE_STRNCMP 1 -#define HAVE_STRCASECMP 1 -#define HAVE_STRNCASECMP 1 -#define HAVE_VSSCANF 1 -#define HAVE_VSNPRINTF 1 -#define HAVE_M_PI 1 -#define HAVE_ACOS 1 -#define HAVE_ACOSF 1 -#define HAVE_ASIN 1 -#define HAVE_ASINF 1 -#define HAVE_ATAN 1 -#define HAVE_ATANF 1 -#define HAVE_ATAN2 1 -#define HAVE_ATAN2F 1 -#define HAVE_CEIL 1 -#define HAVE_CEILF 1 -#define HAVE_COPYSIGN 1 -#define HAVE_COPYSIGNF 1 -#define HAVE_COS 1 -#define HAVE_COSF 1 -#define HAVE_EXP 1 -#define HAVE_EXPF 1 -#define HAVE_FABS 1 -#define HAVE_FABSF 1 -#define HAVE_FLOOR 1 -#define HAVE_FLOORF 1 -#define HAVE_FMOD 1 -#define HAVE_FMODF 1 -#define HAVE_LOG 1 -#define HAVE_LOGF 1 -#define HAVE_LOG10 1 -#define HAVE_LOG10F 1 -#define HAVE_LROUND 1 -#define HAVE_LROUNDF 1 -#define HAVE_POW 1 -#define HAVE_POWF 1 -#define HAVE_ROUND 1 -#define HAVE_ROUNDF 1 -#define HAVE_SCALBN 1 -#define HAVE_SCALBNF 1 -#define HAVE_SIN 1 -#define HAVE_SINF 1 -#define HAVE_SQRT 1 -#define HAVE_SQRTF 1 -#define HAVE_TAN 1 -#define HAVE_TANF 1 -#define HAVE_TRUNC 1 -#define HAVE_TRUNCF 1 -#define HAVE_SIGACTION 1 -#define HAVE_SETJMP 1 -#define HAVE_NANOSLEEP 1 -#define HAVE_POW 1 - -#define SDL_AUDIO_DRIVER_DUMMY 1 -#define SDL_AUDIO_DRIVER_OSS 1 - -#define SDL_INPUT_LINUXEV 1 -#define SDL_JOYSTICK_LINUX 1 -#define SDL_JOYSTICK_VIRTUAL 1 -#define SDL_HAPTIC_LINUX 1 - -#define SDL_SENSOR_DUMMY 1 - -#define SDL_LOADSO_DLOPEN 1 - -#define SDL_THREAD_PTHREAD 1 -#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1 - -#define SDL_TIMER_UNIX 1 - -#define SDL_VIDEO_DRIVER_DUMMY 1 -#define SDL_VIDEO_DRIVER_PANDORA 1 -#define SDL_VIDEO_RENDER_OGL_ES 1 -#define SDL_VIDEO_OPENGL_ES 1 - -#endif /* SDL_config_wiz_h_ */ diff --git a/include/SDL_endian.h b/include/SDL_endian.h index 46c296253..2866f4bea 100644 --- a/include/SDL_endian.h +++ b/include/SDL_endian.h @@ -65,6 +65,15 @@ _m_prefetch(void *__P) #elif defined(__FreeBSD__) || defined(__NetBSD__) #include #define SDL_BYTEORDER BYTE_ORDER +/* predefs from newer gcc and clang versions: */ +#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__) +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define SDL_BYTEORDER SDL_LIL_ENDIAN +#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define SDL_BYTEORDER SDL_BIG_ENDIAN +#else +#error Unsupported endianness +#endif /**/ #else #if defined(__hppa__) || \ defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ diff --git a/include/SDL_events.h b/include/SDL_events.h index b23188979..962300575 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -102,6 +102,7 @@ typedef enum SDL_KEYMAPCHANGED, /**< Keymap changed due to a system event such as an input language or keyboard layout change. */ + SDL_TEXTEDITING_EXT, /**< Extended keyboard text editing (composition) */ /* Mouse events */ SDL_MOUSEMOTION = 0x400, /**< Mouse moved */ @@ -244,6 +245,19 @@ typedef struct SDL_TextEditingEvent Sint32 length; /**< The length of selected editing text */ } SDL_TextEditingEvent; +/** + * \brief Extended keyboard text editing event structure (event.editExt.*) when text would be + * truncated if stored in the text buffer SDL_TextEditingEvent + */ +typedef struct SDL_TextEditingExtEvent +{ + Uint32 type; /**< ::SDL_TEXTEDITING_EXT */ + Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ + Uint32 windowID; /**< The window with keyboard focus, if any */ + char* text; /**< The editing text, which should be freed with SDL_free(), and will not be NULL */ + Sint32 start; /**< The start cursor of selected editing text */ + Sint32 length; /**< The length of selected editing text */ +} SDL_TextEditingExtEvent; #define SDL_TEXTINPUTEVENT_TEXT_SIZE (32) /** @@ -618,6 +632,7 @@ typedef union SDL_Event SDL_WindowEvent window; /**< Window event data */ SDL_KeyboardEvent key; /**< Keyboard event data */ SDL_TextEditingEvent edit; /**< Text editing event data */ + SDL_TextEditingExtEvent editExt; /**< Extended text editing event data */ SDL_TextInputEvent text; /**< Text input event data */ SDL_MouseMotionEvent motion; /**< Mouse motion event data */ SDL_MouseButtonEvent button; /**< Mouse button event data */ diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index bdd9b8993..548861083 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -869,8 +869,9 @@ extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecon * calling it with 0 intensity stops any rumbling. * * Note that this is rumbling of the _triggers_ and not the game controller as - * a whole. The first controller to offer this feature was the PlayStation 5's - * DualShock 5. + * a whole. This is currently only supported on Xbox One controllers. If you + * want the (more common) whole-controller rumble, use + * SDL_GameControllerRumble() instead. * * \param gamecontroller The controller to vibrate * \param left_rumble The intensity of the left trigger rumble motor, from 0 diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 9336e41fe..c57bfc22f 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -412,6 +412,19 @@ extern "C" { */ #define SDL_HINT_EVENT_LOGGING "SDL_EVENT_LOGGING" +/** + * \brief A variable controlling whether raising the window should be done more forcefully + * + * This variable can be set to the following values: + * "0" - No forcing (the default) + * "1" - Extra level of forcing + * + * At present, this is only an issue under MS Windows, which makes it nearly impossible to + * programmatically move a window to the foreground, for "security" reasons. See + * http://stackoverflow.com/a/34414846 for a discussion. + */ +#define SDL_HINT_FORCE_RAISEWINDOW "SDL_HINT_FORCE_RAISEWINDOW" + /** * \brief A variable controlling how 3D acceleration is used to accelerate the SDL screen surface. * @@ -566,6 +579,17 @@ extern "C" { */ #define SDL_HINT_IME_SHOW_UI "SDL_IME_SHOW_UI" +/** + * \brief A variable to control if extended IME text support is enabled. + * If enabled then SDL_TextEditingExtEvent will be issued if the text would be truncated otherwise. + * Additionally SDL_TextInputEvent will be dispatched multiple times so that it is not truncated. + * + * The variable can be set to the following values: + * "0" - Legacy behavior. Text can be truncated, no heap allocations. (default) + * "1" - Modern behavior. + */ +#define SDL_HINT_IME_SUPPORT_EXTENDED_TEXT "SDL_IME_SUPPORT_EXTENDED_TEXT" + /** * \brief A variable controlling whether the home indicator bar on iPhone X * should be hidden. @@ -612,6 +636,21 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE "SDL_JOYSTICK_HIDAPI_GAMECUBE" +/** + * \brief A variable controlling whether "low_frequency_rumble" and "high_frequency_rumble" is used to implement + * the GameCube controller's 3 rumble modes, Stop(0), Rumble(1), and StopHard(2) + * this is useful for applications that need full compatibility for things like ADSR envelopes. + * Stop is implemented by setting "low_frequency_rumble" to "0" and "high_frequency_rumble" ">0" + * Rumble is both at any arbitrary value, + * StopHard is implemented by setting both "low_frequency_rumble" and "high_frequency_rumble" to "0" + * + * This variable can be set to the following values: + * "0" - Normal rumble behavior is behavior is used (default) + * "1" - Proper GameCube controller rumble behavior is used + * + */ +#define SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE "SDL_JOYSTICK_GAMECUBE_RUMBLE_BRAKE" + /** * \brief A variable controlling whether Switch Joy-Cons should be treated the same as Switch Pro Controllers when using the HIDAPI driver. * @@ -766,7 +805,6 @@ extern "C" { * This variable can be set to the following values: * "0" - RAWINPUT drivers are not used * "1" - RAWINPUT drivers are used (the default) - * */ #define SDL_HINT_JOYSTICK_RAWINPUT "SDL_JOYSTICK_RAWINPUT" @@ -783,6 +821,15 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_RAWINPUT_CORRELATE_XINPUT "SDL_JOYSTICK_RAWINPUT_CORRELATE_XINPUT" + /** + * \brief A variable controlling whether the ROG Chakram mice should show up as joysticks + * + * This variable can be set to the following values: + * "0" - ROG Chakram mice do not show up as joysticks (the default) + * "1" - ROG Chakram mice show up as joysticks + */ +#define SDL_HINT_JOYSTICK_ROG_CHAKRAM "SDL_JOYSTICK_ROG_CHAKRAM" + /** * \brief A variable controlling whether a separate thread should be used * for handling joystick detection and raw input messages on Windows @@ -886,6 +933,22 @@ extern "C" { */ #define SDL_HINT_MOUSE_NORMAL_SPEED_SCALE "SDL_MOUSE_NORMAL_SPEED_SCALE" +/** + * \brief A variable controlling whether relative mouse mode constrains the mouse to the center of the window + * + * This variable can be set to the following values: + * "0" - Relative mouse mode constrains the mouse to the window + * "1" - Relative mouse mode constrains the mouse to the center of the window + * + * Constraining to the center of the window works better for FPS games and when the + * application is running over RDP. Constraining to the whole window works better + * for 2D games and increases the chance that the mouse will be in the correct + * position when using high DPI mice. + * + * By default SDL will constrain the mouse to the center of the window + */ +#define SDL_HINT_MOUSE_RELATIVE_MODE_CENTER "SDL_MOUSE_RELATIVE_MODE_CENTER" + /** * \brief A variable controlling whether relative mouse mode is implemented using mouse warping * @@ -922,6 +985,19 @@ extern "C" { */ #define SDL_HINT_MOUSE_TOUCH_EVENTS "SDL_MOUSE_TOUCH_EVENTS" +/** + * \brief A variable controlling whether the mouse is captured while mouse buttons are pressed + * + * This variable can be set to the following values: + * "0" - The mouse is not captured while mouse buttons are pressed + * "1" - The mouse is captured while mouse buttons are pressed + * + * By default the mouse is captured while mouse buttons are pressed so if the mouse is dragged + * outside the window, the application continues to receive mouse events until the button is + * released. + */ +#define SDL_HINT_MOUSE_AUTO_CAPTURE "SDL_MOUSE_AUTO_CAPTURE" + /** * \brief Tell SDL not to catch the SIGINT or SIGTERM signals. * @@ -1278,6 +1354,18 @@ extern "C" { */ #define SDL_HINT_TOUCH_MOUSE_EVENTS "SDL_TOUCH_MOUSE_EVENTS" +/** + * \brief A variable controlling which touchpad should generate synthetic mouse events + * + * This variable can be set to the following values: + * "0" - Only front touchpad should generate mouse events. Default + * "1" - Only back touchpad should generate mouse events. + * "2" - Both touchpads should generate mouse events. + * + * By default SDL will generate mouse events for all touch devices + */ +#define SDL_HINT_VITA_TOUCH_MOUSE_DEVICE "SDL_HINT_VITA_TOUCH_MOUSE_DEVICE" + /** * \brief A variable controlling whether the Android / tvOS remotes * should be listed as joystick devices, instead of sending keyboard events. @@ -1387,6 +1475,20 @@ extern "C" { */ #define SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR "SDL_VIDEO_WAYLAND_ALLOW_LIBDECOR" +/** + * \brief A variable controlling whether the libdecor Wayland backend is preferred over native decrations. + * + * When this hint is set, libdecor will be used to provide window decorations, even if xdg-decoration is + * available. (Note that, by default, libdecor will use xdg-decoration itself if available). + * + * This variable can be set to the following values: + * "0" - libdecor is enabled only if server-side decorations are unavailable. + * "1" - libdecor is always enabled if available. + * + * libdecor is used over xdg-shell when xdg-decoration protocol is unavailable. + */ +#define SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR "SDL_VIDEO_WAYLAND_PREFER_LIBDECOR" + /** * \brief A variable that is the address of another SDL_Window* (as a hex string formatted with "%p"). * @@ -1406,6 +1508,28 @@ extern "C" { */ #define SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT" +/** + * \brief When calling SDL_CreateWindowFrom(), make the window compatible with OpenGL. + * + * This variable can be set to the following values: + * "0" - Don't add any graphics flags to the SDL_WindowFlags + * "1" - Add SDL_WINDOW_OPENGL to the SDL_WindowFlags + * + * By default SDL will not make the foreign window compatible with OpenGL. + */ +#define SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL "SDL_VIDEO_FOREIGN_WINDOW_OPENGL" + +/** + * \brief When calling SDL_CreateWindowFrom(), make the window compatible with Vulkan. + * + * This variable can be set to the following values: + * "0" - Don't add any graphics flags to the SDL_WindowFlags + * "1" - Add SDL_WINDOW_VULKAN to the SDL_WindowFlags + * + * By default SDL will not make the foreign window compatible with Vulkan. + */ +#define SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN "SDL_VIDEO_FOREIGN_WINDOW_VULKAN" + /** * \brief A variable specifying which shader compiler to preload when using the Chrome ANGLE binaries * @@ -1824,6 +1948,96 @@ extern "C" { */ #define SDL_HINT_AUDIO_INCLUDE_MONITORS "SDL_AUDIO_INCLUDE_MONITORS" +/** + * \brief A variable that forces X11 windows to create as a custom type. + * + * This is currently only used for X11 and ignored elsewhere. + * + * During SDL_CreateWindow, SDL uses the _NET_WM_WINDOW_TYPE X11 property + * to report to the window manager the type of window it wants to create. + * This might be set to various things if SDL_WINDOW_TOOLTIP or + * SDL_WINDOW_POPUP_MENU, etc, were specified. For "normal" windows that + * haven't set a specific type, this hint can be used to specify a custom + * type. For example, a dock window might set this to + * "_NET_WM_WINDOW_TYPE_DOCK". + * + * If not set or set to "", this hint is ignored. This hint must be set + * before the SDL_CreateWindow() call that it is intended to affect. + * + * This hint is available since SDL 2.0.22. + */ +#define SDL_HINT_X11_WINDOW_TYPE "SDL_X11_WINDOW_TYPE" + +/** + * \brief A variable that decides whether to send SDL_QUIT when closing the final window. + * + * By default, SDL sends an SDL_QUIT event when there is only one window + * and it receives an SDL_WINDOWEVENT_CLOSE event, under the assumption most + * apps would also take the loss of this window as a signal to terminate the + * program. + * + * However, it's not unreasonable in some cases to have the program continue + * to live on, perhaps to create new windows later. + * + * Changing this hint to "0" will cause SDL to not send an SDL_QUIT event + * when the final window is requesting to close. Note that in this case, + * there are still other legitimate reasons one might get an SDL_QUIT + * event: choosing "Quit" from the macOS menu bar, sending a SIGINT (ctrl-c) + * on Unix, etc. + * + * The default value is "1". This hint can be changed at any time. + * + * This hint is available since SDL 2.0.22. Before then, you always get + * an SDL_QUIT event when closing the final window. + */ +#define SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE "SDL_QUIT_ON_LAST_WINDOW_CLOSE" + +/** + * \brief A variable that decides what video backend to use. + * + * By default, SDL will try all available video backends in a reasonable + * order until it finds one that can work, but this hint allows the app + * or user to force a specific target, such as "x11" if, say, you are + * on Wayland but want to try talking to the X server instead. + * + * This functionality has existed since SDL 2.0.0 (indeed, before that) + * but before 2.0.22 this was an environment variable only. In 2.0.22, + * it was upgraded to a full SDL hint, so you can set the environment + * variable as usual or programatically set the hint with SDL_SetHint, + * which won't propagate to child processes. + * + * The default value is unset, in which case SDL will try to figure out + * the best video backend on your behalf. This hint needs to be set + * before SDL_Init() is called to be useful. + * + * This hint is available since SDL 2.0.22. Before then, you could set + * the environment variable to get the same effect. + */ +#define SDL_HINT_VIDEODRIVER "SDL_VIDEODRIVER" + +/** + * \brief A variable that decides what audio backend to use. + * + * By default, SDL will try all available audio backends in a reasonable + * order until it finds one that can work, but this hint allows the app + * or user to force a specific target, such as "alsa" if, say, you are + * on PulseAudio but want to try talking to the lower level instead. + * + * This functionality has existed since SDL 2.0.0 (indeed, before that) + * but before 2.0.22 this was an environment variable only. In 2.0.22, + * it was upgraded to a full SDL hint, so you can set the environment + * variable as usual or programatically set the hint with SDL_SetHint, + * which won't propagate to child processes. + * + * The default value is unset, in which case SDL will try to figure out + * the best audio backend on your behalf. This hint needs to be set + * before SDL_Init() is called to be useful. + * + * This hint is available since SDL 2.0.22. Before then, you could set + * the environment variable to get the same effect. + */ +#define SDL_HINT_AUDIODRIVER "SDL_AUDIODRIVER" + /** * \brief Configure a macOS window as full-size content view. * diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h index e80c0057f..07e2b1561 100644 --- a/include/SDL_joystick.h +++ b/include/SDL_joystick.h @@ -829,9 +829,9 @@ extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 lo * Each call to this function cancels any previous trigger rumble effect, and * calling it with 0 intensity stops any rumbling. * - * Note that this function is for _trigger_ rumble; the first joystick to - * support this was the PlayStation 5's DualShock 5 controller. If you want - * the (more common) whole-controller rumble, use SDL_JoystickRumble() + * Note that this is rumbling of the _triggers_ and not the game controller as + * a whole. This is currently only supported on Xbox One controllers. If you + * want the (more common) whole-controller rumble, use SDL_JoystickRumble() * instead. * * \param joystick The joystick to vibrate diff --git a/include/SDL_keyboard.h b/include/SDL_keyboard.h index a53dde68e..0aa599076 100644 --- a/include/SDL_keyboard.h +++ b/include/SDL_keyboard.h @@ -268,9 +268,30 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputActive(void); */ extern DECLSPEC void SDLCALL SDL_StopTextInput(void); +/** + * Dismiss the composition window/IME without disabling the subsystem. + * + * \since This function is available since SDL 2.0.22. + * + * \sa SDL_StartTextInput + * \sa SDL_StopTextInput + */ +extern DECLSPEC void SDLCALL SDL_ClearComposition(void); + +/** + * Returns if an IME Composite or Candidate window is currently shown. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_IsTextInputShown(void); + /** * Set the rectangle used to type Unicode text inputs. * + * Note: If you want use system native IME window, try to set hint + * **SDL_HINT_IME_SHOW_UI** to **1**, otherwise this function won't give you + * any feedback. + * * \param rect the SDL_Rect structure representing the rectangle to receive * text (ignored if NULL) * diff --git a/include/SDL_metal.h b/include/SDL_metal.h index 9ecaa8151..eb3082879 100644 --- a/include/SDL_metal.h +++ b/include/SDL_metal.h @@ -92,6 +92,7 @@ extern DECLSPEC void *SDLCALL SDL_Metal_GetLayer(SDL_MetalView view); * * \param window SDL_Window from which the drawable size should be queried * \param w Pointer to variable for storing the width in pixels, may be NULL + * \param h Pointer to variable for storing the height in pixels, may be NULL * * \since This function is available since SDL 2.0.14. * diff --git a/include/SDL_rect.h b/include/SDL_rect.h index 6616ba6a2..b678c7a34 100644 --- a/include/SDL_rect.h +++ b/include/SDL_rect.h @@ -54,8 +54,8 @@ typedef struct SDL_Point /** * The structure that defines a point (floating point) * - * \sa SDL_EnclosePoints - * \sa SDL_PointInRect + * \sa SDL_EncloseFPoints + * \sa SDL_PointInFRect */ typedef struct SDL_FPoint { @@ -71,6 +71,7 @@ typedef struct SDL_FPoint * \sa SDL_RectEquals * \sa SDL_HasIntersection * \sa SDL_IntersectRect + * \sa SDL_IntersectRectAndLine * \sa SDL_UnionRect * \sa SDL_EnclosePoints */ @@ -83,6 +84,16 @@ typedef struct SDL_Rect /** * A rectangle, with the origin at the upper left (floating point). + * + * \sa SDL_FRectEmpty + * \sa SDL_FRectEquals + * \sa SDL_FRectEqualsEpsilon + * \sa SDL_HasIntersectionF + * \sa SDL_IntersectFRect + * \sa SDL_IntersectFRectAndLine + * \sa SDL_UnionFRect + * \sa SDL_EncloseFPoints + * \sa SDL_PointInFRect */ typedef struct SDL_FRect { @@ -213,6 +224,147 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IntersectRectAndLine(const SDL_Rect * int *Y1, int *X2, int *Y2); + +/* SDL_FRect versions... */ + +/** + * Returns true if point resides inside a rectangle. + */ +SDL_FORCE_INLINE SDL_bool SDL_PointInFRect(const SDL_FPoint *p, const SDL_FRect *r) +{ + return ( (p->x >= r->x) && (p->x < (r->x + r->w)) && + (p->y >= r->y) && (p->y < (r->y + r->h)) ) ? SDL_TRUE : SDL_FALSE; +} + +/** + * Returns true if the rectangle has no area. + */ +SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r) +{ + return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE; +} + +/** + * Returns true if the two rectangles are equal, within some given epsilon. + * + * \since This function is available since SDL 2.0.22. + */ +SDL_FORCE_INLINE SDL_bool SDL_FRectEqualsEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon) +{ + return (a && b && ((a == b) || + ((SDL_fabs(a->x - b->x) <= epsilon) && + (SDL_fabs(a->y - b->y) <= epsilon) && + (SDL_fabs(a->w - b->w) <= epsilon) && + (SDL_fabs(a->h - b->h) <= epsilon)))) + ? SDL_TRUE : SDL_FALSE; +} + +/** + * Returns true if the two rectangles are equal, using a default epsilon. + * + * \since This function is available since SDL 2.0.22. + */ +SDL_FORCE_INLINE SDL_bool SDL_FRectEquals(const SDL_FRect *a, const SDL_FRect *b) +{ + return SDL_FRectEqualsEpsilon(a, b, SDL_FLT_EPSILON); +} + +/** + * Determine whether two rectangles intersect with float precision. + * + * If either pointer is NULL the function will return SDL_FALSE. + * + * \param A an SDL_FRect structure representing the first rectangle + * \param B an SDL_FRect structure representing the second rectangle + * \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise. + * + * \since This function is available since SDL 2.0.22. + * + * \sa SDL_IntersectRect + */ +extern DECLSPEC SDL_bool SDLCALL SDL_HasIntersectionF(const SDL_FRect * A, + const SDL_FRect * B); + +/** + * Calculate the intersection of two rectangles with float precision. + * + * If `result` is NULL then this function will return SDL_FALSE. + * + * \param A an SDL_FRect structure representing the first rectangle + * \param B an SDL_FRect structure representing the second rectangle + * \param result an SDL_FRect structure filled in with the intersection of + * rectangles `A` and `B` + * \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise. + * + * \since This function is available since SDL 2.0.22. + * + * \sa SDL_HasIntersectionF + */ +extern DECLSPEC SDL_bool SDLCALL SDL_IntersectFRect(const SDL_FRect * A, + const SDL_FRect * B, + SDL_FRect * result); + +/** + * Calculate the union of two rectangles with float precision. + * + * \param A an SDL_FRect structure representing the first rectangle + * \param B an SDL_FRect structure representing the second rectangle + * \param result an SDL_FRect structure filled in with the union of rectangles + * `A` and `B` + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC void SDLCALL SDL_UnionFRect(const SDL_FRect * A, + const SDL_FRect * B, + SDL_FRect * result); + +/** + * Calculate a minimal rectangle enclosing a set of points with float + * precision. + * + * If `clip` is not NULL then only points inside of the clipping rectangle are + * considered. + * + * \param points an array of SDL_FPoint structures representing points to be + * enclosed + * \param count the number of structures in the `points` array + * \param clip an SDL_FRect used for clipping or NULL to enclose all points + * \param result an SDL_FRect structure filled in with the minimal enclosing + * rectangle + * \returns SDL_TRUE if any points were enclosed or SDL_FALSE if all the + * points were outside of the clipping rectangle. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_EncloseFPoints(const SDL_FPoint * points, + int count, + const SDL_FRect * clip, + SDL_FRect * result); + +/** + * Calculate the intersection of a rectangle and line segment with float + * precision. + * + * This function is used to clip a line segment to a rectangle. A line segment + * contained entirely within the rectangle or that does not intersect will + * remain unchanged. A line segment that crosses the rectangle at either or + * both ends will be clipped to the boundary of the rectangle and the new + * coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary. + * + * \param rect an SDL_FRect structure representing the rectangle to intersect + * \param X1 a pointer to the starting X-coordinate of the line + * \param Y1 a pointer to the starting Y-coordinate of the line + * \param X2 a pointer to the ending X-coordinate of the line + * \param Y2 a pointer to the ending Y-coordinate of the line + * \returns SDL_TRUE if there is an intersection, SDL_FALSE otherwise. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_IntersectFRectAndLine(const SDL_FRect * + rect, float *X1, + float *Y1, float *X2, + float *Y2); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus } diff --git a/include/SDL_render.h b/include/SDL_render.h index 948202dca..674ee6500 100644 --- a/include/SDL_render.h +++ b/include/SDL_render.h @@ -261,6 +261,17 @@ extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateSoftwareRenderer(SDL_Surface * */ extern DECLSPEC SDL_Renderer * SDLCALL SDL_GetRenderer(SDL_Window * window); +/** + * Get the window associated with a renderer. + * + * \param renderer the renderer to query + * \returns the window on success or NULL on failure; call SDL_GetError() for + * more information. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC SDL_Window * SDLCALL SDL_RenderGetWindow(SDL_Renderer *renderer); + /** * Get information about a rendering context. * @@ -402,11 +413,15 @@ extern DECLSPEC SDL_Texture * SDLCALL SDL_CreateTextureFromHandle(SDL_Renderer * * \param texture the texture to query * \param format a pointer filled in with the raw format of the texture; the * actual format may differ, but pixel transfers will use this - * format (one of the SDL_PixelFormatEnum values) + * format (one of the SDL_PixelFormatEnum values). This argument + * can be NULL if you don't need this information. * \param access a pointer filled in with the actual access to the texture - * (one of the SDL_TextureAccess values) - * \param w a pointer filled in with the width of the texture in pixels - * \param h a pointer filled in with the height of the texture in pixels + * (one of the SDL_TextureAccess values). This argument can be + * NULL if you don't need this information. + * \param w a pointer filled in with the width of the texture in pixels. This + * argument can be NULL if you don't need this information. + * \param h a pointer filled in with the height of the texture in pixels. This + * argument can be NULL if you don't need this information. * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * @@ -1649,6 +1664,7 @@ extern DECLSPEC int SDLCALL SDL_RenderCopyExF(SDL_Renderer * renderer, * vertex array Color and alpha modulation is done per vertex * (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored). * + * \param renderer The rendering context. * \param texture (optional) The SDL texture to use. * \param vertices Vertices. * \param num_vertices Number of vertices. @@ -1673,6 +1689,7 @@ extern DECLSPEC int SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer, * vertex arrays Color and alpha modulation is done per vertex * (SDL_SetTextureColorMod and SDL_SetTextureAlphaMod are ignored). * + * \param renderer The rendering context. * \param texture (optional) The SDL texture to use. * \param xy Vertex positions * \param xy_stride Byte size to move from one element to the next element @@ -1704,7 +1721,8 @@ extern DECLSPEC int SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, * Read pixels from the current rendering target to an array of pixels. * * **WARNING**: This is a very slow operation, and should not be used - * frequently. + * frequently. If you're using this on the main rendering target, it should be + * called after rendering and before SDL_RenderPresent(). * * `pitch` specifies the number of bytes between rows in the destination * `pixels` data. This allows you to write to a subrectangle or have padded diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index c0d194c4a..449e6445c 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -234,6 +234,19 @@ typedef uint64_t Uint64; /* @} *//* Basic data types */ +/** + * \name Floating-point constants + */ +/* @{ */ + +#ifdef FLT_EPSILON +#define SDL_FLT_EPSILON FLT_EPSILON +#else +#define SDL_FLT_EPSILON 1.1920928955078125e-07F /* 0x0.000002p0 */ +#endif + +/* @} *//* Floating-point constants */ + /* Make sure we have macros for printing width-based integers. * should define these but this is not true all platforms. * (for example win32) */ @@ -354,8 +367,14 @@ typedef uint64_t Uint64; #endif #endif /* SDL_DISABLE_ANALYZE_MACROS */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#define SDL_COMPILE_TIME_ASSERT(name, x) _Static_assert(x, #x) +#elif defined(__cplusplus) && (__cplusplus >= 201103L) +#define SDL_COMPILE_TIME_ASSERT(name, x) static_assert(x, #x) +#else /* universal, but may trigger -Wunused-local-typedefs */ #define SDL_COMPILE_TIME_ASSERT(name, x) \ typedef int SDL_compile_time_assert_ ## name[(x) * 2 - 1] +#endif /** \cond */ #ifndef DOXYGEN_SHOULD_IGNORE_THIS SDL_COMPILE_TIME_ASSERT(uint8, sizeof(Uint8) == 1); diff --git a/include/SDL_system.h b/include/SDL_system.h index e2fa7b5fe..41563add4 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -425,6 +425,18 @@ extern DECLSPEC SDL_bool SDLCALL SDL_AndroidRequestPermission(const char *permis */ extern DECLSPEC int SDLCALL SDL_AndroidShowToast(const char* message, int duration, int gravity, int xoffset, int yoffset); +/** + * Send a user command to SDLActivity. + * + * Override "boolean onUnhandledMessage(Message msg)" to handle the message. + * + * \param command user command that must be greater or equal to 0x8000 + * \param param user parameter + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC int SDLCALL SDL_AndroidSendMessage(Uint32 command, int param); + #endif /* __ANDROID__ */ /* Platform specific functions for WinRT */ diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h index f7cd670cd..45f8e7540 100644 --- a/include/SDL_syswm.h +++ b/include/SDL_syswm.h @@ -298,6 +298,8 @@ struct SDL_SysWMinfo struct wl_egl_window *egl_window; /**< Wayland EGL window (native window) */ struct xdg_surface *xdg_surface; /**< Wayland xdg surface (window manager handle) */ struct xdg_toplevel *xdg_toplevel; /**< Wayland xdg toplevel role */ + struct xdg_popup *xdg_popup; /**< Wayland xdg popup role */ + struct xdg_positioner *xdg_positioner; /**< Wayland xdg positioner, for popup */ } wl; #endif #if defined(SDL_VIDEO_DRIVER_MIR) /* no longer available, left for API/ABI compatibility. Remove in 2.1! */ diff --git a/include/SDL_touch.h b/include/SDL_touch.h index 9b00716b2..95924135e 100644 --- a/include/SDL_touch.h +++ b/include/SDL_touch.h @@ -95,6 +95,14 @@ extern DECLSPEC int SDLCALL SDL_GetNumTouchDevices(void); */ extern DECLSPEC SDL_TouchID SDLCALL SDL_GetTouchDevice(int index); +/** + * Get the touch device name as reported from the driver or NULL if the index + * is invalid. + * + * \since This function is available since SDL 2.0.22. + */ +extern DECLSPEC const char* SDLCALL SDL_GetTouchName(int index); + /** * Get the type of the given touch device. * diff --git a/include/SDL_version.h b/include/SDL_version.h index 2716eba7b..3df4e041a 100644 --- a/include/SDL_version.h +++ b/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 20 +#define SDL_PATCHLEVEL 22 /** * Macro to determine SDL version program was compiled against. diff --git a/include/SDL_video.h b/include/SDL_video.h index 0f7f42691..7b67bc74c 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -1340,6 +1340,7 @@ extern DECLSPEC void SDLCALL SDL_SetWindowKeyboardGrab(SDL_Window * window, * Mouse grab confines the mouse cursor to the window. * * \param window The window for which the mouse grab mode should be set. + * \param grabbed This is SDL_TRUE to grab mouse, and SDL_FALSE to release. * * \since This function is available since SDL 2.0.16. * diff --git a/include/begin_code.h b/include/begin_code.h index 63f064b6f..b1b1a3a9b 100644 --- a/include/begin_code.h +++ b/include/begin_code.h @@ -107,7 +107,7 @@ #ifdef __BORLANDC__ #pragma nopackwarning #endif -#ifdef _M_X64 +#ifdef _WIN64 /* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */ #pragma pack(push,8) #else diff --git a/src/SDL.c b/src/SDL.c index 67afa67aa..68a4f5da2 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -153,8 +153,7 @@ SDL_InitSubSystem(Uint32 flags) Uint32 flags_initialized = 0; if (!SDL_MainIsReady) { - SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?"); - return -1; + return SDL_SetError("Application didn't initialize properly, did you include SDL_main.h in the file containing your main() function?"); } /* Clear the error message */ @@ -208,7 +207,7 @@ SDL_InitSubSystem(Uint32 flags) /* Initialize the timer subsystem */ if ((flags & SDL_INIT_TIMER)){ -#if !SDL_TIMERS_DISABLED +#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY if (SDL_PrivateShouldInitSubsystem(SDL_INIT_TIMER)) { if (SDL_TimerInit() < 0) { goto quit_and_error; @@ -317,6 +316,8 @@ SDL_InitSubSystem(Uint32 flags) #endif } + (void) flags_initialized; /* make static analysis happy, since this only gets used in error cases. */ + return (0); quit_and_error: @@ -402,7 +403,7 @@ SDL_QuitSubSystem(Uint32 flags) } #endif -#if !SDL_TIMERS_DISABLED +#if !SDL_TIMERS_DISABLED && !SDL_TIMER_DUMMY if ((flags & SDL_INIT_TIMER)) { if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) { SDL_TimerQuit(); diff --git a/src/SDL_hints.c b/src/SDL_hints.c index 2eea5501e..d3fc8ab46 100644 --- a/src/SDL_hints.c +++ b/src/SDL_hints.c @@ -178,6 +178,11 @@ SDL_AddHintCallback(const char *name, SDL_HintCallback callback, void *userdata) return; } hint->name = SDL_strdup(name); + if (!hint->name) { + SDL_free(hint); + SDL_OutOfMemory(); + return; + } hint->value = NULL; hint->priority = SDL_HINT_DEFAULT; hint->callbacks = NULL; diff --git a/src/SDL_list.c b/src/SDL_list.c new file mode 100644 index 000000000..af9f8bf81 --- /dev/null +++ b/src/SDL_list.c @@ -0,0 +1,93 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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" + +#include "SDL.h" +#include "./SDL_list.h" + +/* Push */ +int +SDL_ListAdd(SDL_ListNode **head, void *ent) +{ + SDL_ListNode *node = SDL_malloc(sizeof (*node)); + + if (node == NULL) { + return SDL_OutOfMemory(); + } + + node->entry = ent; + node->next = *head; + *head = node; + return 0; +} + +/* Pop from end as a FIFO (if add with SDL_ListAdd) */ +void +SDL_ListPop(SDL_ListNode **head, void **ent) +{ + SDL_ListNode **ptr = head; + + /* Invalid or empty */ + if (head == NULL || *head == NULL) { + return; + } + + while ((*ptr)->next) { + ptr = &(*ptr)->next; + } + + if (ent) { + *ent = (*ptr)->entry; + } + + SDL_free(*ptr); + *ptr = NULL; +} + +void +SDL_ListRemove(SDL_ListNode **head, void *ent) +{ + SDL_ListNode **ptr = head; + + while (*ptr) { + if ((*ptr)->entry == ent) { + SDL_ListNode *tmp = *ptr; + *ptr = (*ptr)->next; + SDL_free(tmp); + return; + } + ptr = &(*ptr)->next; + } +} + +void +SDL_ListClear(SDL_ListNode **head) +{ + SDL_ListNode *l = *head; + *head = NULL; + while (l) { + SDL_ListNode *tmp = l; + l = l->next; + SDL_free(tmp); + } +} + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/SDL_list.h b/src/SDL_list.h new file mode 100644 index 000000000..a7ead1dcd --- /dev/null +++ b/src/SDL_list.h @@ -0,0 +1,39 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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_list_h_ +#define SDL_list_h_ + +typedef struct SDL_ListNode +{ + void *entry; + struct SDL_ListNode *next; +} SDL_ListNode; + + +int SDL_ListAdd(SDL_ListNode **head, void *ent); +void SDL_ListPop(SDL_ListNode **head, void **ent); +void SDL_ListRemove(SDL_ListNode **head, void *ent); +void SDL_ListClear(SDL_ListNode **head); + +#endif /* SDL_list_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 849416c83..fb363f771 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -245,11 +245,6 @@ SDL_AudioThreadDeinit_Default(_THIS) { /* no-op. */ } -static void -SDL_AudioBeginLoopIteration_Default(_THIS) -{ /* no-op. */ -} - static void SDL_AudioWaitDevice_Default(_THIS) { /* no-op. */ @@ -277,11 +272,6 @@ SDL_AudioFlushCapture_Default(_THIS) { /* no-op. */ } -static void -SDL_AudioPrepareToClose_Default(_THIS) -{ /* no-op. */ -} - static void SDL_AudioCloseDevice_Default(_THIS) { /* no-op. */ @@ -299,7 +289,7 @@ SDL_AudioFreeDeviceHandle_Default(void *handle) static int -SDL_AudioOpenDevice_Default(_THIS, void *handle, const char *devname, int iscapture) +SDL_AudioOpenDevice_Default(_THIS, const char *devname) { return SDL_Unsupported(); } @@ -334,11 +324,6 @@ SDL_AudioUnlockDevice_Default(SDL_AudioDevice * device) } } -static void -SDL_AudioLockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device) -{ -} - static void finish_audio_entry_points_init(void) { @@ -347,14 +332,6 @@ finish_audio_entry_points_init(void) * blindly call them without having to check for validity first. */ - if (current_audio.impl.SkipMixerLock) { - if (current_audio.impl.LockDevice == NULL) { - current_audio.impl.LockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock; - } - if (current_audio.impl.UnlockDevice == NULL) { - current_audio.impl.UnlockDevice = SDL_AudioLockOrUnlockDeviceWithNoMixerLock; - } - } #define FILL_STUB(x) \ if (current_audio.impl.x == NULL) { \ @@ -364,13 +341,11 @@ finish_audio_entry_points_init(void) FILL_STUB(OpenDevice); FILL_STUB(ThreadInit); FILL_STUB(ThreadDeinit); - FILL_STUB(BeginLoopIteration); FILL_STUB(WaitDevice); FILL_STUB(PlayDevice); FILL_STUB(GetDeviceBuf); FILL_STUB(CaptureFromDevice); FILL_STUB(FlushCapture); - FILL_STUB(PrepareToClose); FILL_STUB(CloseDevice); FILL_STUB(LockDevice); FILL_STUB(UnlockDevice); @@ -429,8 +404,7 @@ add_audio_device(const char *name, SDL_AudioSpec *spec, void *handle, SDL_AudioD SDL_UnlockMutex(current_audio.detectionLock); SDL_free(item->original_name); SDL_free(item); - SDL_OutOfMemory(); - return -1; + return SDL_OutOfMemory(); } SDL_snprintf(replacement, len, "%s (%d)", name, dupenum + 1); @@ -483,7 +457,7 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount) /* The audio backends call this when a new device is plugged in. */ void -SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle) +SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle) { const int device_index = iscapture ? add_capture_device(name, spec, handle) : add_output_device(name, spec, handle); if (device_index != -1) { @@ -545,7 +519,7 @@ mark_device_removed(void *handle, SDL_AudioDeviceItem *devices, SDL_bool *remove /* The audio backends call this when a device is removed from the system. */ void -SDL_RemoveAudioDevice(const int iscapture, void *handle) +SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle) { int device_index; SDL_AudioDevice *device = NULL; @@ -723,7 +697,6 @@ SDL_RunAudio(void *devicep) /* Loop, filling the audio buffers */ while (!SDL_AtomicGet(&device->shutdown)) { - current_audio.impl.BeginLoopIteration(device); data_len = device->callbackspec.size; /* Fill the current buffer with sound */ @@ -786,8 +759,6 @@ SDL_RunAudio(void *devicep) } } - current_audio.impl.PrepareToClose(device); - /* Wait for the audio to drain. */ SDL_Delay(((device->spec.samples * 1000) / device->spec.freq) * 2); @@ -831,8 +802,6 @@ SDL_CaptureAudio(void *devicep) int still_need; Uint8 *ptr; - current_audio.impl.BeginLoopIteration(device); - if (SDL_AtomicGet(&device->paused)) { SDL_Delay(delay); /* just so we don't cook the CPU. */ if (device->stream) { @@ -956,20 +925,18 @@ SDL_GetAudioDriver(int index) int SDL_AudioInit(const char *driver_name) { - int i = 0; - int initialized = 0; - int tried_to_init = 0; + int i; + SDL_bool initialized = SDL_FALSE, tried_to_init = SDL_FALSE; if (SDL_GetCurrentAudioDriver()) { SDL_AudioQuit(); /* shutdown driver if already running. */ } - SDL_zero(current_audio); SDL_zeroa(open_devices); /* Select the proper audio driver */ if (driver_name == NULL) { - driver_name = SDL_getenv("SDL_AUDIODRIVER"); + driver_name = SDL_GetHint(SDL_HINT_AUDIODRIVER); } if (driver_name != NULL && *driver_name != 0) { @@ -990,7 +957,7 @@ SDL_AudioInit(const char *driver_name) for (i = 0; bootstrap[i]; ++i) { if ((driver_attempt_len == SDL_strlen(bootstrap[i]->name)) && (SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) { - tried_to_init = 1; + tried_to_init = SDL_TRUE; SDL_zero(current_audio); current_audio.name = bootstrap[i]->name; current_audio.desc = bootstrap[i]->desc; @@ -1007,7 +974,7 @@ SDL_AudioInit(const char *driver_name) continue; } - tried_to_init = 1; + tried_to_init = SDL_TRUE; SDL_zero(current_audio); current_audio.name = bootstrap[i]->name; current_audio.desc = bootstrap[i]->desc; @@ -1114,38 +1081,29 @@ SDL_GetNumAudioDevices(int iscapture) const char * SDL_GetAudioDeviceName(int index, int iscapture) { - const char *retval = NULL; + SDL_AudioDeviceItem *item; + int i; + const char *retval; if (!SDL_GetCurrentAudioDriver()) { SDL_SetError("Audio subsystem is not initialized"); return NULL; } - if (iscapture && !current_audio.impl.HasCaptureSupport) { - SDL_SetError("No capture support"); - return NULL; - } - - if (index >= 0) { - SDL_AudioDeviceItem *item; - int i; - - SDL_LockMutex(current_audio.detectionLock); - item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; - i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; - if (index < i) { - for (i--; i > index; i--, item = item->next) { - SDL_assert(item != NULL); - } + SDL_LockMutex(current_audio.detectionLock); + item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; + i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + if (index >= 0 && index < i) { + for (i--; i > index; i--, item = item->next) { SDL_assert(item != NULL); - retval = item->name; } - SDL_UnlockMutex(current_audio.detectionLock); - } - - if (retval == NULL) { - SDL_SetError("No such device"); + SDL_assert(item != NULL); + retval = item->name; + } else { + SDL_InvalidParamError("index"); + retval = NULL; } + SDL_UnlockMutex(current_audio.detectionLock); return retval; } @@ -1154,38 +1112,33 @@ SDL_GetAudioDeviceName(int index, int iscapture) int SDL_GetAudioDeviceSpec(int index, int iscapture, SDL_AudioSpec *spec) { + SDL_AudioDeviceItem *item; + int i, retval; + if (spec == NULL) { return SDL_InvalidParamError("spec"); } - SDL_zerop(spec); - if (!SDL_GetCurrentAudioDriver()) { return SDL_SetError("Audio subsystem is not initialized"); } - if (iscapture && !current_audio.impl.HasCaptureSupport) { - return SDL_SetError("No capture support"); - } - - if (index >= 0) { - SDL_AudioDeviceItem *item; - int i; - - SDL_LockMutex(current_audio.detectionLock); - item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; - i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; - if (index < i) { - for (i--; i > index; i--, item = item->next) { - SDL_assert(item != NULL); - } + SDL_LockMutex(current_audio.detectionLock); + item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; + i = iscapture ? current_audio.inputDeviceCount : current_audio.outputDeviceCount; + if (index >= 0 && index < i) { + for (i--; i > index; i--, item = item->next) { SDL_assert(item != NULL); - SDL_memcpy(spec, &item->spec, sizeof(SDL_AudioSpec)); } - SDL_UnlockMutex(current_audio.detectionLock); + SDL_assert(item != NULL); + SDL_memcpy(spec, &item->spec, sizeof(SDL_AudioSpec)); + retval = 0; + } else { + retval = SDL_InvalidParamError("index"); } + SDL_UnlockMutex(current_audio.detectionLock); - return 0; + return retval; } @@ -1421,7 +1374,7 @@ open_audio_device(const char *devname, int iscapture, SDL_AtomicSet(&device->enabled, 1); /* Create a mutex for locking the sound buffers */ - if (!current_audio.impl.SkipMixerLock) { + if (current_audio.impl.LockDevice == SDL_AudioLockDevice_Default) { device->mixer_lock = SDL_CreateMutex(); if (device->mixer_lock == NULL) { close_audio_device(device); @@ -1430,7 +1383,7 @@ open_audio_device(const char *devname, int iscapture, } } - if (current_audio.impl.OpenDevice(device, handle, devname, iscapture) < 0) { + if (current_audio.impl.OpenDevice(device, devname) < 0) { close_audio_device(device); return 0; } @@ -1555,8 +1508,7 @@ SDL_OpenAudio(SDL_AudioSpec * desired, SDL_AudioSpec * obtained) /* SDL_OpenAudio() is legacy and can only act on Device ID #1. */ if (open_devices[0] != NULL) { - SDL_SetError("Audio device is already opened"); - return -1; + return SDL_SetError("Audio device is already opened"); } if (obtained) { diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 31e4e224d..539900d84 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -80,7 +80,7 @@ SDL_ConvertStereoToMono_SSE3(SDL_AudioCVT * cvt, SDL_AudioFormat format) Just use unaligned load/stores, if the memory at runtime is aligned it'll be just as fast on modern processors */ while (i >= 4) { /* 4 * float32 */ - _mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_load_ps(src), _mm_loadu_ps(src+4)), divby2)); + _mm_storeu_ps(dst, _mm_mul_ps(_mm_hadd_ps(_mm_loadu_ps(src), _mm_loadu_ps(src+4)), divby2)); i -= 4; src += 8; dst += 4; } @@ -369,11 +369,11 @@ SDL_Convert71To51(SDL_AudioCVT * cvt, SDL_AudioFormat format) const float surround_left_distributed = src[6] * 0.5f; const float surround_right_distributed = src[7] * 0.5f; dst[0] = (src[0] + surround_left_distributed) * two_thirds; /* FL */ - dst[1] = (src[1] + surround_right_distributed) * two_thirds; /* FR */ + dst[1] = (src[1] + surround_right_distributed) * two_thirds; /* FR */ dst[2] = src[2] * two_thirds; /* CC */ dst[3] = src[3] * two_thirds; /* LFE */ dst[4] = (src[4] + surround_left_distributed) * two_thirds; /* BL */ - dst[5] = (src[5] + surround_right_distributed) * two_thirds; /* BR */ + dst[5] = (src[5] + surround_right_distributed) * two_thirds; /* BR */ } cvt->len_cvt /= 8; @@ -398,12 +398,12 @@ SDL_Convert71To61(SDL_AudioCVT * cvt, SDL_AudioFormat format) for (i = cvt->len_cvt / (sizeof (float) * 8); i; --i, src += 8, dst += 7) { dst[0] = src[3]; /* LFE */ - dst[1] = src[2]; /* FC */ + dst[1] = src[2]; /* FC */ dst[2] = src[1]; /* FR */ dst[3] = src[7]; /* SR */ dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */ dst[5] = src[6]; /* SL */ - dst[6] = src[0]; /* FL */ + dst[6] = src[0]; /* FL */ } cvt->len_cvt /= 8; @@ -428,13 +428,13 @@ SDL_Convert61To71(SDL_AudioCVT * cvt, SDL_AudioFormat format) for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 8) { dst[0] = src[6]; /* FL */ - dst[1] = src[2]; /* FR */ + dst[1] = src[2]; /* FR */ dst[2] = src[1]; /* FC */ dst[3] = src[0]; /* LFE */ dst[4] = src[4]; /* BL */ dst[5] = src[4]; /* BR */ - dst[6] = src[5]; /* SL */ - dst[7] = src[3]; /* SR */ + dst[6] = src[5]; /* SL */ + dst[7] = src[3]; /* SR */ } cvt->len_cvt /= 7; @@ -459,12 +459,12 @@ SDL_Convert51To61(SDL_AudioCVT * cvt, SDL_AudioFormat format) for (i = cvt->len_cvt / (sizeof (float) * 6); i; --i, src += 6, dst += 7) { dst[0] = src[3]; /* LFE */ - dst[1] = src[2]; /* FC */ + dst[1] = src[2]; /* FC */ dst[2] = src[1]; /* FR */ dst[3] = src[5]; /* SR */ dst[4] = (src[4] + src[5]) / 0.2f; /* BackSurround */ dst[5] = src[4]; /* SL */ - dst[6] = src[0]; /* FL */ + dst[6] = src[0]; /* FL */ } cvt->len_cvt /= 6; @@ -489,7 +489,7 @@ SDL_Convert61To51(SDL_AudioCVT * cvt, SDL_AudioFormat format) for (i = cvt->len_cvt / (sizeof (float) * 7); i; --i, src += 7, dst += 6) { dst[0] = src[6]; /* FL */ - dst[1] = src[2]; /* FR */ + dst[1] = src[2]; /* FR */ dst[2] = src[1]; /* FC */ dst[3] = src[0]; /* LFE */ dst[4] = src[5]; /* BL */ @@ -614,7 +614,7 @@ SDL_ConvertQuadTo51(SDL_AudioCVT * cvt, SDL_AudioFormat format) ce = (lf + rf) * 0.5f; /* Constant 0.571f is approx 4/7 not to saturate */ dst[0] = 0.571f * (lf + (lf - 0.5f * ce)); /* FL */ - dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */ + dst[1] = 0.571f * (rf + (rf - 0.5f * ce)); /* FR */ dst[2] = ce; /* FC */ dst[3] = 0; /* LFE (only meant for special LFE effects) */ dst[4] = lb; /* BL */ @@ -801,7 +801,8 @@ ResamplerPadding(const int inrate, const int outrate) { if (inrate == outrate) { return 0; - } else if (inrate > outrate) { + } + if (inrate > outrate) { return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))); } return RESAMPLER_SAMPLES_PER_ZERO_CROSSING; @@ -930,9 +931,7 @@ SDL_AddAudioCVTFilter(SDL_AudioCVT *cvt, const SDL_AudioFilter filter) if (cvt->filter_index >= SDL_AUDIOCVT_MAX_FILTERS) { return SDL_SetError("Too many filters needed for conversion, exceeded maximum of %d", SDL_AUDIOCVT_MAX_FILTERS); } - if (filter == NULL) { - return SDL_SetError("Audio filter pointer is NULL"); - } + SDL_assert(filter != NULL); cvt->filters[cvt->filter_index++] = filter; cvt->filters[cvt->filter_index] = NULL; /* Moving terminator */ return 0; @@ -943,7 +942,7 @@ SDL_BuildAudioTypeCVTToFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat src_fmt) { int retval = 0; /* 0 == no conversion necessary. */ - if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) { + if ((SDL_AUDIO_ISBIGENDIAN(src_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN) && SDL_AUDIO_BITSIZE(src_fmt) > 8) { if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { return -1; } @@ -1020,7 +1019,7 @@ SDL_BuildAudioTypeCVTFromFloat(SDL_AudioCVT *cvt, const SDL_AudioFormat dst_fmt) retval = 1; /* added a converter. */ } - if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN)) { + if ((SDL_AUDIO_ISBIGENDIAN(dst_fmt) != 0) == (SDL_BYTEORDER == SDL_LIL_ENDIAN) && SDL_AUDIO_BITSIZE(dst_fmt) > 8) { if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { return -1; } @@ -1217,19 +1216,26 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt, if (!SDL_SupportedAudioFormat(src_fmt)) { return SDL_SetError("Invalid source format"); - } else if (!SDL_SupportedAudioFormat(dst_fmt)) { + } + if (!SDL_SupportedAudioFormat(dst_fmt)) { return SDL_SetError("Invalid destination format"); - } else if (!SDL_SupportedChannelCount(src_channels)) { + } + if (!SDL_SupportedChannelCount(src_channels)) { return SDL_SetError("Invalid source channels"); - } else if (!SDL_SupportedChannelCount(dst_channels)) { + } + if (!SDL_SupportedChannelCount(dst_channels)) { return SDL_SetError("Invalid destination channels"); - } else if (src_rate <= 0) { + } + if (src_rate <= 0) { return SDL_SetError("Source rate is equal to or less than zero"); - } else if (dst_rate <= 0) { + } + if (dst_rate <= 0) { return SDL_SetError("Destination rate is equal to or less than zero"); - } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) { + } + if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) { return SDL_SetError("Source rate is too high"); - } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) { + } + if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) { return SDL_SetError("Destination rate is too high"); } @@ -1273,6 +1279,9 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt, /* just a byteswap needed? */ if ((src_fmt & ~SDL_AUDIO_MASK_ENDIAN) == (dst_fmt & ~SDL_AUDIO_MASK_ENDIAN)) { + if (SDL_AUDIO_BITSIZE(dst_fmt) == 8) { + return 0; + } if (SDL_AddAudioCVTFilter(cvt, SDL_Convert_Byteswap) < 0) { return -1; } @@ -1666,6 +1675,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format, retval = (SDL_AudioStream *) SDL_calloc(1, sizeof (SDL_AudioStream)); if (!retval) { + SDL_OutOfMemory(); return NULL; } @@ -1907,11 +1917,14 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len) if (!stream) { return SDL_InvalidParamError("stream"); - } else if (!buf) { + } + if (!buf) { return SDL_InvalidParamError("buf"); - } else if (len == 0) { + } + if (len == 0) { return 0; /* nothing to do. */ - } else if ((len % stream->src_sample_frame_size) != 0) { + } + if ((len % stream->src_sample_frame_size) != 0) { return SDL_SetError("Can't add partial sample frames"); } @@ -2017,11 +2030,14 @@ SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len) if (!stream) { return SDL_InvalidParamError("stream"); - } else if (!buf) { + } + if (!buf) { return SDL_InvalidParamError("buf"); - } else if (len <= 0) { + } + if (len <= 0) { return 0; /* nothing to do. */ - } else if ((len % stream->dst_sample_frame_size) != 0) { + } + if ((len % stream->dst_sample_frame_size) != 0) { return SDL_SetError("Can't request partial sample frames"); } @@ -2067,4 +2083,3 @@ SDL_FreeAudioStream(SDL_AudioStream *stream) } /* vi: set ts=4 sw=4 expandtab: */ - diff --git a/src/audio/SDL_mixer.c b/src/audio/SDL_mixer.c index 23adec056..9c9e5df21 100644 --- a/src/audio/SDL_mixer.c +++ b/src/audio/SDL_mixer.c @@ -29,7 +29,6 @@ /* This table is used to add two sound values together and pin * the value to avoid overflow. (used with permission from ARDI) - * Changed to use 0xFE instead of 0xFF for better sound quality. */ static const Uint8 mix8[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -66,24 +65,25 @@ static const Uint8 mix8[] = { 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, - 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* The volume ranges from 0 - 128 */ #define ADJUST_VOLUME(s, v) (s = (s*v)/SDL_MIX_MAXVOLUME) #define ADJUST_VOLUME_U8(s, v) (s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128) +#define ADJUST_VOLUME_U16(s, v) (s = (((s-32768)*v)/SDL_MIX_MAXVOLUME)+32768) void @@ -115,8 +115,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, Sint8 *dst8, *src8; Sint8 src_sample; int dst_sample; - const int max_audioval = ((1 << (8 - 1)) - 1); - const int min_audioval = -(1 << (8 - 1)); + const int max_audioval = SDL_MAX_SINT8; + const int min_audioval = SDL_MIN_SINT8; src8 = (Sint8 *) src; dst8 = (Sint8 *) dst; @@ -125,12 +125,11 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, ADJUST_VOLUME(src_sample, volume); dst_sample = *dst8 + src_sample; if (dst_sample > max_audioval) { - *dst8 = max_audioval; + dst_sample = max_audioval; } else if (dst_sample < min_audioval) { - *dst8 = min_audioval; - } else { - *dst8 = dst_sample; + dst_sample = min_audioval; } + *dst8 = dst_sample; ++dst8; ++src8; } @@ -141,14 +140,14 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, { Sint16 src1, src2; int dst_sample; - const int max_audioval = ((1 << (16 - 1)) - 1); - const int min_audioval = -(1 << (16 - 1)); + const int max_audioval = SDL_MAX_SINT16; + const int min_audioval = SDL_MIN_SINT16; len /= 2; while (len--) { - src1 = ((src[1]) << 8 | src[0]); + src1 = SDL_SwapLE16(*(Sint16 *)src); ADJUST_VOLUME(src1, volume); - src2 = ((dst[1]) << 8 | dst[0]); + src2 = SDL_SwapLE16(*(Sint16 *)dst); src += 2; dst_sample = src1 + src2; if (dst_sample > max_audioval) { @@ -156,9 +155,7 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, } else if (dst_sample < min_audioval) { dst_sample = min_audioval; } - dst[0] = dst_sample & 0xFF; - dst_sample >>= 8; - dst[1] = dst_sample & 0xFF; + *(Sint16 *)dst = SDL_SwapLE16(dst_sample); dst += 2; } } @@ -168,14 +165,14 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, { Sint16 src1, src2; int dst_sample; - const int max_audioval = ((1 << (16 - 1)) - 1); - const int min_audioval = -(1 << (16 - 1)); + const int max_audioval = SDL_MAX_SINT16; + const int min_audioval = SDL_MIN_SINT16; len /= 2; while (len--) { - src1 = ((src[0]) << 8 | src[1]); + src1 = SDL_SwapBE16(*(Sint16 *)src); ADJUST_VOLUME(src1, volume); - src2 = ((dst[0]) << 8 | dst[1]); + src2 = SDL_SwapBE16(*(Sint16 *)dst); src += 2; dst_sample = src1 + src2; if (dst_sample > max_audioval) { @@ -183,9 +180,7 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, } else if (dst_sample < min_audioval) { dst_sample = min_audioval; } - dst[1] = dst_sample & 0xFF; - dst_sample >>= 8; - dst[0] = dst_sample & 0xFF; + *(Sint16 *)dst = SDL_SwapBE16(dst_sample); dst += 2; } } @@ -195,21 +190,23 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, { Uint16 src1, src2; int dst_sample; - const int max_audioval = 0xFFFF; + const int max_audioval = SDL_MAX_SINT16; + const int min_audioval = SDL_MIN_SINT16; len /= 2; while (len--) { - src1 = ((src[1]) << 8 | src[0]); - ADJUST_VOLUME(src1, volume); - src2 = ((dst[1]) << 8 | dst[0]); + src1 = SDL_SwapLE16(*(Uint16 *)src); + ADJUST_VOLUME_U16(src1, volume); + src2 = SDL_SwapLE16(*(Uint16 *)dst); src += 2; - dst_sample = src1 + src2; + dst_sample = src1 + src2 - 32768 * 2; if (dst_sample > max_audioval) { dst_sample = max_audioval; + } else if (dst_sample < min_audioval) { + dst_sample = min_audioval; } - dst[0] = dst_sample & 0xFF; - dst_sample >>= 8; - dst[1] = dst_sample & 0xFF; + dst_sample += 32768; + *(Uint16 *)dst = SDL_SwapLE16(dst_sample); dst += 2; } } @@ -219,21 +216,23 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, { Uint16 src1, src2; int dst_sample; - const int max_audioval = 0xFFFF; + const int max_audioval = SDL_MAX_SINT16; + const int min_audioval = SDL_MIN_SINT16; len /= 2; while (len--) { - src1 = ((src[0]) << 8 | src[1]); - ADJUST_VOLUME(src1, volume); - src2 = ((dst[0]) << 8 | dst[1]); + src1 = SDL_SwapBE16(*(Uint16 *)src); + ADJUST_VOLUME_U16(src1, volume); + src2 = SDL_SwapBE16(*(Uint16 *)dst); src += 2; - dst_sample = src1 + src2; + dst_sample = src1 + src2 - 32768 * 2; if (dst_sample > max_audioval) { dst_sample = max_audioval; + } else if (dst_sample < min_audioval) { + dst_sample = min_audioval; } - dst[1] = dst_sample & 0xFF; - dst_sample >>= 8; - dst[0] = dst_sample & 0xFF; + dst_sample += 32768; + *(Uint16 *)dst = SDL_SwapBE16(dst_sample); dst += 2; } } @@ -245,8 +244,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, Uint32 *dst32 = (Uint32 *) dst; Sint64 src1, src2; Sint64 dst_sample; - const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1); - const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1)); + const Sint64 max_audioval = SDL_MAX_SINT32; + const Sint64 min_audioval = SDL_MIN_SINT32; len /= 4; while (len--) { @@ -271,8 +270,8 @@ SDL_MixAudioFormat(Uint8 * dst, const Uint8 * src, SDL_AudioFormat format, Uint32 *dst32 = (Uint32 *) dst; Sint64 src1, src2; Sint64 dst_sample; - const Sint64 max_audioval = ((((Sint64) 1) << (32 - 1)) - 1); - const Sint64 min_audioval = -(((Sint64) 1) << (32 - 1)); + const Sint64 max_audioval = SDL_MAX_SINT32; + const Sint64 min_audioval = SDL_MIN_SINT32; len /= 4; while (len--) { diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 6c602f07b..8aa729817 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -39,11 +39,11 @@ typedef struct SDL_AudioDevice SDL_AudioDevice; /* Audio targets should call this as devices are added to the system (such as a USB headset being plugged in), and should also be called for for every device found during DetectDevices(). */ -extern void SDL_AddAudioDevice(const int iscapture, const char *name, SDL_AudioSpec *spec, void *handle); +extern void SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle); /* Audio targets should call this as devices are removed, so SDL can update its list of available devices. */ -extern void SDL_RemoveAudioDevice(const int iscapture, void *handle); +extern void SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle); /* Audio targets should call this if an opened audio device is lost while being used. This can happen due to i/o errors, or a device being unplugged, @@ -65,16 +65,14 @@ extern void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device); typedef struct SDL_AudioDriverImpl { void (*DetectDevices) (void); - int (*OpenDevice) (_THIS, void *handle, const char *devname, int iscapture); + int (*OpenDevice) (_THIS, const char *devname); void (*ThreadInit) (_THIS); /* Called by audio thread at start */ void (*ThreadDeinit) (_THIS); /* Called by audio thread at end */ - void (*BeginLoopIteration)(_THIS); /* Called by audio thread at top of loop */ void (*WaitDevice) (_THIS); void (*PlayDevice) (_THIS); Uint8 *(*GetDeviceBuf) (_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); @@ -84,13 +82,11 @@ typedef struct SDL_AudioDriverImpl /* !!! FIXME: add pause(), so we can optimize instead of mixing silence. */ /* Some flags to push duplicate code into the core and reduce #ifdefs. */ - /* !!! FIXME: these should be SDL_bool */ - int ProvidesOwnCallbackThread; - int SkipMixerLock; - int HasCaptureSupport; - int OnlyHasDefaultOutputDevice; - int OnlyHasDefaultCaptureDevice; - int AllowsArbitraryDeviceNames; + SDL_bool ProvidesOwnCallbackThread; + SDL_bool HasCaptureSupport; + SDL_bool OnlyHasDefaultOutputDevice; + SDL_bool OnlyHasDefaultCaptureDevice; + SDL_bool AllowsArbitraryDeviceNames; } SDL_AudioDriverImpl; @@ -178,8 +174,8 @@ typedef struct AudioBootStrap { const char *name; const char *desc; - int (*init) (SDL_AudioDriverImpl * impl); - int demand_only; /* 1==request explicitly, or it won't be available. */ + SDL_bool (*init) (SDL_AudioDriverImpl * impl); + SDL_bool demand_only; /* 1==request explicitly, or it won't be available. */ } AudioBootStrap; /* Not all of these are available in a given build. Use #ifdefs, etc. */ diff --git a/src/audio/SDL_wave.c b/src/audio/SDL_wave.c index 07eb10147..e49b55068 100644 --- a/src/audio/SDL_wave.c +++ b/src/audio/SDL_wave.c @@ -685,7 +685,7 @@ MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len) state.output.pos = 0; state.output.size = outputsize / sizeof(Sint16); - state.output.data = (Sint16 *)SDL_malloc(outputsize); + state.output.data = (Sint16 *)SDL_calloc(1, outputsize); if (state.output.data == NULL) { return SDL_OutOfMemory(); } diff --git a/src/audio/aaudio/SDL_aaudio.c b/src/audio/aaudio/SDL_aaudio.c index 4e728b5c1..1d1553ba7 100644 --- a/src/audio/aaudio/SDL_aaudio.c +++ b/src/audio/aaudio/SDL_aaudio.c @@ -71,9 +71,10 @@ void aaudio_errorCallback( AAudioStream *stream, void *userData, aaudio_result_t #define LIB_AAUDIO_SO "libaaudio.so" static int -aaudio_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +aaudio_OpenDevice(_THIS, const char *devname) { struct SDL_PrivateAudioData *private; + SDL_bool iscapture = this->iscapture; aaudio_result_t res; LOGI(__func__); @@ -268,7 +269,7 @@ aaudio_Deinitialize(void) LOGI("End AAUDIO %s", SDL_GetError()); } -static int +static SDL_bool aaudio_Init(SDL_AudioDriverImpl *impl) { aaudio_result_t res; @@ -280,7 +281,7 @@ aaudio_Init(SDL_AudioDriverImpl *impl) * See https://github.com/google/oboe/issues/40 for more information. */ if (SDL_GetAndroidSDKVersion() < 27) { - return 0; + return SDL_FALSE; } SDL_zero(ctx); @@ -315,12 +316,12 @@ aaudio_Init(SDL_AudioDriverImpl *impl) /* and the capabilities */ impl->HasCaptureSupport = SDL_TRUE; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; /* this audio target is available. */ LOGI("SDL aaudio_Init OK"); - return 1; + return SDL_TRUE; failure: if (ctx.handle) { @@ -331,11 +332,11 @@ aaudio_Init(SDL_AudioDriverImpl *impl) } ctx.handle = NULL; ctx.builder = NULL; - return 0; + return SDL_FALSE; } AudioBootStrap aaudio_bootstrap = { - "AAudio", "AAudio audio driver", aaudio_Init, 0 + "AAudio", "AAudio audio driver", aaudio_Init, SDL_FALSE }; /* Pause (block) all non already paused audio devices by taking their mixer lock */ diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 78a491eda..3f990a2a0 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/src/audio/alsa/SDL_alsa_audio.c @@ -543,9 +543,10 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params) } static int -ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +ALSA_OpenDevice(_THIS, const char *devname) { int status = 0; + SDL_bool iscapture = this->iscapture; snd_pcm_t *pcm_handle = NULL; snd_pcm_hw_params_t *hwparams = NULL; snd_pcm_sw_params_t *swparams = NULL; @@ -569,7 +570,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Open the audio device */ /* Name of device should depend on # channels in spec */ status = ALSA_snd_pcm_open(&pcm_handle, - get_audio_device(handle, this->spec.channels), + get_audio_device(this->handle, this->spec.channels), iscapture ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); @@ -597,10 +598,7 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Try for a closest match on audio format */ - status = -1; - for (test_format = SDL_FirstAudioFormat(this->spec.format); - test_format && (status < 0);) { - status = 0; /* if we can't support a format, it'll become -1. */ + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { switch (test_format) { case AUDIO_U8: format = SND_PCM_FORMAT_U8; @@ -633,19 +631,14 @@ ALSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) format = SND_PCM_FORMAT_FLOAT_BE; break; default: - status = -1; - break; - } - if (status >= 0) { - status = ALSA_snd_pcm_hw_params_set_format(pcm_handle, - hwparams, format); + continue; } - if (status < 0) { - test_format = SDL_NextAudioFormat(); + if (ALSA_snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) >= 0) { + break; } } - if (status < 0) { - return SDL_SetError("ALSA: Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "alsa"); } this->spec.format = test_format; @@ -997,11 +990,11 @@ ALSA_Deinitialize(void) UnloadALSALibrary(); } -static int +static SDL_bool ALSA_Init(SDL_AudioDriverImpl * impl) { if (LoadALSALibrary() < 0) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ @@ -1017,12 +1010,12 @@ ALSA_Init(SDL_AudioDriverImpl * impl) impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap ALSA_bootstrap = { - "alsa", "ALSA PCM audio", ALSA_Init, 0 + "alsa", "ALSA PCM audio", ALSA_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_ALSA */ diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 3efa2d630..aa0d44242 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -36,9 +36,10 @@ static SDL_AudioDevice* audioDevice = NULL; static SDL_AudioDevice* captureDevice = NULL; static int -ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +ANDROIDAUDIO_OpenDevice(_THIS, const char *devname) { SDL_AudioFormat test_format; + SDL_bool iscapture = this->iscapture; SDL_assert((captureDevice == NULL) || !iscapture); SDL_assert((audioDevice == NULL) || iscapture); @@ -54,20 +55,18 @@ ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_OutOfMemory(); } - test_format = SDL_FirstAudioFormat(this->spec.format); - while (test_format != 0) { /* no "UNKNOWN" constant */ + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16) || (test_format == AUDIO_F32)) { this->spec.format = test_format; break; } - test_format = SDL_NextAudioFormat(); } - if (test_format == 0) { + if (!test_format) { /* Didn't find a compatible format :( */ - return SDL_SetError("No compatible audio format!"); + return SDL_SetError("%s: Unsupported audio format", "android"); } if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) { @@ -120,7 +119,7 @@ ANDROIDAUDIO_CloseDevice(_THIS) SDL_free(this->hidden); } -static int +static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -133,14 +132,14 @@ ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl) /* and the capabilities */ impl->HasCaptureSupport = SDL_TRUE; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap ANDROIDAUDIO_bootstrap = { - "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0 + "android", "SDL Android audio driver", ANDROIDAUDIO_Init, SDL_FALSE }; /* Pause (block) all non already paused audio devices by taking their mixer lock */ diff --git a/src/audio/arts/SDL_artsaudio.c b/src/audio/arts/SDL_artsaudio.c index 040d93669..ce74b7d4d 100644 --- a/src/audio/arts/SDL_artsaudio.c +++ b/src/audio/arts/SDL_artsaudio.c @@ -216,11 +216,11 @@ ARTS_Suspend(void) } static int -ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +ARTS_OpenDevice(_THIS, const char *devname) { int rc = 0; - int bits = 0, frag_spec = 0; - SDL_AudioFormat test_format = 0, format = 0; + int bits, frag_spec = 0; + SDL_AudioFormat test_format = 0; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -231,32 +231,24 @@ ARTS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_zerop(this->hidden); /* Try for a closest match on audio format */ - for (test_format = SDL_FirstAudioFormat(this->spec.format); - !format && test_format;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); #endif switch (test_format) { case AUDIO_U8: - bits = 8; - format = 1; - break; case AUDIO_S16LSB: - bits = 16; - format = 1; break; default: - format = 0; - break; - } - if (!format) { - test_format = SDL_NextAudioFormat(); + continue; } + break; } - if (format == 0) { - return SDL_SetError("Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "arts"); } this->spec.format = test_format; + bits = SDL_AUDIO_BITSIZE(test_format); if ((rc = SDL_NAME(arts_init) ()) != 0) { return SDL_SetError("Unable to initialize ARTS: %s", @@ -320,16 +312,16 @@ ARTS_Deinitialize(void) } -static int +static SDL_bool ARTS_Init(SDL_AudioDriverImpl * impl) { if (LoadARTSLibrary() < 0) { - return 0; + return SDL_FALSE; } else { if (SDL_NAME(arts_init) () != 0) { UnloadARTSLibrary(); SDL_SetError("ARTS: arts_init failed (no audio server?)"); - return 0; + return SDL_FALSE; } /* Play a stream so aRts doesn't crash */ @@ -350,14 +342,14 @@ ARTS_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = ARTS_GetDeviceBuf; impl->CloseDevice = ARTS_CloseDevice; impl->Deinitialize = ARTS_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap ARTS_bootstrap = { - "arts", "Analog RealTime Synthesizer", ARTS_Init, 0 + "arts", "Analog RealTime Synthesizer", ARTS_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_ARTS */ diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m index 67d838fdd..304599fff 100644 --- a/src/audio/coreaudio/SDL_coreaudio.m +++ b/src/audio/coreaudio/SDL_coreaudio.m @@ -741,8 +741,10 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec #if MACOSX_COREAUDIO static int -prepare_device(_THIS, void *handle, int iscapture) +prepare_device(_THIS) { + void *handle = this->handle; + SDL_bool iscapture = this->iscapture; AudioDeviceID devid = (AudioDeviceID) ((size_t) handle); OSStatus result = noErr; UInt32 size = 0; @@ -983,7 +985,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open, SDL_bool allow_playandrec and quits (flagging the audioqueue for shutdown), or toggles to some other system output device (in which case we'll try again). */ const AudioDeviceID prev_devid = this->hidden->deviceID; - if (prepare_device(this, this->handle, this->iscapture) && (prev_devid != this->hidden->deviceID)) { + if (prepare_device(this) && (prev_devid != this->hidden->deviceID)) { AudioQueueStop(this->hidden->audioQueue, 1); if (assign_device_to_audioqueue(this)) { int i; @@ -1015,11 +1017,11 @@ output device (in which case we'll try again). */ } static int -COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +COREAUDIO_OpenDevice(_THIS, const char *devname) { AudioStreamBasicDescription *strdesc; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - int valid_datatype = 0; + SDL_AudioFormat test_format; + SDL_bool iscapture = this->iscapture; SDL_AudioDevice **new_open_devices; /* Initialize all variables that we clean on shutdown */ @@ -1076,8 +1078,7 @@ output device (in which case we'll try again). */ strdesc->mSampleRate = this->spec.freq; strdesc->mFramesPerPacket = 1; - while ((!valid_datatype) && (test_format)) { - this->spec.format = test_format; + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { /* CoreAudio handles most of SDL's formats natively, but not U16, apparently. */ switch (test_format) { case AUDIO_U8: @@ -1088,32 +1089,32 @@ output device (in which case we'll try again). */ 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; default: - test_format = SDL_NextAudioFormat(); - break; + continue; } + break; } - if (!valid_datatype) { /* shouldn't happen, but just in case... */ - return SDL_SetError("Unsupported audio format"); + if (!test_format) { /* shouldn't happen, but just in case... */ + return SDL_SetError("%s: Unsupported audio format", "coreaudio"); } + this->spec.format = test_format; + strdesc->mBitsPerChannel = SDL_AUDIO_BITSIZE(test_format); + if (SDL_AUDIO_ISBIGENDIAN(test_format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; + + if (SDL_AUDIO_ISFLOAT(test_format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsFloat; + else if (SDL_AUDIO_ISSIGNED(test_format)) + strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; strdesc->mBytesPerFrame = strdesc->mChannelsPerFrame * strdesc->mBitsPerChannel / 8; strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket; #if MACOSX_COREAUDIO - if (!prepare_device(this, handle, iscapture)) { + if (!prepare_device(this)) { return -1; } #endif @@ -1135,8 +1136,7 @@ output device (in which case we'll try again). */ 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 SDL_SetError("%s", this->hidden->thread_error); } return (this->hidden->thread != NULL) ? 0 : -1; @@ -1152,7 +1152,7 @@ output device (in which case we'll try again). */ #endif } -static int +static SDL_bool COREAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -1164,18 +1164,18 @@ output device (in which case we'll try again). */ impl->DetectDevices = COREAUDIO_DetectDevices; AudioObjectAddPropertyListener(kAudioObjectSystemObject, &devlist_address, device_list_changed, NULL); #else - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; #endif - impl->ProvidesOwnCallbackThread = 1; - impl->HasCaptureSupport = 1; + impl->ProvidesOwnCallbackThread = SDL_TRUE; + impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap COREAUDIO_bootstrap = { - "coreaudio", "CoreAudio", COREAUDIO_Init, 0 + "coreaudio", "CoreAudio", COREAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_COREAUDIO */ diff --git a/src/audio/directsound/SDL_directsound.c b/src/audio/directsound/SDL_directsound.c index b4e8ce252..0242b139d 100644 --- a/src/audio/directsound/SDL_directsound.c +++ b/src/audio/directsound/SDL_directsound.c @@ -98,10 +98,8 @@ DSOUND_Load(void) static int SetDSerror(const char *function, int code) { - static const char *error; - static char errbuf[1024]; + const char *error; - errbuf[0] = 0; switch (code) { case E_NOINTERFACE: error = "Unsupported interface -- Is DirectX 8.0 or later installed?"; @@ -137,15 +135,11 @@ SetDSerror(const char *function, int code) error = "Function not supported"; break; default: - SDL_snprintf(errbuf, SDL_arraysize(errbuf), - "%s: Unknown DirectSound error: 0x%x", function, code); + error = "Unknown DirectSound error"; break; } - if (!errbuf[0]) { - SDL_snprintf(errbuf, SDL_arraysize(errbuf), "%s: %s", function, - error); - } - return SDL_SetError("%s", errbuf); + + return SDL_SetError("%s: %s (0x%x)", function, error, code); } static void @@ -473,14 +467,14 @@ CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt) } static int -DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DSOUND_OpenDevice(_THIS, const char *devname) { 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; + SDL_bool iscapture = this->iscapture; + SDL_AudioFormat test_format; + LPGUID guid = (LPGUID) this->handle; DWORD bufsize; /* Initialize all variables that we clean on shutdown */ @@ -510,7 +504,7 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } } - while ((!valid_format) && (test_format)) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { switch (test_format) { case AUDIO_U8: case AUDIO_S16: @@ -547,19 +541,21 @@ DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt); if (rc == 0) { this->hidden->num_buffers = numchunks; - valid_format = SDL_TRUE; + break; } } - break; + continue; + default: + continue; } - test_format = SDL_NextAudioFormat(); + break; } - if (!valid_format) { + if (!test_format) { if (tried_format) { return -1; /* CreateSecondary() should have called SDL_SetError(). */ } - return SDL_SetError("DirectSound: Unsupported audio format"); + return SDL_SetError("%s: Unsupported audio format", "directsound"); } /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */ @@ -575,11 +571,11 @@ DSOUND_Deinitialize(void) } -static int +static SDL_bool DSOUND_Init(SDL_AudioDriverImpl * impl) { if (!DSOUND_Load()) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ @@ -596,11 +592,11 @@ DSOUND_Init(SDL_AudioDriverImpl * impl) impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap DSOUND_bootstrap = { - "directsound", "DirectSound", DSOUND_Init, 0 + "directsound", "DirectSound", DSOUND_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_DSOUND */ diff --git a/src/audio/disk/SDL_diskaudio.c b/src/audio/disk/SDL_diskaudio.c index 56dfca503..f1edf503e 100644 --- a/src/audio/disk/SDL_diskaudio.c +++ b/src/audio/disk/SDL_diskaudio.c @@ -114,7 +114,7 @@ DISKAUDIO_CloseDevice(_THIS) static const char * -get_filename(const int iscapture, const char *devname) +get_filename(const SDL_bool iscapture, const char *devname) { if (devname == NULL) { devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE); @@ -126,9 +126,11 @@ get_filename(const int iscapture, const char *devname) } static int -DISKAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DISKAUDIO_OpenDevice(_THIS, const char *devname) { + void *handle = _this->handle; /* handle != NULL means "user specified the placeholder name on the fake detected device list" */ + SDL_bool iscapture = _this->iscapture; const char *fname = get_filename(iscapture, handle ? NULL : devname); const char *envr = SDL_getenv(DISKENVR_IODELAY); @@ -177,7 +179,7 @@ DISKAUDIO_DetectDevices(void) SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2); } -static int +static SDL_bool DISKAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -191,14 +193,14 @@ DISKAUDIO_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = DISKAUDIO_CloseDevice; impl->DetectDevices = DISKAUDIO_DetectDevices; - impl->AllowsArbitraryDeviceNames = 1; + impl->AllowsArbitraryDeviceNames = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap DISKAUDIO_bootstrap = { - "disk", "direct-to-disk audio", DISKAUDIO_Init, 1 + "disk", "direct-to-disk audio", DISKAUDIO_Init, SDL_TRUE }; #endif /* SDL_AUDIO_DRIVER_DISK */ diff --git a/src/audio/dsp/SDL_dspaudio.c b/src/audio/dsp/SDL_dspaudio.c index 3c4b6aaf2..531612a29 100644 --- a/src/audio/dsp/SDL_dspaudio.c +++ b/src/audio/dsp/SDL_dspaudio.c @@ -68,8 +68,9 @@ DSP_CloseDevice(_THIS) static int -DSP_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DSP_OpenDevice(_THIS, const char *devname) { + SDL_bool iscapture = this->iscapture; const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); int format; int value; @@ -301,13 +302,14 @@ look_for_devices_test(int fd) return 0; } -static int +static SDL_bool DSP_Init(SDL_AudioDriverImpl * impl) { InitTimeDevicesExist = SDL_FALSE; SDL_EnumUnixAudioDevices(0, look_for_devices_test); if (!InitTimeDevicesExist) { - return 0; /* maybe try a different backend. */ + SDL_SetError("dsp: No such audio device"); + return SDL_FALSE; /* maybe try a different backend. */ } /* Set the function pointers */ @@ -319,15 +321,15 @@ DSP_Init(SDL_AudioDriverImpl * impl) impl->CaptureFromDevice = DSP_CaptureFromDevice; impl->FlushCapture = DSP_FlushCapture; - impl->AllowsArbitraryDeviceNames = 1; + impl->AllowsArbitraryDeviceNames = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap DSP_bootstrap = { - "dsp", "OSS /dev/dsp standard audio", DSP_Init, 0 + "dsp", "OSS /dev/dsp standard audio", DSP_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_OSS */ diff --git a/src/audio/dummy/SDL_dummyaudio.c b/src/audio/dummy/SDL_dummyaudio.c index e8b557a25..dab1edb59 100644 --- a/src/audio/dummy/SDL_dummyaudio.c +++ b/src/audio/dummy/SDL_dummyaudio.c @@ -28,7 +28,7 @@ #include "SDL_dummyaudio.h" static int -DUMMYAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +DUMMYAUDIO_OpenDevice(_THIS, const char *devname) { _this->hidden = (void *) 0x1; /* just something non-NULL */ return 0; /* always succeeds. */ @@ -45,22 +45,22 @@ DUMMYAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen) return buflen; } -static int +static SDL_bool DUMMYAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ impl->OpenDevice = DUMMYAUDIO_OpenDevice; impl->CaptureFromDevice = DUMMYAUDIO_CaptureFromDevice; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap DUMMYAUDIO_bootstrap = { - "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, 1 + "dummy", "SDL dummy audio driver", DUMMYAUDIO_Init, SDL_TRUE }; /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c index c85d8d0fc..722f5d0fa 100644 --- a/src/audio/emscripten/SDL_emscriptenaudio.c +++ b/src/audio/emscripten/SDL_emscriptenaudio.c @@ -32,7 +32,7 @@ static void FeedAudioDevice(_THIS, const void *buf, const int buflen) { const int framelen = (SDL_AUDIO_BITSIZE(this->spec.format) / 8) * this->spec.channels; - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var numChannels = SDL2.audio.currentOutputBuffer['numberOfChannels']; for (var c = 0; c < numChannels; ++c) { @@ -101,7 +101,7 @@ HandleCaptureProcess(_THIS) return; } - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var numChannels = SDL2.capture.currentCaptureBuffer.numberOfChannels; for (var c = 0; c < numChannels; ++c) { @@ -147,7 +147,7 @@ HandleCaptureProcess(_THIS) static void EMSCRIPTENAUDIO_CloseDevice(_THIS) { - EM_ASM_({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; if ($0) { if (SDL2.capture.silenceTimer !== undefined) { @@ -192,16 +192,16 @@ EMSCRIPTENAUDIO_CloseDevice(_THIS) } static int -EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +EMSCRIPTENAUDIO_OpenDevice(_THIS, const char *devname) { - SDL_bool valid_format = SDL_FALSE; SDL_AudioFormat test_format; + SDL_bool iscapture = this->iscapture; int result; /* based on parts of library_sdl.js */ /* create context */ - result = EM_ASM_INT({ + result = MAIN_THREAD_EM_ASM_INT({ if(typeof(Module['SDL2']) === 'undefined') { Module['SDL2'] = {}; } @@ -228,22 +228,21 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu return SDL_SetError("Web Audio API is not available!"); } - test_format = SDL_FirstAudioFormat(this->spec.format); - while ((!valid_format) && (test_format)) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { switch (test_format) { case AUDIO_F32: /* web audio only supports floats */ - this->spec.format = test_format; - - valid_format = SDL_TRUE; break; + default: + continue; } - test_format = SDL_NextAudioFormat(); + break; } - if (!valid_format) { + if (!test_format) { /* Didn't find a compatible format :( */ - return SDL_SetError("No compatible audio format!"); + return SDL_SetError("%s: Unsupported audio format", "emscripten"); } + this->spec.format = test_format; /* Initialize all variables that we clean on shutdown */ #if 0 /* !!! FIXME: currently not used. Can we move some stuff off the SDL2 namespace? --ryan. */ @@ -281,7 +280,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu feels like it's a pretty inefficient tapdance in similar ways, to be honest. */ - EM_ASM_({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; var have_microphone = function(stream) { //console.log('SDL audio capture: we have a microphone! Replacing silence callback.'); @@ -324,7 +323,7 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu }, this->spec.channels, this->spec.samples, HandleCaptureProcess, this); } else { /* setup a ScriptProcessorNode */ - EM_ASM_ARGS({ + MAIN_THREAD_EM_ASM({ var SDL2 = Module['SDL2']; SDL2.audio.scriptProcessorNode = SDL2.audioContext['createScriptProcessor']($1, 0, $0); SDL2.audio.scriptProcessorNode['onaudioprocess'] = function (e) { @@ -339,43 +338,47 @@ EMSCRIPTENAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscaptu return 0; } -static int +static void +EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock(SDL_AudioDevice * device) +{ +} + +static SDL_bool EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl) { - int available; - int capture_available; + SDL_bool available, capture_available; /* Set the function pointers */ impl->OpenDevice = EMSCRIPTENAUDIO_OpenDevice; impl->CloseDevice = EMSCRIPTENAUDIO_CloseDevice; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; /* no threads here */ - impl->SkipMixerLock = 1; - impl->ProvidesOwnCallbackThread = 1; + impl->LockDevice = impl->UnlockDevice = EMSCRIPTENAUDIO_LockOrUnlockDeviceWithNoMixerLock; + impl->ProvidesOwnCallbackThread = SDL_TRUE; /* check availability */ - available = EM_ASM_INT_V({ + available = MAIN_THREAD_EM_ASM_INT({ if (typeof(AudioContext) !== 'undefined') { - return 1; + return true; } else if (typeof(webkitAudioContext) !== 'undefined') { - return 1; + return true; } - return 0; + return false; }); if (!available) { SDL_SetError("No audio context available"); } - capture_available = available && EM_ASM_INT_V({ + capture_available = available && MAIN_THREAD_EM_ASM_INT({ if ((typeof(navigator.mediaDevices) !== 'undefined') && (typeof(navigator.mediaDevices.getUserMedia) !== 'undefined')) { - return 1; + return true; } else if (typeof(navigator.webkitGetUserMedia) !== 'undefined') { - return 1; + return true; } - return 0; + return false; }); impl->HasCaptureSupport = capture_available ? SDL_TRUE : SDL_FALSE; @@ -385,7 +388,7 @@ EMSCRIPTENAUDIO_Init(SDL_AudioDriverImpl * impl) } AudioBootStrap EMSCRIPTENAUDIO_bootstrap = { - "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, 0 + "emscripten", "SDL emscripten audio driver", EMSCRIPTENAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_EMSCRIPTEN */ diff --git a/src/audio/esd/SDL_esdaudio.c b/src/audio/esd/SDL_esdaudio.c index b0b794d7b..ccf07916c 100644 --- a/src/audio/esd/SDL_esdaudio.c +++ b/src/audio/esd/SDL_esdaudio.c @@ -208,7 +208,7 @@ get_progname(void) static int -ESD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +ESD_OpenDevice(_THIS, const char *devname) { esd_format_t format = (ESD_STREAM | ESD_PLAY); SDL_AudioFormat test_format = 0; @@ -293,11 +293,11 @@ ESD_Deinitialize(void) UnloadESDLibrary(); } -static int +static SDL_bool ESD_Init(SDL_AudioDriverImpl * impl) { if (LoadESDLibrary() < 0) { - return 0; + return SDL_FALSE; } else { int connection = 0; @@ -308,7 +308,7 @@ ESD_Init(SDL_AudioDriverImpl * impl) if (connection < 0) { UnloadESDLibrary(); SDL_SetError("ESD: esd_open_sound failed (no audio server?)"); - return 0; + return SDL_FALSE; } SDL_NAME(esd_close) (connection); } @@ -320,14 +320,14 @@ ESD_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = ESD_GetDeviceBuf; impl->CloseDevice = ESD_CloseDevice; impl->Deinitialize = ESD_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap ESD_bootstrap = { - "esd", "Enlightened Sound Daemon", ESD_Init, 0 + "esd", "Enlightened Sound Daemon", ESD_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_ESD */ diff --git a/src/audio/fusionsound/SDL_fsaudio.c b/src/audio/fusionsound/SDL_fsaudio.c index 5f24cf440..fbe684de8 100644 --- a/src/audio/fusionsound/SDL_fsaudio.c +++ b/src/audio/fusionsound/SDL_fsaudio.c @@ -174,10 +174,10 @@ SDL_FS_CloseDevice(_THIS) static int -SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +SDL_FS_OpenDevice(_THIS, const char *devname) { int bytes; - SDL_AudioFormat test_format = 0, format = 0; + SDL_AudioFormat test_format; FSSampleFormat fs_format; FSStreamDescription desc; DirectResult ret; @@ -191,45 +191,34 @@ SDL_FS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_zerop(this->hidden); /* Try for a closest match on audio format */ - for (test_format = SDL_FirstAudioFormat(this->spec.format); - !format && test_format;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); #endif switch (test_format) { case AUDIO_U8: fs_format = FSSF_U8; - bytes = 1; - format = 1; break; case AUDIO_S16SYS: fs_format = FSSF_S16; - bytes = 2; - format = 1; break; case AUDIO_S32SYS: fs_format = FSSF_S32; - bytes = 4; - format = 1; break; case AUDIO_F32SYS: fs_format = FSSF_FLOAT; - bytes = 4; - format = 1; break; default: - format = 0; - break; - } - if (!format) { - test_format = SDL_NextAudioFormat(); + continue; } + break; } - if (format == 0) { - return SDL_SetError("Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "fusionsound"); } this->spec.format = test_format; + bytes = SDL_AUDIO_BITSIZE(test_format) / 8; /* Retrieve the main sound interface. */ ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs); @@ -288,11 +277,11 @@ SDL_FS_Deinitialize(void) } -static int +static SDL_bool SDL_FS_Init(SDL_AudioDriverImpl * impl) { if (LoadFusionSoundLibrary() < 0) { - return 0; + return SDL_FALSE; } else { DirectResult ret; @@ -302,7 +291,7 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl) SDL_SetError ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)", ret); - return 0; + return SDL_FALSE; } } @@ -313,14 +302,14 @@ SDL_FS_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = SDL_FS_GetDeviceBuf; impl->CloseDevice = SDL_FS_CloseDevice; impl->Deinitialize = SDL_FS_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap FUSIONSOUND_bootstrap = { - "fusionsound", "FusionSound", SDL_FS_Init, 0 + "fusionsound", "FusionSound", SDL_FS_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_FUSIONSOUND */ diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc index 82da47827..bb6b78c1d 100644 --- a/src/audio/haiku/SDL_haikuaudio.cc +++ b/src/audio/haiku/SDL_haikuaudio.cc @@ -120,11 +120,10 @@ UnmaskSignals(sigset_t * omask) static int -HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +HAIKUAUDIO_OpenDevice(_THIS, const char *devname) { - int valid_datatype = 0; media_raw_audio_format format; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format); + SDL_AudioFormat test_format; /* Initialize all variables that we clean on shutdown */ _this->hidden = new SDL_PrivateAudioData; @@ -138,9 +137,7 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) format.byte_order = B_MEDIA_LITTLE_ENDIAN; format.frame_rate = (float) _this->spec.freq; format.channel_count = _this->spec.channels; /* !!! FIXME: support > 2? */ - while ((!valid_datatype) && (test_format)) { - valid_datatype = 1; - _this->spec.format = test_format; + for (test_format = SDL_FirstAudioFormat(_this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { switch (test_format) { case AUDIO_S8: format.format = media_raw_audio_format::B_AUDIO_CHAR; @@ -178,15 +175,15 @@ HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) break; default: - valid_datatype = 0; - test_format = SDL_NextAudioFormat(); - break; + continue; } + break; } - if (!valid_datatype) { /* shouldn't happen, but just in case... */ - return SDL_SetError("Unsupported audio format"); + if (!test_format) { /* shouldn't happen, but just in case... */ + return SDL_SetError("%s: Unsupported audio format", "haiku"); } + _this->spec.format = test_format; /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(&_this->spec); @@ -216,22 +213,22 @@ HAIKUAUDIO_Deinitialize(void) SDL_QuitBeApp(); } -static int +static SDL_bool HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Initialize the Be Application, if it's not already started */ if (SDL_InitBeApp() < 0) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ impl->OpenDevice = HAIKUAUDIO_OpenDevice; impl->CloseDevice = HAIKUAUDIO_CloseDevice; impl->Deinitialize = HAIKUAUDIO_Deinitialize; - impl->ProvidesOwnCallbackThread = 1; - impl->OnlyHasDefaultOutputDevice = 1; + impl->ProvidesOwnCallbackThread = SDL_TRUE; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } extern "C" @@ -239,7 +236,7 @@ extern "C" extern AudioBootStrap HAIKUAUDIO_bootstrap; } AudioBootStrap HAIKUAUDIO_bootstrap = { - "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0 + "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_HAIKU */ diff --git a/src/audio/jack/SDL_jackaudio.c b/src/audio/jack/SDL_jackaudio.c index 1c8aa0ba7..f6e7e0cd3 100644 --- a/src/audio/jack/SDL_jackaudio.c +++ b/src/audio/jack/SDL_jackaudio.c @@ -280,12 +280,13 @@ JACK_CloseDevice(_THIS) } static int -JACK_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +JACK_OpenDevice(_THIS, const char *devname) { /* Note that JACK uses "output" for capture devices (they output audio data to us) and "input" for playback (we input audio data to them). Likewise, SDL's playback port will be "output" (we write data out) and capture will be "input" (we read data in). */ + SDL_bool iscapture = this->iscapture; const unsigned long sysportflags = iscapture ? JackPortIsOutput : JackPortIsInput; const unsigned long sdlportflags = iscapture ? JackPortIsInput : JackPortIsOutput; const JackProcessCallback callback = iscapture ? jackProcessCaptureCallback : jackProcessPlaybackCallback; @@ -405,18 +406,18 @@ JACK_Deinitialize(void) UnloadJackLibrary(); } -static int +static SDL_bool JACK_Init(SDL_AudioDriverImpl * impl) { if (LoadJackLibrary() < 0) { - return 0; + return SDL_FALSE; } else { /* Make sure a JACK server is running and available. */ jack_status_t status; jack_client_t *client = JACK_jack_client_open("SDL", JackNoStartServer, &status, NULL); if (client == NULL) { UnloadJackLibrary(); - return 0; + return SDL_FALSE; } JACK_jack_client_close(client); } @@ -433,11 +434,11 @@ JACK_Init(SDL_AudioDriverImpl * impl) impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap JACK_bootstrap = { - "jack", "JACK Audio Connection Kit", JACK_Init, 0 + "jack", "JACK Audio Connection Kit", JACK_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_JACK */ diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c index c651cfc6c..bf48165f5 100644 --- a/src/audio/nacl/SDL_naclaudio.c +++ b/src/audio/nacl/SDL_naclaudio.c @@ -99,7 +99,7 @@ static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) { } static int -NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { +NACLAUDIO_OpenDevice(_THIS, const char *devname) { PP_Instance instance = PSGetInstanceId(); const PPB_Audio *ppb_audio = PSInterfaceAudio(); const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig(); @@ -133,18 +133,18 @@ NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) { return 0; } -static int +static SDL_bool NACLAUDIO_Init(SDL_AudioDriverImpl * impl) { if (PSGetInstanceId() == 0) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ impl->OpenDevice = NACLAUDIO_OpenDevice; impl->CloseDevice = NACLAUDIO_CloseDevice; - impl->OnlyHasDefaultOutputDevice = 1; - impl->ProvidesOwnCallbackThread = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->ProvidesOwnCallbackThread = SDL_TRUE; /* * impl->WaitDevice = NACLAUDIO_WaitDevice; * impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf; @@ -152,12 +152,12 @@ NACLAUDIO_Init(SDL_AudioDriverImpl * impl) * impl->Deinitialize = NACLAUDIO_Deinitialize; */ - return 1; + return SDL_TRUE; } AudioBootStrap NACLAUDIO_bootstrap = { NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver", - NACLAUDIO_Init, 0 + NACLAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_NACL */ diff --git a/src/audio/nas/SDL_nasaudio.c b/src/audio/nas/SDL_nasaudio.c index 87cda5e88..d6d863232 100644 --- a/src/audio/nas/SDL_nasaudio.c +++ b/src/audio/nas/SDL_nasaudio.c @@ -237,26 +237,6 @@ NAS_CloseDevice(_THIS) SDL_free(this->hidden); } -static unsigned char -sdlformat_to_auformat(unsigned int fmt) -{ - switch (fmt) { - case AUDIO_U8: - return AuFormatLinearUnsigned8; - case AUDIO_S8: - return AuFormatLinearSigned8; - case AUDIO_U16LSB: - return AuFormatLinearUnsigned16LSB; - case AUDIO_U16MSB: - return AuFormatLinearUnsigned16MSB; - case AUDIO_S16LSB: - return AuFormatLinearSigned16LSB; - case AUDIO_S16MSB: - return AuFormatLinearSigned16MSB; - } - return AuNone; -} - static AuBool event_handler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * hnd) { @@ -331,11 +311,12 @@ find_device(_THIS) } static int -NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +NAS_OpenDevice(_THIS, const char *devname) { AuElement elms[3]; int buffer_size; - SDL_AudioFormat test_format, format; + SDL_bool iscapture = this->iscapture; + SDL_AudioFormat test_format, format = 0; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -346,16 +327,33 @@ NAS_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) SDL_zerop(this->hidden); /* Try for a closest match on audio format */ - format = 0; - for (test_format = SDL_FirstAudioFormat(this->spec.format); - !format && test_format;) { - format = sdlformat_to_auformat(test_format); - if (format == AuNone) { - test_format = SDL_NextAudioFormat(); + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + switch (test_format) { + case AUDIO_U8: + format = AuFormatLinearUnsigned8; + break; + case AUDIO_S8: + format = AuFormatLinearSigned8; + break; + case AUDIO_U16LSB: + format = AuFormatLinearUnsigned16LSB; + break; + case AUDIO_U16MSB: + format = AuFormatLinearUnsigned16MSB; + break; + case AUDIO_S16LSB: + format = AuFormatLinearSigned16LSB; + break; + case AUDIO_S16MSB: + format = AuFormatLinearSigned16MSB; + break; + default: + continue; } + break; } - if (format == 0) { - return SDL_SetError("NAS: Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "nas"); } this->spec.format = test_format; @@ -423,16 +421,16 @@ NAS_Deinitialize(void) UnloadNASLibrary(); } -static int +static SDL_bool NAS_Init(SDL_AudioDriverImpl * impl) { if (LoadNASLibrary() < 0) { - return 0; + return SDL_FALSE; } else { AuServer *aud = NAS_AuOpenServer("", 0, NULL, 0, NULL, NULL); if (aud == NULL) { SDL_SetError("NAS: AuOpenServer() failed (no audio server?)"); - return 0; + return SDL_FALSE; } NAS_AuCloseServer(aud); } @@ -447,15 +445,15 @@ NAS_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = NAS_CloseDevice; impl->Deinitialize = NAS_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap NAS_bootstrap = { - "nas", "Network Audio System", NAS_Init, 0 + "nas", "Network Audio System", NAS_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_NAS */ diff --git a/src/audio/netbsd/SDL_netbsdaudio.c b/src/audio/netbsd/SDL_netbsdaudio.c index b061ce7f1..6ff81578a 100644 --- a/src/audio/netbsd/SDL_netbsdaudio.c +++ b/src/audio/netbsd/SDL_netbsdaudio.c @@ -202,9 +202,11 @@ NETBSDAUDIO_CloseDevice(_THIS) } static int -NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +NETBSDAUDIO_OpenDevice(_THIS, const char *devname) { - SDL_AudioFormat format = 0; + SDL_bool iscapture = this->iscapture; + SDL_AudioFormat test_format; + int encoding = AUDIO_ENCODING_NONE; audio_info_t info, hwinfo; struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play; @@ -244,54 +246,46 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } #endif - prinfo->encoding = AUDIO_ENCODING_NONE; prinfo->sample_rate = this->spec.freq; prinfo->channels = this->spec.channels; - for (format = SDL_FirstAudioFormat(this->spec.format); format;) { - switch (format) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + switch (test_format) { case AUDIO_U8: - prinfo->encoding = AUDIO_ENCODING_ULINEAR; - prinfo->precision = 8; + encoding = AUDIO_ENCODING_ULINEAR; break; case AUDIO_S8: - prinfo->encoding = AUDIO_ENCODING_SLINEAR; - prinfo->precision = 8; + encoding = AUDIO_ENCODING_SLINEAR; break; case AUDIO_S16LSB: - prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; - prinfo->precision = 16; + encoding = AUDIO_ENCODING_SLINEAR_LE; break; case AUDIO_S16MSB: - prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; - prinfo->precision = 16; + encoding = AUDIO_ENCODING_SLINEAR_BE; break; case AUDIO_U16LSB: - prinfo->encoding = AUDIO_ENCODING_ULINEAR_LE; - prinfo->precision = 16; + encoding = AUDIO_ENCODING_ULINEAR_LE; break; case AUDIO_U16MSB: - prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE; - prinfo->precision = 16; + encoding = AUDIO_ENCODING_ULINEAR_BE; break; case AUDIO_S32LSB: - prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; - prinfo->precision = 32; + encoding = AUDIO_ENCODING_SLINEAR_LE; break; case AUDIO_S32MSB: - prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; - prinfo->precision = 32; + encoding = AUDIO_ENCODING_SLINEAR_BE; break; + default: + continue; } - if (prinfo->encoding != AUDIO_ENCODING_NONE) { - break; - } - format = SDL_NextAudioFormat(); + break; } - if (prinfo->encoding == AUDIO_ENCODING_NONE) { - return SDL_SetError("No supported encoding for 0x%x", this->spec.format); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "netbsd"); } + prinfo->encoding = encoding; + prinfo->precision = SDL_AUDIO_BITSIZE(test_format); info.hiwat = 5; info.lowat = 3; @@ -304,7 +298,7 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Final spec used for the device. */ - this->spec.format = format; + this->spec.format = test_format; this->spec.freq = prinfo->sample_rate; this->spec.channels = prinfo->channels; @@ -326,7 +320,7 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; } -static int +static SDL_bool NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -339,14 +333,14 @@ NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl) impl->FlushCapture = NETBSDAUDIO_FlushCapture; impl->HasCaptureSupport = SDL_TRUE; - impl->AllowsArbitraryDeviceNames = 1; + impl->AllowsArbitraryDeviceNames = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap NETBSDAUDIO_bootstrap = { - "netbsd", "NetBSD audio", NETBSDAUDIO_Init, 0 + "netbsd", "NetBSD audio", NETBSDAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_NETBSD */ diff --git a/src/audio/openslES/SDL_openslES.c b/src/audio/openslES/SDL_openslES.c index ad0209037..39d64b2b6 100644 --- a/src/audio/openslES/SDL_openslES.c +++ b/src/audio/openslES/SDL_openslES.c @@ -407,6 +407,7 @@ openslES_CreatePCMPlayer(_THIS) { struct SDL_PrivateAudioData *audiodata = this->hidden; SLDataFormat_PCM format_pcm; + SLAndroidDataFormat_PCM_EX format_pcm_ex; SLresult result; int i; @@ -414,31 +415,30 @@ openslES_CreatePCMPlayer(_THIS) it can be done as described here: https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point */ -#if 1 - /* Just go with signed 16-bit audio as it's the most compatible */ - this->spec.format = AUDIO_S16SYS; -#else - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - while (test_format != 0) { - if (SDL_AUDIO_ISSIGNED(test_format) && SDL_AUDIO_ISINT(test_format)) { - break; + if(SDL_GetAndroidSDKVersion() >= 21) { + SDL_AudioFormat test_format; + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + if (SDL_AUDIO_ISSIGNED(test_format)) { + break; + } } - test_format = SDL_NextAudioFormat(); - } - if (test_format == 0) { - /* Didn't find a compatible format : */ - LOGI( "No compatible audio format, using signed 16-bit audio" ); - test_format = AUDIO_S16SYS; + if (!test_format) { + /* Didn't find a compatible format : */ + LOGI( "No compatible audio format, using signed 16-bit audio" ); + test_format = AUDIO_S16SYS; + } + this->spec.format = test_format; + } else { + /* Just go with signed 16-bit audio as it's the most compatible */ + this->spec.format = AUDIO_S16SYS; } - this->spec.format = test_format; -#endif /* Update the fragment size as size in bytes */ SDL_CalculateAudioSpec(&this->spec); - LOGI("Try to open %u hz %u bit chan %u %s samples %u", - this->spec.freq, SDL_AUDIO_BITSIZE(this->spec.format), + LOGI("Try to open %u hz %s %u bit chan %u %s samples %u", + this->spec.freq, SDL_AUDIO_ISFLOAT(this->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(this->spec.format), this->spec.channels, (this->spec.format & 0x1000) ? "BE" : "LE", this->spec.samples); /* configure audio source */ @@ -489,7 +489,19 @@ openslES_CreatePCMPlayer(_THIS) break; } - SLDataSource audioSrc = { &loc_bufq, &format_pcm }; + if(SDL_AUDIO_ISFLOAT(this->spec.format)) { + /* Copy all setup into PCM EX structure */ + format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + format_pcm_ex.endianness = format_pcm.endianness; + format_pcm_ex.channelMask = format_pcm.channelMask; + format_pcm_ex.numChannels = format_pcm.numChannels; + format_pcm_ex.sampleRate = format_pcm.samplesPerSec; + format_pcm_ex.bitsPerSample = format_pcm.bitsPerSample; + format_pcm_ex.containerSize = format_pcm.containerSize; + format_pcm_ex.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; + } + + SLDataSource audioSrc = { &loc_bufq, SDL_AUDIO_ISFLOAT(this->spec.format) ? (void*)&format_pcm_ex : (void*)&format_pcm }; /* configure audio sink */ SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject }; @@ -583,14 +595,14 @@ openslES_CreatePCMPlayer(_THIS) } static int -openslES_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +openslES_OpenDevice(_THIS, const char *devname) { this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); } - if (iscapture) { + if (this->iscapture) { LOGI("openslES_OpenDevice() %s for capture", devname); return openslES_CreatePCMRecorder(this); } else { @@ -714,13 +726,13 @@ openslES_CloseDevice(_THIS) SDL_free(this->hidden); } -static int +static SDL_bool openslES_Init(SDL_AudioDriverImpl * impl) { LOGI("openslES_Init() called"); if (!openslES_CreateEngine()) { - return 0; + return SDL_FALSE; } LOGI("openslES_Init() - set pointers"); @@ -736,18 +748,18 @@ openslES_Init(SDL_AudioDriverImpl * impl) impl->Deinitialize = openslES_DestroyEngine; /* and the capabilities */ - impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultOutputDevice = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; LOGI("openslES_Init() - success"); /* this audio target is available. */ - return 1; + return SDL_TRUE; } AudioBootStrap openslES_bootstrap = { - "openslES", "opensl ES audio driver", openslES_Init, 0 + "openslES", "opensl ES audio driver", openslES_Init, SDL_FALSE }; void openslES_ResumeDevices(void) diff --git a/src/audio/os2/SDL_os2audio.c b/src/audio/os2/SDL_os2audio.c index 5fa1ad4ed..9ddfb7607 100644 --- a/src/audio/os2/SDL_os2audio.c +++ b/src/audio/os2/SDL_os2audio.c @@ -248,29 +248,28 @@ static void OS2_CloseDevice(_THIS) SDL_free(pAData); } -static int OS2_OpenDevice(_THIS, void *handle, const char *devname, - int iscapture) +static int OS2_OpenDevice(_THIS, const char *devname) { SDL_PrivateAudioData *pAData; - SDL_AudioFormat SDLAudioFmt; + SDL_AudioFormat test_format; MCI_AMP_OPEN_PARMS stMCIAmpOpen; MCI_BUFFER_PARMS stMCIBuffer; ULONG ulRC; ULONG ulIdx; BOOL new_freq; + SDL_bool iscapture = _this->iscapture; new_freq = FALSE; SDL_zero(stMCIAmpOpen); SDL_zero(stMCIBuffer); - for (SDLAudioFmt = SDL_FirstAudioFormat(_this->spec.format); - SDLAudioFmt != 0; SDLAudioFmt = SDL_NextAudioFormat()) { - if (SDLAudioFmt == AUDIO_U8 || SDLAudioFmt == AUDIO_S16) + for (test_format = SDL_FirstAudioFormat(_this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + if (test_format == AUDIO_U8 || test_format == AUDIO_S16) break; } - if (SDLAudioFmt == 0) { + if (!test_format) { debug_os2("Unsupported audio format, AUDIO_S16 used"); - SDLAudioFmt = AUDIO_S16; + test_format = AUDIO_S16; } pAData = (SDL_PrivateAudioData *) SDL_calloc(1, sizeof(struct SDL_PrivateAudioData)); @@ -285,7 +284,7 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname, } /* Open audio device */ - stMCIAmpOpen.usDeviceID = (handle != NULL) ? ((ULONG)handle - 1) : 0; + stMCIAmpOpen.usDeviceID = (_this->handle != NULL) ? ((ULONG)_this->handle - 1) : 0; stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX; ulRC = mciSendCommand(0, MCI_OPEN, (_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)? @@ -298,7 +297,7 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname, } pAData->usDeviceId = stMCIAmpOpen.usDeviceID; - if (iscapture != 0) { + if (iscapture) { MCI_CONNECTOR_PARMS stMCIConnector; MCI_AMP_SET_PARMS stMCIAmpSet; BOOL fLineIn = _getEnvULong("SDL_AUDIO_LINEIN", 1, 0); @@ -330,7 +329,7 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname, &stMCIAmpSet, 0); } - _this->spec.format = SDLAudioFmt; + _this->spec.format = test_format; _this->spec.channels = _this->spec.channels > 1 ? 2 : 1; if (_this->spec.freq < 8000) { _this->spec.freq = 8000; @@ -342,11 +341,11 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname, /* Setup mixer. */ pAData->stMCIMixSetup.ulFormatTag = MCI_WAVE_FORMAT_PCM; - pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE(SDLAudioFmt); + pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE(test_format); pAData->stMCIMixSetup.ulSamplesPerSec = _this->spec.freq; pAData->stMCIMixSetup.ulChannels = _this->spec.channels; pAData->stMCIMixSetup.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; - if (iscapture == 0) { + if (!iscapture) { pAData->stMCIMixSetup.ulFormatMode= MCI_PLAY; pAData->stMCIMixSetup.pmixEvent = cbAudioWriteEvent; } else { @@ -423,7 +422,7 @@ static int OS2_OpenDevice(_THIS, void *handle, const char *devname, } -static int OS2_Init(SDL_AudioDriverImpl * impl) +static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ impl->DetectDevices = OS2_DetectDevices; @@ -438,12 +437,12 @@ static int OS2_Init(SDL_AudioDriverImpl * impl) impl->FlushCapture = ; impl->HasCaptureSupport = SDL_TRUE; */ - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap OS2AUDIO_bootstrap = { - "DART", "OS/2 DART", OS2_Init, 0 + "DART", "OS/2 DART", OS2_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_OS2 */ diff --git a/src/audio/paudio/SDL_paudio.c b/src/audio/paudio/SDL_paudio.c index c4f40b35d..ae2fc2950 100644 --- a/src/audio/paudio/SDL_paudio.c +++ b/src/audio/paudio/SDL_paudio.c @@ -223,12 +223,12 @@ PAUDIO_CloseDevice(_THIS) } static int -PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +PAUDIO_OpenDevice(_THIS, const char *devname) { const char *workaround = SDL_getenv("SDL_DSP_NOSELECT"); char audiodev[1024]; const char *err = NULL; - int format; + int flags; int bytes_per_sample; SDL_AudioFormat test_format; audio_init paud_init; @@ -316,63 +316,44 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) paud_init.channels = this->spec.channels; /* Try for a closest match on audio format */ - format = 0; - for (test_format = SDL_FirstAudioFormat(this->spec.format); - !format && test_format;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); #endif switch (test_format) { case AUDIO_U8: - bytes_per_sample = 1; - paud_init.bits_per_sample = 8; - paud_init.flags = TWOS_COMPLEMENT | FIXED; - format = 1; + flags = TWOS_COMPLEMENT | FIXED; break; case AUDIO_S8: - bytes_per_sample = 1; - paud_init.bits_per_sample = 8; - paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED; - format = 1; + flags = SIGNED | TWOS_COMPLEMENT | FIXED; break; case AUDIO_S16LSB: - bytes_per_sample = 2; - paud_init.bits_per_sample = 16; - paud_init.flags = SIGNED | TWOS_COMPLEMENT | FIXED; - format = 1; + flags = SIGNED | TWOS_COMPLEMENT | FIXED; break; case AUDIO_S16MSB: - bytes_per_sample = 2; - paud_init.bits_per_sample = 16; - paud_init.flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED; - format = 1; + flags = BIG_ENDIAN | SIGNED | TWOS_COMPLEMENT | FIXED; break; case AUDIO_U16LSB: - bytes_per_sample = 2; - paud_init.bits_per_sample = 16; - paud_init.flags = TWOS_COMPLEMENT | FIXED; - format = 1; + flags = TWOS_COMPLEMENT | FIXED; break; case AUDIO_U16MSB: - bytes_per_sample = 2; - paud_init.bits_per_sample = 16; - paud_init.flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED; - format = 1; + flags = BIG_ENDIAN | TWOS_COMPLEMENT | FIXED; break; default: - break; - } - if (!format) { - test_format = SDL_NextAudioFormat(); + continue; } + break; } - if (format == 0) { + if (!test_format) { #ifdef DEBUG_AUDIO fprintf(stderr, "Couldn't find any hardware audio formats\n"); #endif - return SDL_SetError("Couldn't find any hardware audio formats"); + return SDL_SetError("%s: Unsupported audio format", "paud"); } this->spec.format = test_format; + paud_init.bits_per_sample = SDL_AUDIO_BITSIZE(test_format); + bytes_per_sample = SDL_AUDIO_BITSIZE(test_format) / 8; + paud_init.flags = flags; /* * We know the buffer size and the max number of subsequent writes @@ -406,28 +387,25 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (ioctl(fd, AUDIO_INIT, &paud_init) < 0) { switch (paud_init.rc) { case 1: - err = "Couldn't set audio format: DSP can't do play requests"; + err = "DSP can't do play requests"; break; case 2: - err = "Couldn't set audio format: DSP can't do record requests"; + err = "DSP can't do record requests"; break; case 4: - err = "Couldn't set audio format: request was invalid"; + err = "request was invalid"; break; case 5: - err = "Couldn't set audio format: conflict with open's flags"; + err = "conflict with open's flags"; break; case 6: - err = "Couldn't set audio format: out of DSP MIPS or memory"; + err = "out of DSP MIPS or memory"; break; default: - err = "Couldn't set audio format: not documented in sys/audio.h"; + err = "not documented in sys/audio.h"; break; } - } - - if (err != NULL) { - return SDL_SetError("Paudio: %s", err); + return SDL_SetError("paud: Couldn't set audio format (%s)", err); } /* Allocate mixing buffer */ @@ -485,14 +463,14 @@ PAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; } -static int +static SDL_bool PAUDIO_Init(SDL_AudioDriverImpl * impl) { /* !!! FIXME: not right for device enum? */ int fd = OpenAudioPath(NULL, 0, OPEN_FLAGS, 0); if (fd < 0) { SDL_SetError("PAUDIO: Couldn't open audio device"); - return 0; + return SDL_FALSE; } close(fd); @@ -502,13 +480,13 @@ PAUDIO_Init(SDL_AudioDriverImpl * impl) impl->PlayDevice = PAUDIO_WaitDevice; impl->GetDeviceBuf = PAUDIO_GetDeviceBuf; impl->CloseDevice = PAUDIO_CloseDevice; - impl->OnlyHasDefaultOutputDevice = 1; /* !!! FIXME: add device enum! */ + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; /* !!! FIXME: add device enum! */ - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap PAUDIO_bootstrap = { - "paud", "AIX Paudio", PAUDIO_Init, 0 + "paud", "AIX Paudio", PAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_PAUDIO */ diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c index 32d7d5a5a..7e318f1bc 100644 --- a/src/audio/pipewire/SDL_pipewire.c +++ b/src/audio/pipewire/SDL_pipewire.c @@ -31,8 +31,22 @@ #include #include -/* Older versions of Pipewire may not define this, but it's safe to pass at - * runtime even if older installations don't recognize it. +/* + * The following keys are defined for compatability when building against older versions of Pipewire + * prior to their introduction and can be removed if the minimum required Pipewire version is increased + * to or beyond their point of introduction. + */ + +/* + * Introduced in 0.3.22 + * Taken from /src/pipewire/keys.h + */ +#ifndef PW_KEY_CONFIG_NAME +#define PW_KEY_CONFIG_NAME "config.name" +#endif + +/* + * Introduced in 0.3.33 * Taken from src/pipewire/keys.h */ #ifndef PW_KEY_NODE_RATE @@ -40,19 +54,22 @@ #endif /* - * These seem to be sane limits as Pipewire - * uses them in several of it's own modules. - * - * NOTE: 8192 is a hard upper limit in Pipewire and - * increasing this value can lead to buffer overflows. + * This seems to be a sane lower limit as Pipewire + * uses it in several of it's own modules. */ -#define PW_MIN_SAMPLES 32 /* About 0.67ms at 48kHz */ -#define PW_MAX_SAMPLES 8192 /* About 170.6ms at 48kHz */ +#define PW_MIN_SAMPLES 32 /* About 0.67ms at 48kHz */ #define PW_BASE_CLOCK_RATE 48000 #define PW_POD_BUFFER_LENGTH 1024 #define PW_THREAD_NAME_BUFFER_LENGTH 128 +enum PW_READY_FLAGS +{ + PW_READY_FLAG_BUFFER_ADDED = 0x1, + PW_READY_FLAG_STREAM_READY = 0x2, + PW_READY_FLAG_ALL_BITS = 0x3 +}; + #define PW_ID_TO_HANDLE(x) (void *)((uintptr_t)x) #define PW_HANDLE_TO_ID(x) (uint32_t)((uintptr_t)x) @@ -86,14 +103,13 @@ static enum pw_stream_state (*PIPEWIRE_pw_stream_get_state)(struct pw_stream *st static struct pw_buffer *(*PIPEWIRE_pw_stream_dequeue_buffer)(struct pw_stream *); static int (*PIPEWIRE_pw_stream_queue_buffer)(struct pw_stream *, struct pw_buffer *); static struct pw_properties *(*PIPEWIRE_pw_properties_new)(const char *, ...)SPA_SENTINEL; -static void (*PIPEWIRE_pw_properties_free)(struct pw_properties *); static int (*PIPEWIRE_pw_properties_set)(struct pw_properties *, const char *, const char *); static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *, const char *, ...) SPA_PRINTF_FUNC(3, 4); #ifdef SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC static const char *pipewire_library = SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC; -static void * pipewire_handle = NULL; +static void *pipewire_handle = NULL; static int pipewire_dlsym(const char *fn, void **addr) @@ -176,7 +192,6 @@ load_pipewire_syms() SDL_PIPEWIRE_SYM(pw_stream_dequeue_buffer); SDL_PIPEWIRE_SYM(pw_stream_queue_buffer); SDL_PIPEWIRE_SYM(pw_properties_new); - SDL_PIPEWIRE_SYM(pw_properties_free); SDL_PIPEWIRE_SYM(pw_properties_set); SDL_PIPEWIRE_SYM(pw_properties_setf); @@ -239,16 +254,16 @@ struct io_node /* The global hotplug thread and associated objects. */ static struct pw_thread_loop *hotplug_loop; -static struct pw_core * hotplug_core; -static struct pw_context * hotplug_context; -static struct pw_registry * hotplug_registry; +static struct pw_core *hotplug_core; +static struct pw_context *hotplug_context; +static struct pw_registry *hotplug_registry; static struct spa_hook hotplug_registry_listener; static struct spa_hook hotplug_core_listener; static struct spa_list hotplug_pending_list; static struct spa_list hotplug_io_list; static int hotplug_init_seq_val; -static SDL_atomic_t hotplug_init_complete; -static SDL_atomic_t hotplug_events_enabled; +static SDL_bool hotplug_init_complete; +static SDL_bool hotplug_events_enabled; static Uint32 pipewire_default_sink_id = SPA_ID_INVALID; static Uint32 pipewire_default_source_id = SPA_ID_INVALID; @@ -260,8 +275,6 @@ io_list_check_add(struct io_node *node) struct io_node *n; SDL_bool ret = SDL_TRUE; - PIPEWIRE_pw_thread_loop_lock(hotplug_loop); - /* See if the node is already in the list */ spa_list_for_each (n, &hotplug_io_list, link) { if (n->id == node->id) { @@ -273,14 +286,12 @@ io_list_check_add(struct io_node *node) /* Add to the list if the node doesn't already exist */ spa_list_append(&hotplug_io_list, &node->link); - if (SDL_AtomicGet(&hotplug_events_enabled)) { + if (hotplug_events_enabled) { SDL_AddAudioDevice(node->is_capture, node->name, &node->spec, PW_ID_TO_HANDLE(node->id)); } dup_found: - PIPEWIRE_pw_thread_loop_unlock(hotplug_loop); - return ret; } @@ -289,14 +300,12 @@ io_list_remove(Uint32 id) { struct io_node *n, *temp; - PIPEWIRE_pw_thread_loop_lock(hotplug_loop); - /* Find and remove the node from the list */ spa_list_for_each_safe (n, temp, &hotplug_io_list, link) { if (n->id == id) { spa_list_remove(&n->link); - if (SDL_AtomicGet(&hotplug_events_enabled)) { + if (hotplug_events_enabled) { SDL_RemoveAudioDevice(n->is_capture, PW_ID_TO_HANDLE(id)); } @@ -305,8 +314,6 @@ io_list_remove(Uint32 id) break; } } - - PIPEWIRE_pw_thread_loop_unlock(hotplug_loop); } static void @@ -315,8 +322,6 @@ io_list_sort() struct io_node *default_sink = NULL, *default_source = NULL; struct io_node *n, *temp; - PIPEWIRE_pw_thread_loop_lock(hotplug_loop); - /* Find and move the default nodes to the beginning of the list */ spa_list_for_each_safe (n, temp, &hotplug_io_list, link) { if (n->id == pipewire_default_sink_id) { @@ -335,8 +340,6 @@ io_list_sort() if (default_sink) { spa_list_prepend(&hotplug_io_list, &default_sink->link); } - - PIPEWIRE_pw_thread_loop_unlock(hotplug_loop); } static void @@ -395,7 +398,7 @@ pending_list_clear() static void * node_object_new(Uint32 id, const char *type, Uint32 version, const void *funcs, const struct pw_core_events *core_events) { - struct pw_proxy * proxy; + struct pw_proxy *proxy; struct node_object *node; /* Create the proxy object */ @@ -430,7 +433,7 @@ core_events_hotplug_init_callback(void *object, uint32_t id, int seq) spa_hook_remove(&hotplug_core_listener); /* Signal that the initial I/O list is populated */ - SDL_AtomicSet(&hotplug_init_complete, 1); + hotplug_init_complete = SDL_TRUE; PIPEWIRE_pw_thread_loop_signal(hotplug_loop, false); } } @@ -439,7 +442,7 @@ static void core_events_interface_callback(void *object, uint32_t id, int seq) { struct node_object *node = object; - struct io_node * io = node->userdata; + struct io_node *io = node->userdata; if (id == PW_ID_CORE && seq == node->seq) { /* @@ -479,7 +482,7 @@ hotplug_core_sync(struct node_object *node) node->seq = pw_core_sync(hotplug_core, PW_ID_CORE, node->seq); } - if (!SDL_AtomicGet(&hotplug_init_complete)) { + if (!hotplug_init_complete) { hotplug_init_seq_val = pw_core_sync(hotplug_core, PW_ID_CORE, hotplug_init_seq_val); } } @@ -489,7 +492,7 @@ static SDL_bool get_range_param(const struct spa_pod *param, Uint32 key, int *def, int *min, int *max) { const struct spa_pod_prop *prop; - struct spa_pod * value; + struct spa_pod *value; Uint32 n_values, choice; prop = spa_pod_find_prop(param, NULL, key); @@ -543,8 +546,8 @@ static void node_event_info(void *object, const struct pw_node_info *info) { struct node_object *node = object; - struct io_node * io = node->userdata; - const char * prop_val; + struct io_node *io = node->userdata; + const char *prop_val; Uint32 i; if (info) { @@ -566,7 +569,7 @@ static void node_event_param(void *object, int seq, uint32_t id, uint32_t index, uint32_t next, const struct spa_pod *param) { struct node_object *node = object; - struct io_node * io = node->userdata; + struct io_node *io = node->userdata; /* Get the default frequency */ if (io->spec.freq == 0) { @@ -619,7 +622,7 @@ registry_event_global_callback(void *object, uint32_t id, uint32_t permissions, const char *media_class = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS); if (media_class) { - const char * node_desc; + const char *node_desc; struct io_node *io; SDL_bool is_capture; int str_buffer_len; @@ -738,23 +741,30 @@ hotplug_loop_destroy() pending_list_clear(); io_list_clear(); - SDL_AtomicSet(&hotplug_init_complete, 0); - SDL_AtomicSet(&hotplug_events_enabled, 0); + hotplug_init_complete = SDL_FALSE; + hotplug_events_enabled = SDL_FALSE; + + pipewire_default_sink_id = SPA_ID_INVALID; + pipewire_default_source_id = SPA_ID_INVALID; if (hotplug_registry) { PIPEWIRE_pw_proxy_destroy((struct pw_proxy *)hotplug_registry); + hotplug_registry = NULL; } if (hotplug_core) { PIPEWIRE_pw_core_disconnect(hotplug_core); + hotplug_core = NULL; } if (hotplug_context) { PIPEWIRE_pw_context_destroy(hotplug_context); + hotplug_context = NULL; } if (hotplug_loop) { PIPEWIRE_pw_thread_loop_destroy(hotplug_loop); + hotplug_loop = NULL; } } @@ -766,7 +776,7 @@ PIPEWIRE_DetectDevices() PIPEWIRE_pw_thread_loop_lock(hotplug_loop); /* Wait until the initial registry enumeration is complete */ - if (!SDL_AtomicGet(&hotplug_init_complete)) { + if (!hotplug_init_complete) { PIPEWIRE_pw_thread_loop_wait(hotplug_loop); } @@ -777,7 +787,7 @@ PIPEWIRE_DetectDevices() SDL_AddAudioDevice(io->is_capture, io->name, &io->spec, PW_ID_TO_HANDLE(io->id)); } - SDL_AtomicSet(&hotplug_events_enabled, 1); + hotplug_events_enabled = SDL_TRUE; PIPEWIRE_pw_thread_loop_unlock(hotplug_loop); } @@ -790,14 +800,14 @@ static const enum spa_audio_channel PIPEWIRE_channel_map_4[] = { SPA_AUDIO_CHANN SPA_AUDIO_CHANNEL_RR }; static const enum spa_audio_channel PIPEWIRE_channel_map_5[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR }; -static const enum spa_audio_channel PIPEWIRE_channel_map_6[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, +static const enum spa_audio_channel PIPEWIRE_channel_map_6[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR }; -static const enum spa_audio_channel PIPEWIRE_channel_map_7[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, +static const enum spa_audio_channel PIPEWIRE_channel_map_7[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RC, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR }; -static const enum spa_audio_channel PIPEWIRE_channel_map_8[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, +static const enum spa_audio_channel PIPEWIRE_channel_map_8[] = { SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, - SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR }; + SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR }; #define COPY_CHANNEL_MAP(c) SDL_memcpy(info->position, PIPEWIRE_channel_map_##c, sizeof(PIPEWIRE_channel_map_##c)) @@ -872,9 +882,9 @@ initialize_spa_info(const SDL_AudioSpec *spec, struct spa_audio_info_raw *info) static void output_callback(void *data) { - struct pw_buffer * pw_buf; + struct pw_buffer *pw_buf; struct spa_buffer *spa_buf; - Uint8 * dst; + Uint8 *dst; _THIS = (SDL_AudioDevice *)data; struct pw_stream *stream = this->hidden->stream; @@ -941,9 +951,9 @@ output_callback(void *data) static void input_callback(void *data) { - struct pw_buffer * pw_buf; + struct pw_buffer *pw_buf; struct spa_buffer *spa_buf; - Uint8 * src; + Uint8 *src; _THIS = (SDL_AudioDevice *)data; struct pw_stream *stream = this->hidden->stream; @@ -985,35 +995,71 @@ input_callback(void *data) this->callbackspec.callback(this->callbackspec.userdata, this->work_buffer, this->callbackspec.size); SDL_UnlockMutex(this->mixer_lock); } - } else { /* Flush the buffer when paused */ + } else if (this->hidden->buffer) { /* Flush the buffer when paused */ if (SDL_CountDataQueue(this->hidden->buffer) != 0) { - SDL_ClearDataQueue(this->hidden->buffer, this->hidden->buffer_period_size * 2); + SDL_ClearDataQueue(this->hidden->buffer, this->hidden->input_buffer_packet_size); } } PIPEWIRE_pw_stream_queue_buffer(stream, pw_buf); } +static void +stream_add_buffer_callback(void *data, struct pw_buffer *buffer) +{ + _THIS = data; + + if (this->iscapture == SDL_FALSE) { + /* + * Clamp the output spec samples and size to the max size of the Pipewire buffer. + * If they exceed the maximum size of the Pipewire buffer, double buffering will be used. + */ + if (this->spec.size > buffer->buffer->datas[0].maxsize) { + this->spec.samples = buffer->buffer->datas[0].maxsize / this->hidden->stride; + this->spec.size = buffer->buffer->datas[0].maxsize; + } + } else if (this->hidden->buffer == NULL) { + /* + * The latency of source nodes can change, so buffering is always required. + * + * Ensure that the intermediate input buffer is large enough to hold the requested + * application packet size or a full buffer of data from Pipewire, whichever is larger. + * + * A packet size of 2 periods should be more than is ever needed. + */ + this->hidden->input_buffer_packet_size = SPA_MAX(this->spec.size, buffer->buffer->datas[0].maxsize) * 2; + this->hidden->buffer = SDL_NewDataQueue(this->hidden->input_buffer_packet_size, this->hidden->input_buffer_packet_size); + } + + this->hidden->stream_init_status |= PW_READY_FLAG_BUFFER_ADDED; + PIPEWIRE_pw_thread_loop_signal(this->hidden->loop, false); +} + static void stream_state_changed_callback(void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { _THIS = data; + if (state == PW_STREAM_STATE_STREAMING) { + this->hidden->stream_init_status |= PW_READY_FLAG_STREAM_READY; + } + if (state == PW_STREAM_STATE_STREAMING || state == PW_STREAM_STATE_ERROR) { - SDL_AtomicSet(&this->hidden->stream_initialized, 1); PIPEWIRE_pw_thread_loop_signal(this->hidden->loop, false); } } static const struct pw_stream_events stream_output_events = { PW_VERSION_STREAM_EVENTS, .state_changed = stream_state_changed_callback, + .add_buffer = stream_add_buffer_callback, .process = output_callback }; static const struct pw_stream_events stream_input_events = { PW_VERSION_STREAM_EVENTS, - .state_changed = stream_state_changed_callback, - .process = input_callback }; + .state_changed = stream_state_changed_callback, + .add_buffer = stream_add_buffer_callback, + .process = input_callback }; static int -PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +PIPEWIRE_OpenDevice(_THIS, const char *devname) { /* * NOTE: The PW_STREAM_FLAG_RT_PROCESS flag can be set to call the stream @@ -1028,23 +1074,22 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) Uint8 pod_buffer[PW_POD_BUFFER_LENGTH]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(pod_buffer, sizeof(pod_buffer)); struct spa_audio_info_raw spa_info = { 0 }; - const struct spa_pod * params = NULL; + const struct spa_pod *params = NULL; struct SDL_PrivateAudioData *priv; - struct pw_properties * props; - const char * app_name, *stream_name, *stream_role, *error; - const Uint32 node_id = this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(this->handle); - enum pw_stream_state state; + struct pw_properties *props; + const char *app_name, *stream_name, *stream_role, *error; + const Uint32 node_id = this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(this->handle); + SDL_bool iscapture = this->iscapture; int res; /* Clamp the period size to sane values */ - const int min_period = PW_MIN_SAMPLES * SPA_MAX(this->spec.freq / PW_BASE_CLOCK_RATE, 1); - const int adjusted_samples = SPA_CLAMP(this->spec.samples, min_period, PW_MAX_SAMPLES); + const int min_period = PW_MIN_SAMPLES * SPA_MAX(this->spec.freq / PW_BASE_CLOCK_RATE, 1); /* Get the hints for the application name, stream name and role */ app_name = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME); if (!app_name || *app_name == '\0') { app_name = SDL_GetHint(SDL_HINT_APP_NAME); - if (!app_name || *app_name == '\0') { + if (!app_name || *app_name == '\0') { app_name = "SDL Application"; } } @@ -1077,38 +1122,34 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Size of a single audio frame in bytes */ priv->stride = (SDL_AUDIO_BITSIZE(this->spec.format) >> 3) * this->spec.channels; - if (this->spec.samples != adjusted_samples && !iscapture) { - this->spec.samples = adjusted_samples; + if (this->spec.samples < min_period) { + this->spec.samples = min_period; this->spec.size = this->spec.samples * priv->stride; } - /* The latency of source nodes can change, so buffering is required. */ - if (iscapture) { - priv->buffer_period_size = SPA_MAX(this->spec.samples, adjusted_samples) * priv->stride; - - /* A packet size of 4 periods should be more than is ever needed (no more than 2 should be queued in practice). */ - priv->buffer = SDL_NewDataQueue(priv->buffer_period_size * 4, priv->buffer_period_size * 2); - if (priv->buffer == NULL) { - return SDL_SetError("Pipewire: Failed to allocate source buffer"); - } - } - - SDL_snprintf(thread_name, sizeof(thread_name), "SDLAudio%c%ld", (iscapture) ? 'C' : 'P', (long)handle); + SDL_snprintf(thread_name, sizeof(thread_name), "SDLAudio%c%ld", (iscapture) ? 'C' : 'P', (long)this->handle); priv->loop = PIPEWIRE_pw_thread_loop_new(thread_name, NULL); if (priv->loop == NULL) { return SDL_SetError("Pipewire: Failed to create stream loop (%i)", errno); } - /* Load the rtkit module so Pipewire can set the loop thread to the appropriate priority */ - props = PIPEWIRE_pw_properties_new(PW_KEY_CONTEXT_PROFILE_MODULES, "default,rtkit", NULL); + /* + * Load the realtime module so Pipewire can set the loop thread to the appropriate priority. + * + * NOTE: Pipewire versions 0.3.22 or higher require the PW_KEY_CONFIG_NAME property (with client-rt.conf), + * lower versions require explicitly specifying the 'rtkit' module. + * + * PW_KEY_CONTEXT_PROFILE_MODULES is deprecated and can be safely removed if the minimum required + * Pipewire version is increased to 0.3.22 or higher at some point. + */ + props = PIPEWIRE_pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", + PW_KEY_CONTEXT_PROFILE_MODULES, "default,rtkit", NULL); if (props == NULL) { return SDL_SetError("Pipewire: Failed to create stream context properties (%i)", errno); } - /* On success, the context owns the properties object and will free it at destruction time. */ priv->context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), props, 0); if (priv->context == NULL) { - PIPEWIRE_pw_properties_free(props); return SDL_SetError("Pipewire: Failed to create stream context (%i)", errno); } @@ -1123,18 +1164,14 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) PIPEWIRE_pw_properties_set(props, PW_KEY_APP_NAME, app_name); PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_NAME, stream_name); PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_DESCRIPTION, stream_name); - PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", adjusted_samples, this->spec.freq); + PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%i", this->spec.samples, this->spec.freq); PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", this->spec.freq); PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true"); - /* - * Create the new stream - * On success, the stream owns the properties object and will free it at destruction time. - */ + /* Create the new stream */ priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props, iscapture ? &stream_input_events : &stream_output_events, this); if (priv->stream == NULL) { - PIPEWIRE_pw_properties_free(props); return SDL_SetError("Pipewire: Failed to create stream (%i)", errno); } @@ -1149,19 +1186,23 @@ PIPEWIRE_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("Pipewire: Failed to start stream loop"); } - /* Wait until the stream is either running or failed */ + /* Wait until all init flags are set or the stream has failed. */ PIPEWIRE_pw_thread_loop_lock(priv->loop); - if (!SDL_AtomicGet(&priv->stream_initialized)) { + while (priv->stream_init_status != PW_READY_FLAG_ALL_BITS && + PIPEWIRE_pw_stream_get_state(priv->stream, NULL) != PW_STREAM_STATE_ERROR) { PIPEWIRE_pw_thread_loop_wait(priv->loop); } PIPEWIRE_pw_thread_loop_unlock(priv->loop); - state = PIPEWIRE_pw_stream_get_state(priv->stream, &error); - - if (state == PW_STREAM_STATE_ERROR) { + if (PIPEWIRE_pw_stream_get_state(priv->stream, &error) == PW_STREAM_STATE_ERROR) { return SDL_SetError("Pipewire: Stream error: %s", error); } + /* If this is a capture stream, make sure the intermediate buffer was successfully allocated. */ + if (iscapture && priv->buffer == NULL) { + return SDL_SetError("Pipewire: Failed to allocate source buffer"); + } + return 0; } @@ -1200,19 +1241,19 @@ PIPEWIRE_Deinitialize() } } -static int +static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl) { if (!pipewire_initialized) { if (init_pipewire_library() < 0) { - return 0; + return SDL_FALSE; } pipewire_initialized = SDL_TRUE; if (hotplug_loop_init() < 0) { PIPEWIRE_Deinitialize(); - return 0; + return SDL_FALSE; } } @@ -1222,13 +1263,13 @@ PIPEWIRE_Init(SDL_AudioDriverImpl *impl) impl->CloseDevice = PIPEWIRE_CloseDevice; impl->Deinitialize = PIPEWIRE_Deinitialize; - impl->HasCaptureSupport = 1; - impl->ProvidesOwnCallbackThread = 1; + impl->HasCaptureSupport = SDL_TRUE; + impl->ProvidesOwnCallbackThread = SDL_TRUE; - return 1; + return SDL_TRUE; } -AudioBootStrap PIPEWIRE_bootstrap = { "pipewire", "Pipewire", PIPEWIRE_Init, 0 }; +AudioBootStrap PIPEWIRE_bootstrap = { "pipewire", "Pipewire", PIPEWIRE_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_PIPEWIRE */ diff --git a/src/audio/pipewire/SDL_pipewire.h b/src/audio/pipewire/SDL_pipewire.h index 731a2027f..767b8f10c 100644 --- a/src/audio/pipewire/SDL_pipewire.h +++ b/src/audio/pipewire/SDL_pipewire.h @@ -37,9 +37,9 @@ struct SDL_PrivateAudioData struct pw_context *context; struct SDL_DataQueue *buffer; - size_t buffer_period_size; - Sint32 stride; /* Bytes-per-frame */ - SDL_atomic_t stream_initialized; + size_t input_buffer_packet_size; + Sint32 stride; /* Bytes-per-frame */ + int stream_init_status; }; #endif /* SDL_pipewire_h_ */ diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c index 1966cafdf..d908170c6 100644 --- a/src/audio/psp/SDL_pspaudio.c +++ b/src/audio/psp/SDL_pspaudio.c @@ -42,7 +42,7 @@ #define PSPAUDIO_DRIVER_NAME "psp" static int -PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +PSPAUDIO_OpenDevice(_THIS, const char *devname) { int format, mixlen, i; @@ -158,7 +158,7 @@ static void PSPAUDIO_ThreadInit(_THIS) } } -static int +static SDL_bool PSPAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -170,16 +170,16 @@ PSPAUDIO_Init(SDL_AudioDriverImpl * impl) impl->ThreadInit = PSPAUDIO_ThreadInit; /* PSP audio device */ - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; /* - impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultCaptureDevice = 1; + impl->HasCaptureSupport = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; */ - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap PSPAUDIO_bootstrap = { - "psp", "PSP audio driver", PSPAUDIO_Init, 0 + "psp", "PSP audio driver", PSPAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_PSP */ diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c index bf16839b5..a969f2b1f 100644 --- a/src/audio/pulseaudio/SDL_pulseaudio.c +++ b/src/audio/pulseaudio/SDL_pulseaudio.c @@ -522,7 +522,7 @@ SourceDeviceNameCallback(pa_context *c, const pa_source_info *i, int is_last, vo } static SDL_bool -FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle) +FindDeviceName(struct SDL_PrivateAudioData *h, const SDL_bool iscapture, void *handle) { const uint32_t idx = ((uint32_t) ((size_t) handle)) - 1; @@ -544,16 +544,17 @@ FindDeviceName(struct SDL_PrivateAudioData *h, const int iscapture, void *handle } static int -PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +PULSEAUDIO_OpenDevice(_THIS, const char *devname) { struct SDL_PrivateAudioData *h = NULL; - Uint16 test_format = 0; + SDL_AudioFormat test_format; pa_sample_spec paspec; pa_buffer_attr paattr; pa_channel_map pacmap; pa_stream_flags_t flags = 0; const char *name = NULL; - int state = 0; + SDL_bool iscapture = this->iscapture; + int state = 0, format = PA_SAMPLE_INVALID; int rc = 0; /* Initialize all variables that we clean on shutdown */ @@ -564,48 +565,43 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } SDL_zerop(this->hidden); - paspec.format = PA_SAMPLE_INVALID; - /* Try for a closest match on audio format */ - for (test_format = SDL_FirstAudioFormat(this->spec.format); - (paspec.format == PA_SAMPLE_INVALID) && test_format;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); #endif switch (test_format) { case AUDIO_U8: - paspec.format = PA_SAMPLE_U8; + format = PA_SAMPLE_U8; break; case AUDIO_S16LSB: - paspec.format = PA_SAMPLE_S16LE; + format = PA_SAMPLE_S16LE; break; case AUDIO_S16MSB: - paspec.format = PA_SAMPLE_S16BE; + format = PA_SAMPLE_S16BE; break; case AUDIO_S32LSB: - paspec.format = PA_SAMPLE_S32LE; + format = PA_SAMPLE_S32LE; break; case AUDIO_S32MSB: - paspec.format = PA_SAMPLE_S32BE; + format = PA_SAMPLE_S32BE; break; case AUDIO_F32LSB: - paspec.format = PA_SAMPLE_FLOAT32LE; + format = PA_SAMPLE_FLOAT32LE; break; case AUDIO_F32MSB: - paspec.format = PA_SAMPLE_FLOAT32BE; + format = PA_SAMPLE_FLOAT32BE; break; default: - paspec.format = PA_SAMPLE_INVALID; - break; - } - if (paspec.format == PA_SAMPLE_INVALID) { - test_format = SDL_NextAudioFormat(); + continue; } + break; } - if (paspec.format == PA_SAMPLE_INVALID) { - return SDL_SetError("Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "pulseaudio"); } this->spec.format = test_format; + paspec.format = format; /* Calculate the final parameters for this audio specification */ #ifdef PA_STREAM_ADJUST_LATENCY @@ -648,7 +644,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_SetError("Could not connect to PulseAudio server"); } - if (!FindDeviceName(h, iscapture, handle)) { + if (!FindDeviceName(h, iscapture, this->handle)) { return SDL_SetError("Requested PulseAudio sink/source missing?"); } @@ -832,16 +828,16 @@ PULSEAUDIO_Deinitialize(void) UnloadPulseAudioLibrary(); } -static int +static SDL_bool PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) { if (LoadPulseAudioLibrary() < 0) { - return 0; + return SDL_FALSE; } if (ConnectToPulseServer(&hotplug_mainloop, &hotplug_context) < 0) { UnloadPulseAudioLibrary(); - return 0; + return SDL_FALSE; } include_monitors = SDL_GetHintBoolean(SDL_HINT_AUDIO_INCLUDE_MONITORS, SDL_FALSE); @@ -859,11 +855,11 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap PULSEAUDIO_bootstrap = { - "pulseaudio", "PulseAudio", PULSEAUDIO_Init, 0 + "pulseaudio", "PulseAudio", PULSEAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_PULSEAUDIO */ diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c index ca1539fdd..5c4ab38ba 100644 --- a/src/audio/qsa/SDL_qsa_audio.c +++ b/src/audio/qsa/SDL_qsa_audio.c @@ -121,7 +121,7 @@ QSA_WaitDevice(_THIS) /* For example, Vortex 8820 audio driver stucks on second DAC because */ /* it doesn't exist ! */ result = SDL_IOReady(this->hidden->audio_fd, - this->hidden->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE, + this->iscapture ? SDL_IOR_READ : SDL_IOR_WRITE, 2 * 1000); switch (result) { case -1: @@ -180,7 +180,7 @@ QSA_PlayDevice(_THIS) } else { if ((errno == EINVAL) || (errno == EIO)) { SDL_zero(cstatus); - if (!this->hidden->iscapture) { + if (!this->iscapture) { cstatus.channel = SND_PCM_CHANNEL_PLAYBACK; } else { cstatus.channel = SND_PCM_CHANNEL_CAPTURE; @@ -196,7 +196,7 @@ QSA_PlayDevice(_THIS) if ((cstatus.status == SND_PCM_STATUS_UNDERRUN) || (cstatus.status == SND_PCM_STATUS_READY)) { - if (!this->hidden->iscapture) { + if (!this->iscapture) { status = snd_pcm_plugin_prepare(this->hidden-> audio_handle, @@ -240,7 +240,7 @@ static void QSA_CloseDevice(_THIS) { if (this->hidden->audio_handle != NULL) { - if (!this->hidden->iscapture) { + if (!this->iscapture) { /* Finish playing available samples */ snd_pcm_plugin_flush(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); @@ -257,13 +257,13 @@ QSA_CloseDevice(_THIS) } static int -QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +QSA_OpenDevice(_THIS, const char *devname) { - const QSA_Device *device = (const QSA_Device *) handle; + const QSA_Device *device = (const QSA_Device *) this->handle; + SDL_Bool iscapture = this->iscapture; int status = 0; int format = 0; - SDL_AudioFormat test_format = 0; - int found = 0; + SDL_AudioFormat test_format; snd_pcm_channel_setup_t csetup; snd_pcm_channel_params_t cparams; @@ -280,9 +280,6 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Initialize channel transfer parameters to default */ QSA_InitAudioParams(&cparams); - /* Initialize channel direction: capture or playback */ - this->hidden->iscapture = iscapture ? SDL_TRUE : SDL_FALSE; - if (device != NULL) { /* Open requested audio device */ this->hidden->deviceno = device->deviceno; @@ -305,89 +302,49 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Try for a closest match on audio format */ - format = 0; - /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */ - found = 0; - - for (test_format = SDL_FirstAudioFormat(this->spec.format); !found;) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { /* if match found set format to equivalent QSA format */ switch (test_format) { case AUDIO_U8: - { - format = SND_PCM_SFMT_U8; - found = 1; - } + format = SND_PCM_SFMT_U8; break; case AUDIO_S8: - { - format = SND_PCM_SFMT_S8; - found = 1; - } + format = SND_PCM_SFMT_S8; break; case AUDIO_S16LSB: - { - format = SND_PCM_SFMT_S16_LE; - found = 1; - } + format = SND_PCM_SFMT_S16_LE; break; case AUDIO_S16MSB: - { - format = SND_PCM_SFMT_S16_BE; - found = 1; - } + format = SND_PCM_SFMT_S16_BE; break; case AUDIO_U16LSB: - { - format = SND_PCM_SFMT_U16_LE; - found = 1; - } + format = SND_PCM_SFMT_U16_LE; break; case AUDIO_U16MSB: - { - format = SND_PCM_SFMT_U16_BE; - found = 1; - } + format = SND_PCM_SFMT_U16_BE; break; case AUDIO_S32LSB: - { - format = SND_PCM_SFMT_S32_LE; - found = 1; - } + format = SND_PCM_SFMT_S32_LE; break; case AUDIO_S32MSB: - { - format = SND_PCM_SFMT_S32_BE; - found = 1; - } + format = SND_PCM_SFMT_S32_BE; break; case AUDIO_F32LSB: - { - format = SND_PCM_SFMT_FLOAT_LE; - found = 1; - } + format = SND_PCM_SFMT_FLOAT_LE; break; case AUDIO_F32MSB: - { - format = SND_PCM_SFMT_FLOAT_BE; - found = 1; - } + format = SND_PCM_SFMT_FLOAT_BE; break; default: - { - break; - } - } - - if (!found) { - test_format = SDL_NextAudioFormat(); + continue; } + break; } - /* assumes test_format not 0 on success */ - if (test_format == 0) { - return SDL_SetError("QSA: Couldn't find any hardware audio formats"); + /* can't use format as SND_PCM_SFMT_U8 = 0 in qsa */ + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "qsa"); } - this->spec.format = test_format; /* Set the audio format */ @@ -407,7 +364,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) /* Make sure channel is setup right one last time */ SDL_zero(csetup); - if (!this->hidden->iscapture) { + if (!this->iscapture) { csetup.channel = SND_PCM_CHANNEL_PLAYBACK; } else { csetup.channel = SND_PCM_CHANNEL_CAPTURE; @@ -443,7 +400,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) this->hidden->pcm_len); /* get the file descriptor */ - if (!this->hidden->iscapture) { + if (!this->iscapture) { this->hidden->audio_fd = snd_pcm_file_descriptor(this->hidden->audio_handle, SND_PCM_CHANNEL_PLAYBACK); @@ -458,7 +415,7 @@ QSA_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) } /* Prepare an audio channel */ - if (!this->hidden->iscapture) { + if (!this->iscapture) { /* Prepare audio playback */ status = snd_pcm_plugin_prepare(this->hidden->audio_handle, @@ -635,7 +592,7 @@ QSA_Deinitialize(void) qsa_capture_devices = 0; } -static int +static SDL_bool QSA_Init(SDL_AudioDriverImpl * impl) { /* Clear devices array */ @@ -655,20 +612,14 @@ QSA_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = QSA_GetDeviceBuf; impl->CloseDevice = QSA_CloseDevice; impl->Deinitialize = QSA_Deinitialize; - impl->LockDevice = NULL; - impl->UnlockDevice = NULL; - impl->ProvidesOwnCallbackThread = 0; - impl->SkipMixerLock = 0; - impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultOutputDevice = 0; - impl->OnlyHasDefaultCaptureDevice = 0; + impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap QSAAUDIO_bootstrap = { - "qsa", "QNX QSA Audio", QSA_Init, 0 + "qsa", "QNX QSA Audio", QSA_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_QSA */ diff --git a/src/audio/qsa/SDL_qsa_audio.h b/src/audio/qsa/SDL_qsa_audio.h index 7f5e9d3a4..e4845c9eb 100644 --- a/src/audio/qsa/SDL_qsa_audio.h +++ b/src/audio/qsa/SDL_qsa_audio.h @@ -33,9 +33,6 @@ struct SDL_PrivateAudioData { - /* SDL capture state */ - SDL_bool iscapture; - /* The audio device handle */ int cardno; int deviceno; diff --git a/src/audio/sndio/SDL_sndioaudio.c b/src/audio/sndio/SDL_sndioaudio.c index aa2f83acc..29e5315b9 100644 --- a/src/audio/sndio/SDL_sndioaudio.c +++ b/src/audio/sndio/SDL_sndioaudio.c @@ -237,11 +237,11 @@ SNDIO_CloseDevice(_THIS) } static int -SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +SNDIO_OpenDevice(_THIS, const char *devname) { - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + SDL_AudioFormat test_format; struct sio_par par; - int status; + SDL_bool iscapture = this->iscapture; this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); @@ -273,8 +273,7 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) par.appbufsz = par.round * 2; /* Try for a closest match on audio format */ - status = -1; - while (test_format && (status < 0)) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { if (!SDL_AUDIO_ISFLOAT(test_format)) { par.le = SDL_AUDIO_ISLITTLEENDIAN(test_format) ? 1 : 0; par.sig = SDL_AUDIO_ISSIGNED(test_format) ? 1 : 0; @@ -290,15 +289,13 @@ SNDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) continue; } if ((par.bits == 8 * par.bps) || (par.msb)) { - status = 0; break; } } - test_format = SDL_NextAudioFormat(); } - if (status < 0) { - return SDL_SetError("sndio: Couldn't find any hardware audio formats"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "sndio"); } if ((par.bps == 4) && (par.sig) && (par.le)) @@ -357,11 +354,11 @@ SNDIO_DetectDevices(void) SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, NULL, (void *) 0x2); } -static int +static SDL_bool SNDIO_Init(SDL_AudioDriverImpl * impl) { if (LoadSNDIOLibrary() < 0) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ @@ -375,14 +372,14 @@ SNDIO_Init(SDL_AudioDriverImpl * impl) impl->Deinitialize = SNDIO_Deinitialize; impl->DetectDevices = SNDIO_DetectDevices; - impl->AllowsArbitraryDeviceNames = 1; + impl->AllowsArbitraryDeviceNames = SDL_TRUE; impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap SNDIO_bootstrap = { - "sndio", "OpenBSD sndio", SNDIO_Init, 0 + "sndio", "OpenBSD sndio", SNDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_SNDIO */ diff --git a/src/audio/sun/SDL_sunaudio.c b/src/audio/sun/SDL_sunaudio.c index a78ec7412..595692423 100644 --- a/src/audio/sun/SDL_sunaudio.c +++ b/src/audio/sun/SDL_sunaudio.c @@ -188,11 +188,12 @@ SUNAUDIO_CloseDevice(_THIS) } static int -SUNAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +SUNAUDIO_OpenDevice(_THIS, const char *devname) { #ifdef AUDIO_SETINFO int enc; #endif + SDL_bool iscapture = this->iscapture; int desired_freq = 0; const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT); SDL_AudioFormat format = 0; @@ -394,7 +395,7 @@ snd2au(int sample) return (mask & sample); } -static int +static SDL_bool SUNAUDIO_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -405,13 +406,13 @@ SUNAUDIO_Init(SDL_AudioDriverImpl * impl) impl->GetDeviceBuf = SUNAUDIO_GetDeviceBuf; impl->CloseDevice = SUNAUDIO_CloseDevice; - impl->AllowsArbitraryDeviceNames = 1; + impl->AllowsArbitraryDeviceNames = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap SUNAUDIO_bootstrap = { - "audio", "UNIX /dev/audio interface", SUNAUDIO_Init, 0 + "audio", "UNIX /dev/audio interface", SUNAUDIO_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_SUNAUDIO */ diff --git a/src/audio/vita/SDL_vitaaudio.c b/src/audio/vita/SDL_vitaaudio.c index 5433594bf..88f4a3285 100644 --- a/src/audio/vita/SDL_vitaaudio.c +++ b/src/audio/vita/SDL_vitaaudio.c @@ -37,18 +37,35 @@ #include #include +#include #define SCE_AUDIO_SAMPLE_ALIGN(s) (((s) + 63) & ~63) #define SCE_AUDIO_MAX_VOLUME 0x8000 -/* The tag name used by VITA audio */ -#define VITAAUD_DRIVER_NAME "vita" +static int +VITAAUD_OpenCaptureDevice(_THIS) +{ + this->spec.freq = 16000; + this->spec.samples = 512; + this->spec.channels = 1; + + SDL_CalculateAudioSpec(&this->spec); + + this->hidden->port = sceAudioInOpenPort(SCE_AUDIO_IN_PORT_TYPE_VOICE , 512, 16000, SCE_AUDIO_IN_PARAM_FORMAT_S16_MONO); + + if (this->hidden->port < 0) { + return SDL_SetError("Couldn't open audio in port: %x", this->hidden->port); + } + + return 0; +} static int -VITAAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +VITAAUD_OpenDevice(_THIS, const char *devname) { int format, mixlen, i, port = SCE_AUDIO_OUT_PORT_TYPE_MAIN; int vols[2] = {SCE_AUDIO_MAX_VOLUME, SCE_AUDIO_MAX_VOLUME}; + SDL_AudioFormat test_format; this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); @@ -56,13 +73,20 @@ VITAAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return SDL_OutOfMemory(); } SDL_memset(this->hidden, 0, sizeof(*this->hidden)); - switch (this->spec.format & 0xff) { - case 8: - case 16: - this->spec.format = AUDIO_S16LSB; + + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { + if (test_format == AUDIO_S16LSB) { + this->spec.format = test_format; break; - default: - return SDL_SetError("Unsupported audio format"); + } + } + + if(!test_format) { + return SDL_SetError("Unsupported audio format"); + } + + if (this->iscapture) { + return VITAAUD_OpenCaptureDevice(this); } /* The sample count must be a multiple of 64. */ @@ -91,14 +115,14 @@ VITAAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) port = SCE_AUDIO_OUT_PORT_TYPE_BGM; } - this->hidden->channel = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format); - if (this->hidden->channel < 0) { + this->hidden->port = sceAudioOutOpenPort(port, this->spec.samples, this->spec.freq, format); + if (this->hidden->port < 0) { free(this->hidden->rawbuf); this->hidden->rawbuf = NULL; - return SDL_SetError("Couldn't reserve hardware channel"); + return SDL_SetError("Couldn't open audio out port: %x", this->hidden->port); } - sceAudioOutSetVolume(this->hidden->channel, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols); + sceAudioOutSetVolume(this->hidden->port, SCE_AUDIO_VOLUME_FLAG_L_CH|SCE_AUDIO_VOLUME_FLAG_R_CH, vols); SDL_memset(this->hidden->rawbuf, 0, mixlen); for (i = 0; i < NUM_BUFFERS; i++) { @@ -113,7 +137,7 @@ static void VITAAUD_PlayDevice(_THIS) { Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer]; - sceAudioOutOutput(this->hidden->channel, mixbuf); + sceAudioOutOutput(this->hidden->port, mixbuf); this->hidden->next_buffer = (this->hidden->next_buffer + 1) % NUM_BUFFERS; } @@ -123,6 +147,7 @@ static void VITAAUD_WaitDevice(_THIS) { /* Because we block when sending audio, there's no need for this function to do anything. */ } + static Uint8 *VITAAUD_GetDeviceBuf(_THIS) { return this->hidden->mixbufs[this->hidden->next_buffer]; @@ -130,17 +155,32 @@ static Uint8 *VITAAUD_GetDeviceBuf(_THIS) static void VITAAUD_CloseDevice(_THIS) { - if (this->hidden->channel >= 0) { - sceAudioOutReleasePort(this->hidden->channel); - this->hidden->channel = -1; + if (this->hidden->port >= 0) { + if (this->iscapture) { + sceAudioInReleasePort(this->hidden->port); + } else { + sceAudioOutReleasePort(this->hidden->port); + } + this->hidden->port = -1; } - if (this->hidden->rawbuf != NULL) { + if (!this->iscapture && this->hidden->rawbuf != NULL) { free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */ this->hidden->rawbuf = NULL; } } +static int VITAAUD_CaptureFromDevice(_THIS, void *buffer, int buflen) +{ + int ret; + SDL_assert(buflen == this->spec.size); + ret = sceAudioInInput(this->hidden->port, buffer); + if (ret < 0) { + return SDL_SetError("Failed to capture from device: %x", ret); + } + return this->spec.size; +} + static void VITAAUD_ThreadInit(_THIS) { /* Increase the priority of this audio thread by 1 to put it @@ -154,7 +194,7 @@ static void VITAAUD_ThreadInit(_THIS) } } -static int +static SDL_bool VITAAUD_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -165,17 +205,18 @@ VITAAUD_Init(SDL_AudioDriverImpl * impl) impl->CloseDevice = VITAAUD_CloseDevice; impl->ThreadInit = VITAAUD_ThreadInit; - /* VITA audio device */ - impl->OnlyHasDefaultOutputDevice = 1; - /* - impl->HasCaptureSupport = 1; - impl->OnlyHasDefaultInputDevice = 1; - */ - return 1; /* this audio target is available. */ + impl->CaptureFromDevice = VITAAUD_CaptureFromDevice; + + /* and the capabilities */ + impl->HasCaptureSupport = SDL_TRUE; + impl->OnlyHasDefaultOutputDevice = SDL_TRUE; + impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; + + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap VITAAUD_bootstrap = { - "vita", "VITA audio driver", VITAAUD_Init, 0 + "vita", "VITA audio driver", VITAAUD_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_VITA */ diff --git a/src/audio/vita/SDL_vitaaudio.h b/src/audio/vita/SDL_vitaaudio.h index 73870759b..a5601b28c 100644 --- a/src/audio/vita/SDL_vitaaudio.h +++ b/src/audio/vita/SDL_vitaaudio.h @@ -30,8 +30,8 @@ #define NUM_BUFFERS 2 struct SDL_PrivateAudioData { - /* The hardware output channel. */ - int channel; + /* The hardware input/output port. */ + int port; /* The raw allocated mixing buffer. */ Uint8 *rawbuf; /* Individual mixing buffers. */ diff --git a/src/audio/wasapi/SDL_wasapi.c b/src/audio/wasapi/SDL_wasapi.c index 8f287cdb8..862ed9f5e 100644 --- a/src/audio/wasapi/SDL_wasapi.c +++ b/src/audio/wasapi/SDL_wasapi.c @@ -209,7 +209,7 @@ UpdateAudioStream(_THIS, const SDL_AudioSpec *oldspec) } if (!this->stream) { - return -1; + return -1; /* SDL_NewAudioStream should have called SDL_SetError. */ } } @@ -512,9 +512,8 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) IAudioRenderClient *render = NULL; IAudioCaptureClient *capture = NULL; WAVEFORMATEX *waveformat = NULL; - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); + SDL_AudioFormat test_format; SDL_AudioFormat wasapi_format = 0; - SDL_bool valid_format = SDL_FALSE; HRESULT ret = S_OK; DWORD streamflags = 0; @@ -543,17 +542,15 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) /* Make sure we have a valid format that we can convert to whatever WASAPI wants. */ wasapi_format = WaveFormatToSDLFormat(waveformat); - while ((!valid_format) && (test_format)) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { if (test_format == wasapi_format) { this->spec.format = test_format; - valid_format = SDL_TRUE; break; } - test_format = SDL_NextAudioFormat(); } - if (!valid_format) { - return SDL_SetError("WASAPI: Unsupported audio format"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "wasapi"); } ret = IAudioClient_GetDevicePeriod(client, &default_period, NULL); @@ -561,12 +558,16 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) return WIN_SetErrorFromHRESULT("WASAPI can't determine minimum device period", ret); } +#if 1 /* we're getting reports that WASAPI's resampler introduces distortions, so it's disabled for now. --ryan. */ + this->spec.freq = waveformat->nSamplesPerSec; /* force sampling rate so our resampler kicks in, if necessary. */ +#else /* favor WASAPI's resampler over our own */ if (this->spec.freq != waveformat->nSamplesPerSec) { streamflags |= (AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY); waveformat->nSamplesPerSec = this->spec.freq; waveformat->nAvgBytesPerSec = waveformat->nSamplesPerSec * waveformat->nChannels * (waveformat->wBitsPerSample / 8); } +#endif streamflags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK; ret = IAudioClient_Initialize(client, sharemode, streamflags, 0, 0, waveformat, NULL); @@ -631,9 +632,7 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) } if (updatestream) { - if (UpdateAudioStream(this, &oldspec) == -1) { - return -1; - } + return UpdateAudioStream(this, &oldspec); } return 0; /* good to go. */ @@ -641,9 +640,9 @@ WASAPI_PrepDevice(_THIS, const SDL_bool updatestream) static int -WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +WASAPI_OpenDevice(_THIS, const char *devname) { - LPCWSTR devid = (LPCWSTR) handle; + LPCWSTR devid = (LPCWSTR) this->handle; /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -656,7 +655,7 @@ WASAPI_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) WASAPI_RefDevice(this); /* so CloseDevice() will unref to zero. */ if (!devid) { /* is default device? */ - this->hidden->default_device_generation = SDL_AtomicGet(iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration); + this->hidden->default_device_generation = SDL_AtomicGet(this->iscapture ? &WASAPI_DefaultCaptureGeneration : &WASAPI_DefaultPlaybackGeneration); } else { this->hidden->devid = SDL_wcsdup(devid); if (!this->hidden->devid) { @@ -691,12 +690,6 @@ WASAPI_ThreadDeinit(_THIS) WASAPI_PlatformThreadDeinit(this); } -void -WASAPI_BeginLoopIteration(_THIS) -{ - /* no-op. */ -} - static void WASAPI_Deinitialize(void) { @@ -713,21 +706,20 @@ WASAPI_Deinitialize(void) deviceid_list = NULL; } -static int +static SDL_bool WASAPI_Init(SDL_AudioDriverImpl * impl) { SDL_AtomicSet(&WASAPI_DefaultPlaybackGeneration, 1); SDL_AtomicSet(&WASAPI_DefaultCaptureGeneration, 1); if (WASAPI_PlatformInit() == -1) { - return 0; + return SDL_FALSE; } /* Set the function pointers */ impl->DetectDevices = WASAPI_DetectDevices; impl->ThreadInit = WASAPI_ThreadInit; impl->ThreadDeinit = WASAPI_ThreadDeinit; - impl->BeginLoopIteration = WASAPI_BeginLoopIteration; impl->OpenDevice = WASAPI_OpenDevice; impl->PlayDevice = WASAPI_PlayDevice; impl->WaitDevice = WASAPI_WaitDevice; @@ -736,13 +728,13 @@ WASAPI_Init(SDL_AudioDriverImpl * impl) impl->FlushCapture = WASAPI_FlushCapture; impl->CloseDevice = WASAPI_CloseDevice; impl->Deinitialize = WASAPI_Deinitialize; - impl->HasCaptureSupport = 1; + impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap WASAPI_bootstrap = { - "wasapi", "WASAPI", WASAPI_Init, 0 + "wasapi", "WASAPI", WASAPI_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_WASAPI */ diff --git a/src/audio/wasapi/SDL_wasapi.h b/src/audio/wasapi/SDL_wasapi.h index 7fd02b45f..af79637b7 100644 --- a/src/audio/wasapi/SDL_wasapi.h +++ b/src/audio/wasapi/SDL_wasapi.h @@ -74,7 +74,6 @@ int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery); void WASAPI_PlatformThreadInit(_THIS); void WASAPI_PlatformThreadDeinit(_THIS); void WASAPI_PlatformDeleteActivationHandler(void *handler); -void WASAPI_BeginLoopIteration(_THIS); #ifdef __cplusplus } diff --git a/src/audio/winmm/SDL_winmm.c b/src/audio/winmm/SDL_winmm.c index e79d6eeb7..444d21576 100644 --- a/src/audio/winmm/SDL_winmm.c +++ b/src/audio/winmm/SDL_winmm.c @@ -283,10 +283,11 @@ PrepWaveFormat(_THIS, UINT devId, WAVEFORMATEX *pfmt, const int iscapture) } static int -WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) +WINMM_OpenDevice(_THIS, const char *devname) { - SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); - int valid_datatype = 0; + SDL_AudioFormat test_format; + SDL_bool iscapture = this->iscapture; + void *handle = this->handle; MMRESULT result; WAVEFORMATEX waveformat; UINT devId = WAVE_MAPPER; /* WAVE_MAPPER == choose system's default */ @@ -313,7 +314,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) if (this->spec.channels > 2) this->spec.channels = 2; /* !!! FIXME: is this right? */ - while ((!valid_datatype) && (test_format)) { + for (test_format = SDL_FirstAudioFormat(this->spec.format); test_format; test_format = SDL_NextAudioFormat()) { switch (test_format) { case AUDIO_U8: case AUDIO_S16: @@ -321,20 +322,17 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) case AUDIO_F32: this->spec.format = test_format; if (PrepWaveFormat(this, devId, &waveformat, iscapture)) { - valid_datatype = 1; - } else { - test_format = SDL_NextAudioFormat(); + break; } - break; - + continue; default: - test_format = SDL_NextAudioFormat(); - break; + continue; } + break; } - if (!valid_datatype) { - return SDL_SetError("Unsupported audio format"); + if (!test_format) { + return SDL_SetError("%s: Unsupported audio format", "winmm"); } /* Update the fragment size as size in bytes */ @@ -434,7 +432,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) return 0; /* Ready to go! */ } -static int +static SDL_bool WINMM_Init(SDL_AudioDriverImpl * impl) { /* Set the function pointers */ @@ -449,11 +447,11 @@ WINMM_Init(SDL_AudioDriverImpl * impl) impl->HasCaptureSupport = SDL_TRUE; - return 1; /* this audio target is available. */ + return SDL_TRUE; /* this audio target is available. */ } AudioBootStrap WINMM_bootstrap = { - "winmm", "Windows Waveform Audio", WINMM_Init, 0 + "winmm", "Windows Waveform Audio", WINMM_Init, SDL_FALSE }; #endif /* SDL_AUDIO_DRIVER_WINMM */ diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 4236835cf..dba9e5f87 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1009,6 +1009,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, j { SDL_LockMutex(Android_ActivityMutex); +#if SDL_VIDEO_OPENGL_EGL if (Android_Window) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); @@ -1021,6 +1022,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(JNIEnv *env, j /* GL Context handling is done in the event loop because this function is run from the Java thread */ } +#endif SDL_UnlockMutex(Android_ActivityMutex); } @@ -1051,10 +1053,12 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceDestroyed)(JNIEnv *env, } } +#if SDL_VIDEO_OPENGL_EGL if (data->egl_surface != EGL_NO_SURFACE) { SDL_EGL_DestroySurface(_this, data->egl_surface); data->egl_surface = EGL_NO_SURFACE; } +#endif if (data->native_window) { ANativeWindow_release(data->native_window); @@ -2126,6 +2130,15 @@ void Android_JNI_HapticStop(int device_id) /* See SDLActivity.java for constants. */ #define COMMAND_SET_KEEP_SCREEN_ON 5 + +int SDL_AndroidSendMessage(Uint32 command, int param) +{ + if (command >= 0x8000) { + return Android_JNI_SendMessage(command, param); + } + return -1; +} + /* sends message to be handled on the UI event dispatch thread */ int Android_JNI_SendMessage(int command, int param) { diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c index 3f0794736..bab5e88f3 100644 --- a/src/core/linux/SDL_fcitx.c +++ b/src/core/linux/SDL_fcitx.c @@ -339,11 +339,11 @@ SDL_Fcitx_Reset(void) } SDL_bool -SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { - Uint32 state = Fcitx_ModState(); + Uint32 mod_state = Fcitx_ModState(); Uint32 handled = SDL_FALSE; - Uint32 is_release = SDL_FALSE; + Uint32 is_release = (state == SDL_RELEASED); Uint32 event_time = 0; if (!fcitx_client.ic_path) { @@ -351,7 +351,7 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) } if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mod_state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) { if (handled) { SDL_Fcitx_UpdateTextRect(NULL); diff --git a/src/core/linux/SDL_fcitx.h b/src/core/linux/SDL_fcitx.h index f7884ea43..c3cea523d 100644 --- a/src/core/linux/SDL_fcitx.h +++ b/src/core/linux/SDL_fcitx.h @@ -31,7 +31,7 @@ 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 SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect); extern void SDL_Fcitx_PumpEvents(void); diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index a7bafda35..60af0ba29 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -503,15 +503,20 @@ SDL_IBus_Reset(void) } SDL_bool -SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { Uint32 result = 0; SDL_DBusContext *dbus = SDL_DBus_GetContext(); - + + if (IBus_CheckConnection(dbus)) { Uint32 mods = IBus_ModState(); + Uint32 ibus_keycode = keycode - 8; + if (state == SDL_RELEASED) { + mods |= (1 << 30); // IBUS_RELEASE_MASK + } if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &ibus_keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) { result = 0; } diff --git a/src/core/linux/SDL_ibus.h b/src/core/linux/SDL_ibus.h index 73a9f1b8b..71d1f2d30 100644 --- a/src/core/linux/SDL_ibus.h +++ b/src/core/linux/SDL_ibus.h @@ -41,7 +41,7 @@ extern void SDL_IBus_Reset(void); /* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to update its candidate list or change input methods. PumpEvents should be called some time after this, to recieve the TextInput / TextEditing event back. */ -extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); /* Update the position of IBus' candidate list. If rect is NULL then this will just reposition it relative to the focused window's new position. */ diff --git a/src/core/linux/SDL_ime.c b/src/core/linux/SDL_ime.c index 84c461f8b..9c0cb80f0 100644 --- a/src/core/linux/SDL_ime.c +++ b/src/core/linux/SDL_ime.c @@ -27,7 +27,7 @@ typedef SDL_bool (*_SDL_IME_Init)(void); typedef void (*_SDL_IME_Quit)(void); typedef void (*_SDL_IME_SetFocus)(SDL_bool); typedef void (*_SDL_IME_Reset)(void); -typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32); +typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32, Uint8 state); typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *); typedef void (*_SDL_IME_PumpEvents)(void); @@ -127,10 +127,10 @@ SDL_IME_Reset(void) } SDL_bool -SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { if (SDL_IME_ProcessKeyEvent_Real) - return SDL_IME_ProcessKeyEvent_Real(keysym, keycode); + return SDL_IME_ProcessKeyEvent_Real(keysym, keycode, state); return SDL_FALSE; } diff --git a/src/core/linux/SDL_ime.h b/src/core/linux/SDL_ime.h index a28a4b430..cc5b105f0 100644 --- a/src/core/linux/SDL_ime.h +++ b/src/core/linux/SDL_ime.h @@ -31,7 +31,7 @@ extern SDL_bool SDL_IME_Init(void); extern void SDL_IME_Quit(void); extern void SDL_IME_SetFocus(SDL_bool focused); extern void SDL_IME_Reset(void); -extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_IME_UpdateTextRect(SDL_Rect *rect); extern void SDL_IME_PumpEvents(void); diff --git a/src/core/openbsd/SDL_wscons_kbd.c b/src/core/openbsd/SDL_wscons_kbd.c index bd19d1517..121867d6a 100644 --- a/src/core/openbsd/SDL_wscons_kbd.c +++ b/src/core/openbsd/SDL_wscons_kbd.c @@ -394,6 +394,7 @@ typedef struct { unsigned int text_len; keysym_t composebuffer[2]; unsigned char composelen; + int type; } SDL_WSCONS_input_data; static SDL_WSCONS_input_data* inputs[4] = {NULL, NULL, NULL, NULL}; @@ -432,6 +433,7 @@ static SDL_WSCONS_input_data* SDL_WSCONS_Init_Keyboard(const char* dev) RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GETLEDS, &input->ledstate)); input->origledstate = input->ledstate; RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GETENCODING, &input->encoding)); + RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_GTYPE, &input->type)); #ifdef WSKBDIO_SETVERSION RETIFIOCTLERR(ioctl(input->fd, WSKBDIO_SETVERSION, &version)); #endif @@ -725,7 +727,12 @@ static void updateKeyboard(SDL_WSCONS_input_data* input) } break; } - Translate_to_keycode(input, type, events[i].value); + + if (input->type == WSKBD_TYPE_USB && events[i].value <= 0xE7) + SDL_SendKeyboardKey(type == WSCONS_EVENT_KEY_DOWN ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)events[i].value); + else + Translate_to_keycode(input, type, events[i].value); + if (type == WSCONS_EVENT_KEY_UP) continue; if (IS_ALTGR_MODE && !IS_CONTROL_HELD) diff --git a/src/core/os2/geniconv/geniconv.c b/src/core/os2/geniconv/geniconv.c index d4f3fa196..5976fe79f 100644 --- a/src/core/os2/geniconv/geniconv.c +++ b/src/core/os2/geniconv/geniconv.c @@ -46,17 +46,17 @@ extern size_t _System os2_iconv (iconv_t cd, char **outbuf, size_t *outbytesleft); extern int _System os2_iconv_close (iconv_t cd); -/* Functions pointers types */ +/* Functions pointers */ typedef iconv_t (_System *FNICONV_OPEN)(const char*, const char*); typedef size_t (_System *FNICONV) (iconv_t, char **, size_t *, char **, size_t *); typedef int (_System *FNICONV_CLOSE)(iconv_t); -/* Used DLL module handle */ static HMODULE hmIconv = NULLHANDLE; -/* Functions pointers */ -static FNICONV_OPEN fn_iconv_open = NULL; -static FNICONV fn_iconv = NULL; -static FNICONV_CLOSE fn_iconv_close = NULL; +static FNICONV_OPEN fn_iconv_open = os2_iconv_open; +static FNICONV fn_iconv = os2_iconv; +static FNICONV_CLOSE fn_iconv_close = os2_iconv_close; + +static int geniconv_init = 0; static BOOL _loadDLL(const char *dllname, @@ -102,10 +102,12 @@ static BOOL _loadDLL(const char *dllname, static void _init(void) { - if (fn_iconv_open != NULL) { + if (geniconv_init) { return; /* Already initialized */ } + geniconv_init = 1; + /* Try to load kiconv.dll, iconv2.dll or iconv.dll */ if (!_loadDLL("KICONV", "_libiconv_open", "_libiconv", "_libiconv_close") && !_loadDLL("ICONV2", "_libiconv_open", "_libiconv", "_libiconv_close") && @@ -123,16 +125,19 @@ static void _init(void) * ---------------- */ -/* Non-standard function for iconv to unload the used dynamic library */ +/* function to unload the used iconv dynamic library */ void libiconv_clean(void) { + geniconv_init = 0; + + /* reset the function pointers. */ + fn_iconv_open = os2_iconv_open; + fn_iconv = os2_iconv; + fn_iconv_close = os2_iconv_close; + if (hmIconv != NULLHANDLE) { DosFreeModule(hmIconv); hmIconv = NULLHANDLE; - - fn_iconv_open = NULL; - fn_iconv = NULL; - fn_iconv_close = NULL; } } diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index 2bdf878dd..50e128fcc 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -25,7 +25,15 @@ #include "SDL_windows.h" #include "SDL_error.h" -#include /* for CoInitialize/CoUninitialize (Win32 only) */ +#include /* for CoInitialize/CoUninitialize (Win32 only) */ +#if defined(HAVE_ROAPI_H) +#include /* For RoInitialize/RoUninitialize (Win32 only) */ +#else +typedef enum RO_INIT_TYPE { + RO_INIT_SINGLETHREADED = 0, + RO_INIT_MULTITHREADED = 1 +} RO_INIT_TYPE; +#endif #ifndef _WIN32_WINNT_VISTA #define _WIN32_WINNT_VISTA 0x0600 @@ -37,6 +45,10 @@ #define _WIN32_WINNT_WIN8 0x0602 #endif +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + /* Sets an error message based on an HRESULT */ int @@ -108,6 +120,65 @@ WIN_CoUninitialize(void) #endif } +#ifndef __WINRT__ +void * +WIN_LoadComBaseFunction(const char *name) +{ + static SDL_bool s_bLoaded; + static HMODULE s_hComBase; + + if (!s_bLoaded) { + s_hComBase = LoadLibraryEx(TEXT("combase.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + s_bLoaded = SDL_TRUE; + } + if (s_hComBase) { + return GetProcAddress(s_hComBase, name); + } else { + return NULL; + } +} +#endif + +HRESULT +WIN_RoInitialize(void) +{ +#ifdef __WINRT__ + return S_OK; +#else + typedef HRESULT (WINAPI *RoInitialize_t)(RO_INIT_TYPE initType); + RoInitialize_t RoInitializeFunc = (RoInitialize_t)WIN_LoadComBaseFunction("RoInitialize"); + if (RoInitializeFunc) { + /* RO_INIT_SINGLETHREADED is equivalent to COINIT_APARTMENTTHREADED */ + HRESULT hr = RoInitializeFunc(RO_INIT_SINGLETHREADED); + if (hr == RPC_E_CHANGED_MODE) { + hr = RoInitializeFunc(RO_INIT_MULTITHREADED); + } + + /* S_FALSE means success, but someone else already initialized. */ + /* You still need to call RoUninitialize in this case! */ + if (hr == S_FALSE) { + return S_OK; + } + + return hr; + } else { + return E_NOINTERFACE; + } +#endif +} + +void +WIN_RoUninitialize(void) +{ +#ifndef __WINRT__ + typedef void (WINAPI *RoUninitialize_t)(void); + RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize"); + if (RoUninitializeFunc) { + RoUninitializeFunc(); + } +#endif +} + #ifndef __WINRT__ static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h index 221c3bd87..917a8256f 100644 --- a/src/core/windows/SDL_windows.h +++ b/src/core/windows/SDL_windows.h @@ -63,10 +63,19 @@ extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr); /* Sets an error message based on GetLastError(). Always return -1. */ extern int WIN_SetError(const char *prefix); +#if !defined(__WINRT__) +/* Load a function from combase.dll */ +void *WIN_LoadComBaseFunction(const char *name); +#endif + /* Wrap up the oddities of CoInitialize() into a common function. */ extern HRESULT WIN_CoInitialize(void); extern void WIN_CoUninitialize(void); +/* Wrap up the oddities of RoInitialize() into a common function. */ +extern HRESULT WIN_RoInitialize(void); +extern void WIN_RoUninitialize(void); + /* Returns SDL_TRUE if we're running on Windows Vista and newer */ extern BOOL WIN_IsWindowsVistaOrGreater(void); diff --git a/src/core/winrt/SDL_winrtapp_xaml.cpp b/src/core/winrt/SDL_winrtapp_xaml.cpp index b64c50591..69716e11d 100644 --- a/src/core/winrt/SDL_winrtapp_xaml.cpp +++ b/src/core/winrt/SDL_winrtapp_xaml.cpp @@ -115,7 +115,7 @@ SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAs // Make sure we have a valid XAML element (to draw onto): if ( ! backgroundPanelAsIInspectable) { - return SDL_SetError("'backgroundPanelAsIInspectable' can't be NULL"); + return SDL_InvalidParamError("backgroundPanelAsIInspectable"); } Platform::Object ^ backgroundPanel = reinterpret_cast((IInspectable *) backgroundPanelAsIInspectable); diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 53bb4d4f6..526513ad5 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -855,3 +855,13 @@ #define SDL_GameControllerHasRumbleTriggers SDL_GameControllerHasRumbleTriggers_REAL #define SDL_hid_ble_scan SDL_hid_ble_scan_REAL #define SDL_PremultiplyAlpha SDL_PremultiplyAlpha_REAL +#define SDL_AndroidSendMessage SDL_AndroidSendMessage_REAL +#define SDL_GetTouchName SDL_GetTouchName_REAL +#define SDL_ClearComposition SDL_ClearComposition_REAL +#define SDL_IsTextInputShown SDL_IsTextInputShown_REAL +#define SDL_HasIntersectionF SDL_HasIntersectionF_REAL +#define SDL_IntersectFRect SDL_IntersectFRect_REAL +#define SDL_UnionFRect SDL_UnionFRect_REAL +#define SDL_EncloseFPoints SDL_EncloseFPoints_REAL +#define SDL_IntersectFRectAndLine SDL_IntersectFRectAndLine_REAL +#define SDL_RenderGetWindow SDL_RenderGetWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 000cde803..22bf870d9 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -924,3 +924,15 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasRumble,(SDL_GameController *a),(a) SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasRumbleTriggers,(SDL_GameController *a),(a),return) SDL_DYNAPI_PROC(void,SDL_hid_ble_scan,(SDL_bool a),(a),) SDL_DYNAPI_PROC(int,SDL_PremultiplyAlpha,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return) +#ifdef __ANDROID__ +SDL_DYNAPI_PROC(int,SDL_AndroidSendMessage,(Uint32 a, int b),(a,b),return) +#endif +SDL_DYNAPI_PROC(const char*,SDL_GetTouchName,(int a),(a),return) +SDL_DYNAPI_PROC(void,SDL_ClearComposition,(void),(),) +SDL_DYNAPI_PROC(SDL_bool,SDL_IsTextInputShown,(void),(),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_HasIntersectionF,(const SDL_FRect *a, const SDL_FRect *b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),return) +SDL_DYNAPI_PROC(void,SDL_UnionFRect,(const SDL_FRect *a, const SDL_FRect *b, SDL_FRect *c),(a,b,c),) +SDL_DYNAPI_PROC(SDL_bool,SDL_EncloseFPoints,(const SDL_FPoint *a, int b, const SDL_FRect *c, SDL_FRect *d),(a,b,c,d),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_IntersectFRectAndLine,(const SDL_FRect *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return) +SDL_DYNAPI_PROC(SDL_Window*,SDL_RenderGetWindow,(SDL_Renderer *a),(a),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 9bea36f9c..b006dc252 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -35,7 +35,7 @@ #include "SDL_syswm.h" #undef SDL_PRIs64 -#ifdef __WIN32__ +#if defined(__WIN32__) && !defined(__CYGWIN__) #define SDL_PRIs64 "I64d" #else #define SDL_PRIs64 "lld" @@ -206,11 +206,28 @@ SDL_LogEvent(const SDL_Event *event) SDL_EVENT_CASE(SDL_APP_DIDENTERBACKGROUND) break; SDL_EVENT_CASE(SDL_APP_WILLENTERFOREGROUND) break; SDL_EVENT_CASE(SDL_APP_DIDENTERFOREGROUND) break; + SDL_EVENT_CASE(SDL_LOCALECHANGED) break; SDL_EVENT_CASE(SDL_KEYMAPCHANGED) break; SDL_EVENT_CASE(SDL_CLIPBOARDUPDATE) break; SDL_EVENT_CASE(SDL_RENDER_TARGETS_RESET) break; SDL_EVENT_CASE(SDL_RENDER_DEVICE_RESET) break; + SDL_EVENT_CASE(SDL_DISPLAYEVENT) { + char name2[64]; + switch (event->display.event) { + case SDL_DISPLAYEVENT_NONE: SDL_strlcpy(name2, "SDL_DISPLAYEVENT_NONE (THIS IS PROBABLY A BUG!)", sizeof(name2)); break; + #define SDL_DISPLAYEVENT_CASE(x) case x: SDL_strlcpy(name2, #x, sizeof (name2)); break + SDL_DISPLAYEVENT_CASE(SDL_DISPLAYEVENT_ORIENTATION); + SDL_DISPLAYEVENT_CASE(SDL_DISPLAYEVENT_CONNECTED); + SDL_DISPLAYEVENT_CASE(SDL_DISPLAYEVENT_DISCONNECTED); + #undef SDL_DISPLAYEVENT_CASE + default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)", sizeof(name2)); break; + } + SDL_snprintf(details, sizeof (details), " (timestamp=%u display=%u event=%s data1=%d)", + (uint) event->display.timestamp, (uint) event->display.display, name2, (int) event->display.data1); + break; + } + SDL_EVENT_CASE(SDL_WINDOWEVENT) { char name2[64]; switch(event->window.event) { @@ -232,6 +249,8 @@ SDL_LogEvent(const SDL_Event *event) SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_CLOSE); SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_TAKE_FOCUS); SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_HIT_TEST); + SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_ICCPROF_CHANGED); + SDL_WINDOWEVENT_CASE(SDL_WINDOWEVENT_DISPLAY_CHANGED); #undef SDL_WINDOWEVENT_CASE default: SDL_strlcpy(name2, "UNKNOWN (bug? fixme?)", sizeof (name2)); break; } @@ -660,12 +679,12 @@ static int SDL_PeepEventsInternal(SDL_Event * events, int numevents, SDL_eventaction action, Uint32 minType, Uint32 maxType, SDL_bool include_sentinel) { - int i, used; + int i, used, sentinels_expected = 0; /* Don't look after we've quit */ if (!SDL_AtomicGet(&SDL_EventQ.active)) { /* We get a few spurious events at shutdown, so don't warn then */ - if (action != SDL_ADDEVENT) { + if (action == SDL_GETEVENT) { SDL_SetError("The event system has been shut down"); } return (-1); @@ -723,8 +742,15 @@ SDL_PeepEventsInternal(SDL_Event * events, int numevents, SDL_eventaction action } if (type == SDL_POLLSENTINEL) { /* Special handling for the sentinel event */ - if (!include_sentinel || SDL_AtomicGet(&SDL_sentinel_pending) > 0) { - /* Skip it, we don't want to include it or there's another one pending */ + if (!include_sentinel) { + /* Skip it, we don't want to include it */ + continue; + } + if (!events || action != SDL_GETEVENT) { + ++sentinels_expected; + } + if (SDL_AtomicGet(&SDL_sentinel_pending) > sentinels_expected) { + /* Skip it, there's another one pending */ continue; } } @@ -891,7 +917,11 @@ SDL_WaitEventTimeout_Device(_THIS, SDL_Window *wakeup_window, SDL_Event * event, c) Periodic processing that takes place in some platform PumpEvents() functions happens d) Signals received in WaitEventTimeout() are turned into SDL events */ - SDL_PumpEventsInternal(SDL_TRUE); + /* We only want a single sentinel in the queue. We could get more than one if event is NULL, + * since the SDL_PeepEvents() call below won't remove it in that case. + */ + SDL_bool add_sentinel = (SDL_AtomicGet(&SDL_sentinel_pending) == 0) ? SDL_TRUE : SDL_FALSE; + SDL_PumpEventsInternal(add_sentinel); if (!_this->wakeup_lock || SDL_LockMutex(_this->wakeup_lock) == 0) { int status = SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT); @@ -987,6 +1017,7 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout) SDL_Window *wakeup_window; Uint32 start, expiration; SDL_bool include_sentinel = (timeout == 0) ? SDL_TRUE : SDL_FALSE; + int result; /* If there isn't a poll sentinel event pending, pump events and add one */ if (SDL_AtomicGet(&SDL_sentinel_pending) == 0) { @@ -994,33 +1025,34 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout) } /* First check for existing events */ - switch (SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT, include_sentinel)) { - case -1: + result = SDL_PeepEventsInternal(event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT, include_sentinel); + if (result < 0) { return 0; - case 0: + } + if (include_sentinel) { + if (event) { + if (event->type == SDL_POLLSENTINEL) { + /* Reached the end of a poll cycle, and not willing to wait */ + return 0; + } + } else { + /* Need to peek the next event to check for sentinel */ + SDL_Event dummy; + + if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT, SDL_TRUE) && + dummy.type == SDL_POLLSENTINEL) { + SDL_PeepEventsInternal(&dummy, 1, SDL_GETEVENT, SDL_POLLSENTINEL, SDL_POLLSENTINEL, SDL_TRUE); + /* Reached the end of a poll cycle, and not willing to wait */ + return 0; + } + } + } + if (result == 0) { if (timeout == 0) { /* No events available, and not willing to wait */ return 0; } - break; - default: - if (include_sentinel) { - if (event) { - if (event->type == SDL_POLLSENTINEL) { - /* Reached the end of a poll cycle, and not willing to wait */ - return 0; - } - } else { - /* Need to peek the next event to check for sentinel */ - SDL_Event dummy; - - if (SDL_PeepEventsInternal(&dummy, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT, SDL_TRUE) && - dummy.type == SDL_POLLSENTINEL) { - /* Reached the end of a poll cycle, and not willing to wait */ - return 0; - } - } - } + } else { /* Has existing events */ return 1; } @@ -1232,8 +1264,7 @@ SDL_FilterEvents(SDL_EventFilter filter, void *userdata) Uint8 SDL_EventState(Uint32 type, int state) { - const SDL_bool isdnd = ((state == SDL_DISABLE) || (state == SDL_ENABLE)) && - ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT)); + const SDL_bool isde = (state == SDL_DISABLE) || (state == SDL_ENABLE); Uint8 current_state; Uint8 hi = ((type >> 8) & 0xff); Uint8 lo = (type & 0xff); @@ -1245,44 +1276,32 @@ SDL_EventState(Uint32 type, int state) current_state = SDL_ENABLE; } - if (state != current_state) - { - switch (state) { - case SDL_DISABLE: + if (isde && state != current_state) { + if (state == SDL_DISABLE) { /* Disable this event type and discard pending events */ if (!SDL_disabled_events[hi]) { SDL_disabled_events[hi] = (SDL_DisabledEventBlock*) SDL_calloc(1, sizeof(SDL_DisabledEventBlock)); - if (!SDL_disabled_events[hi]) { - /* Out of memory, nothing we can do... */ - break; - } } - SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31)); - SDL_FlushEvent(type); - break; - case SDL_ENABLE: + /* Out of memory, nothing we can do... */ + if (SDL_disabled_events[hi]) { + SDL_disabled_events[hi]->bits[lo/32] |= (1 << (lo&31)); + SDL_FlushEvent(type); + } + } else { // state == SDL_ENABLE SDL_disabled_events[hi]->bits[lo/32] &= ~(1 << (lo&31)); - break; - default: - /* Querying state... */ - break; } #if !SDL_JOYSTICK_DISABLED - if (state == SDL_DISABLE || state == SDL_ENABLE) { - SDL_CalculateShouldUpdateJoysticks(); - } + SDL_CalculateShouldUpdateJoysticks(); #endif #if !SDL_SENSOR_DISABLED - if (state == SDL_DISABLE || state == SDL_ENABLE) { - SDL_CalculateShouldUpdateSensors(); - } + SDL_CalculateShouldUpdateSensors(); #endif } /* turn off drag'n'drop support if we've disabled the events. This might change some UI details at the OS level. */ - if (isdnd) { + if (isde && ((type == SDL_DROPFILE) || (type == SDL_DROPTEXT))) { SDL_ToggleDragAndDropSupport(); } diff --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 3400ca0c5..14e79ca49 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -638,6 +638,7 @@ SDL_SetKeyboardFocus(SDL_Window * window) /* old window must lose an existing mouse capture. */ if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) { SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */ + SDL_UpdateMouseCapture(SDL_TRUE); SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE)); } @@ -867,10 +868,14 @@ SDL_SendKeyboardText(const char *text) posted = 0; if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) { SDL_Event event; + size_t i = 0, length = SDL_strlen(text); + event.text.type = SDL_TEXTINPUT; event.text.windowID = keyboard->focus ? keyboard->focus->id : 0; - SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text)); - posted = (SDL_PushEvent(&event) > 0); + while (i < length) { + i += SDL_utf8strlcpy(event.text.text, text + i, SDL_arraysize(event.text.text)); + posted |= (SDL_PushEvent(&event) > 0); + } } return (posted); } @@ -890,6 +895,22 @@ SDL_SendEditingText(const char *text, int start, int length) event.edit.start = start; event.edit.length = length; SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text)); + + if (SDL_GetHintBoolean(SDL_HINT_IME_SUPPORT_EXTENDED_TEXT, SDL_FALSE) && + SDL_strlen(text) > SDL_arraysize(event.text.text)) { + event.editExt.type = SDL_TEXTEDITING_EXT; + event.editExt.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.editExt.text = text ? SDL_strdup(text) : NULL; + event.editExt.start = start; + event.editExt.length = length; + } else { + event.edit.type = SDL_TEXTEDITING; + event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0; + event.edit.start = start; + event.edit.length = length; + SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text)); + } + posted = (SDL_PushEvent(&event) > 0); } return (posted); diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index c737d3027..f2e24eb4c 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -109,6 +109,28 @@ SDL_TouchMouseEventsChanged(void *userdata, const char *name, const char *oldVal mouse->touch_mouse_events = SDL_GetStringBoolean(hint, SDL_TRUE); } +#if defined(__vita__) +static void SDLCALL +SDL_VitaTouchMouseDeviceChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + if (hint) { + switch(*hint) { + default: + case '0': + mouse->vita_touch_mouse_device = 0; + break; + case '1': + mouse->vita_touch_mouse_device = 1; + break; + case '2': + mouse->vita_touch_mouse_device = 2; + break; + } + } +} +#endif + static void SDLCALL SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint) { @@ -127,6 +149,18 @@ SDL_MouseTouchEventsChanged(void *userdata, const char *name, const char *oldVal } } +static void SDLCALL +SDL_MouseAutoCaptureChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_Mouse *mouse = (SDL_Mouse *)userdata; + SDL_bool auto_capture = SDL_GetStringBoolean(hint, SDL_TRUE); + + if (auto_capture != mouse->auto_capture) { + mouse->auto_capture = auto_capture; + SDL_UpdateMouseCapture(SDL_FALSE); + } +} + /* Public functions */ int SDL_MouseInit(void) @@ -150,9 +184,17 @@ SDL_MouseInit(void) SDL_AddHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, SDL_TouchMouseEventsChanged, mouse); +#if defined(__vita__) + SDL_AddHintCallback(SDL_HINT_VITA_TOUCH_MOUSE_DEVICE, + SDL_VitaTouchMouseDeviceChanged, mouse); +#endif + SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, SDL_MouseTouchEventsChanged, mouse); + SDL_AddHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); + mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */ mouse->cursor_shown = SDL_TRUE; @@ -248,23 +290,10 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_ } } -/* Linux doesn't give you mouse events outside your window unless you grab - the pointer. - - Windows doesn't give you mouse events outside your window unless you call - SetCapture(). - - Both of these are slightly scary changes, so for now we'll punt and if the - mouse leaves the window you'll lose mouse focus and reset button state. -*/ -#ifdef SUPPORT_DRAG_OUTSIDE_WINDOW - if (!inWindow && !buttonstate) { -#else if (!inWindow) { -#endif if (window == mouse->focus) { #ifdef DEBUG_MOUSE - printf("Mouse left window, synthesizing move & focus lost event\n"); + SDL_Log("Mouse left window, synthesizing move & focus lost event\n"); #endif if (send_mouse_motion) { SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y); @@ -276,7 +305,7 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_ if (window != mouse->focus) { #ifdef DEBUG_MOUSE - printf("Mouse entered window, synthesizing focus gain & move event\n"); + SDL_Log("Mouse entered window, synthesizing focus gain & move event\n"); #endif SDL_SetMouseFocus(window); if (send_mouse_motion) { @@ -378,14 +407,12 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ /* Ignore relative motion when first positioning the mouse */ if (!mouse->has_position) { - xrel = 0; - yrel = 0; mouse->x = x; mouse->y = y; mouse->has_position = SDL_TRUE; } else if (!xrel && !yrel) { /* Drop events that don't change state */ #ifdef DEBUG_MOUSE - printf("Mouse event didn't change state - dropped!\n"); + SDL_Log("Mouse event didn't change state - dropped!\n"); #endif return 0; } @@ -533,7 +560,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state Uint32 type; Uint32 buttonstate; SDL_MouseInputSource *source; - + source = GetMouseInputSource(mouse, mouseID); if (!source) { return 0; @@ -633,6 +660,11 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE); } + /* Automatically capture the mouse while buttons are pressed */ + if (mouse->auto_capture) { + SDL_UpdateMouseCapture(SDL_FALSE); + } + return posted; } @@ -728,6 +760,7 @@ SDL_MouseQuit(void) if (mouse->CaptureMouse) { SDL_CaptureMouse(SDL_FALSE); + SDL_UpdateMouseCapture(SDL_TRUE); } SDL_SetRelativeMouseMode(SDL_FALSE); SDL_ShowCursor(1); @@ -758,11 +791,26 @@ SDL_MouseQuit(void) } mouse->num_clickstates = 0; + SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_TIME, + SDL_MouseDoubleClickTimeChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, + SDL_MouseDoubleClickRadiusChanged, mouse); + SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE, SDL_MouseNormalSpeedScaleChanged, mouse); SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE, SDL_MouseRelativeSpeedScaleChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_TOUCH_MOUSE_EVENTS, + SDL_TouchMouseEventsChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS, + SDL_MouseTouchEventsChanged, mouse); + + SDL_DelHintCallback(SDL_HINT_MOUSE_AUTO_CAPTURE, + SDL_MouseAutoCaptureChanged, mouse); } Uint32 @@ -917,6 +965,8 @@ SDL_SetRelativeMouseMode(SDL_bool enabled) if (!enabled) { SDL_WarpMouseInWindow(focusWindow, mouse->x, mouse->y); } + + SDL_UpdateMouseCapture(SDL_FALSE); } if (!enabled) { @@ -939,40 +989,60 @@ SDL_GetRelativeMouseMode() } int -SDL_CaptureMouse(SDL_bool enabled) +SDL_UpdateMouseCapture(SDL_bool force_release) { SDL_Mouse *mouse = SDL_GetMouse(); - SDL_Window *focusWindow; - SDL_bool isCaptured; + SDL_Window *capture_window = NULL; if (!mouse->CaptureMouse) { - return SDL_Unsupported(); + return 0; } - focusWindow = SDL_GetKeyboardFocus(); - - isCaptured = focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE); - if (isCaptured == enabled) { - return 0; /* already done! */ + if (!force_release) { + if (mouse->capture_desired || (mouse->auto_capture && SDL_GetMouseState(NULL, NULL) != 0)) { + if (!mouse->relative_mode) { + capture_window = SDL_GetKeyboardFocus(); + } + } } - if (enabled) { - if (!focusWindow) { - return SDL_SetError("No window has focus"); - } else if (mouse->CaptureMouse(focusWindow) == -1) { - return -1; /* CaptureMouse() should call SetError */ + if (capture_window != mouse->capture_window) { + if (mouse->capture_window) { + mouse->CaptureMouse(NULL); + mouse->capture_window->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; + mouse->capture_window = NULL; } - focusWindow->flags |= SDL_WINDOW_MOUSE_CAPTURE; - } else { - if (mouse->CaptureMouse(NULL) == -1) { - return -1; /* CaptureMouse() should call SetError */ + + if (capture_window) { + if (mouse->CaptureMouse(capture_window) < 0) { + /* CaptureMouse() will have set an error */ + return -1; + } + capture_window->flags |= SDL_WINDOW_MOUSE_CAPTURE; } - focusWindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; - } + mouse->capture_window = capture_window; + } return 0; } +int +SDL_CaptureMouse(SDL_bool enabled) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + if (!mouse->CaptureMouse) { + return SDL_Unsupported(); + } + + if (enabled && SDL_GetKeyboardFocus() == NULL) { + return SDL_SetError("No window has focus"); + } + mouse->capture_desired = enabled; + + return SDL_UpdateMouseCapture(SDL_FALSE); +} + SDL_Cursor * SDL_CreateCursor(const Uint8 * data, const Uint8 * mask, int w, int h, int hot_x, int hot_y) @@ -1030,7 +1100,7 @@ SDL_CreateColorCursor(SDL_Surface *surface, int hot_x, int hot_y) SDL_Cursor *cursor; if (!surface) { - SDL_SetError("Passed NULL cursor surface"); + SDL_InvalidParamError("surface"); return NULL; } diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index 2da7978ea..4f2984d09 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -100,6 +100,13 @@ typedef struct SDL_bool touch_mouse_events; SDL_bool mouse_touch_events; SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */ +#if defined(__vita__) + Uint8 vita_touch_mouse_device; +#endif + SDL_bool auto_capture; + SDL_bool capture_desired; + SDL_Window *capture_window; + SDL_MouseWheelMomentumPhase scroll_momentum_phase; /* Data for input source state */ @@ -132,6 +139,9 @@ extern void SDL_SetDefaultCursor(SDL_Cursor * cursor); /* Set the mouse focus window */ extern void SDL_SetMouseFocus(SDL_Window * window); +/* Update the mouse capture window */ +extern int SDL_UpdateMouseCapture(SDL_bool force_release); + /* Send a mouse motion event */ extern int SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int x, int y); diff --git a/src/events/SDL_touch.c b/src/events/SDL_touch.c index 764917462..2dbe09c2e 100644 --- a/src/events/SDL_touch.c +++ b/src/events/SDL_touch.c @@ -63,6 +63,16 @@ SDL_GetTouchDevice(int index) return SDL_touchDevices[index]->id; } +const char* +SDL_GetTouchName(int index) +{ + if (index < 0 || index >= SDL_num_touch) { + SDL_SetError("Unknown touch device"); + return NULL; + } + return SDL_touchDevices[index]->name; +} + static int SDL_GetTouchIndex(SDL_TouchID id) { @@ -185,6 +195,7 @@ SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name) SDL_touchDevices[index]->num_fingers = 0; SDL_touchDevices[index]->max_fingers = 0; SDL_touchDevices[index]->fingers = NULL; + SDL_touchDevices[index]->name = SDL_strdup(name ? name : ""); /* Record this touch device for gestures */ /* We could do this on the fly in the gesture code if we wanted */ @@ -254,8 +265,13 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window, #if SYNTHESIZE_TOUCH_TO_MOUSE /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */ + /* SDL_HINT_VITA_TOUCH_MOUSE_DEVICE: controlling which touchpad should generate synthetic mouse events, PSVita-only */ { +#if defined(__vita__) + if (mouse->touch_mouse_events && ((mouse->vita_touch_mouse_device == id) || (mouse->vita_touch_mouse_device == 2)) ) { +#else if (mouse->touch_mouse_events) { +#endif /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */ if (id != SDL_MOUSE_TOUCHID) { if (window) { @@ -302,8 +318,9 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window, finger = SDL_GetFinger(touch, fingerid); if (down) { if (finger) { - /* This finger is already down */ - return 0; + /* This finger is already down. + Assume the finger-up for the previous touch was lost, and send it. */ + SDL_SendTouch(id, fingerid, window, SDL_FALSE, x, y, pressure); } if (SDL_AddFinger(touch, fingerid, x, y, pressure) < 0) { @@ -451,6 +468,7 @@ SDL_DelTouch(SDL_TouchID id) SDL_free(touch->fingers[i]); } SDL_free(touch->fingers); + SDL_free(touch->name); SDL_free(touch); SDL_num_touch--; diff --git a/src/events/SDL_touch_c.h b/src/events/SDL_touch_c.h index 5a1d1c733..7c0eb60c3 100644 --- a/src/events/SDL_touch_c.h +++ b/src/events/SDL_touch_c.h @@ -31,6 +31,7 @@ typedef struct SDL_Touch int num_fingers; int max_fingers; SDL_Finger** fingers; + char *name; } SDL_Touch; diff --git a/src/events/SDL_windowevents.c b/src/events/SDL_windowevents.c index 16706a448..c65b087b6 100644 --- a/src/events/SDL_windowevents.c +++ b/src/events/SDL_windowevents.c @@ -25,7 +25,7 @@ #include "SDL_events.h" #include "SDL_events_c.h" #include "SDL_mouse_c.h" - +#include "SDL_hints.h" static int SDLCALL RemovePendingSizeChangedAndResizedEvents(void * userdata, SDL_Event *event) @@ -213,8 +213,9 @@ SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1, if (windowevent == SDL_WINDOWEVENT_CLOSE) { if ( !window->prev && !window->next ) { - /* This is the last window in the list so send the SDL_QUIT event */ - SDL_SendQuit(); + if (SDL_GetHintBoolean(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, SDL_TRUE)) { + SDL_SendQuit(); /* This is the last window in the list so send the SDL_QUIT event */ + } } } diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index 5187fae04..670d4dd9a 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -833,7 +833,7 @@ SDL_RWFromFile(const char *file, const char *mode) rwops->type = SDL_RWOPS_VITAFILE; #elif HAVE_STDIO_H { - #ifdef __APPLE__ + #if __APPLE__ && !SDL_FILE_DISABLED // TODO: add dummy? FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode); #elif __WINRT__ FILE *fp = NULL; diff --git a/src/filesystem/os2/SDL_sysfilesystem.c b/src/filesystem/os2/SDL_sysfilesystem.c index e8050cbec..3203f0b3a 100644 --- a/src/filesystem/os2/SDL_sysfilesystem.c +++ b/src/filesystem/os2/SDL_sysfilesystem.c @@ -31,6 +31,7 @@ #define INCL_DOSFILEMGR #define INCL_DOSPROCESS +#define INCL_DOSMODULEMGR #define INCL_DOSERRORS #include @@ -42,30 +43,31 @@ SDL_GetBasePath(void) PPIB pib; ULONG ulRC = DosGetInfoBlocks(&tib, &pib); PCHAR pcEnd; - ULONG cbResult; CHAR acBuf[CCHMAXPATH]; if (ulRC != NO_ERROR) { - debug_os2("DosGetInfoBlocks() failed, rc = %u", ulRC); + SDL_SetError("Can't get process information block (E%lu)", ulRC); return NULL; } - pcEnd = SDL_strrchr(pib->pib_pchcmd, '\\'); + ulRC = DosQueryModuleName(pib->pib_hmte, sizeof(acBuf), acBuf); + if (ulRC != NO_ERROR) { + SDL_SetError("Can't query the module name (E%lu)", ulRC); + return NULL; + } + + pcEnd = SDL_strrchr(acBuf, '\\'); if (pcEnd != NULL) - pcEnd++; + pcEnd[1] = '\0'; else { - if (pib->pib_pchcmd[1] == ':') - pcEnd = &pib->pib_pchcmd[2]; + if (acBuf[1] == ':') /* e.g. "C:FOO" */ + acBuf[2] = '\0'; else { - SDL_SetError("No path in pib->pib_pchcmd"); + SDL_SetError("No path in module name"); return NULL; } } - cbResult = pcEnd - pib->pib_pchcmd; - SDL_memcpy(acBuf, pib->pib_pchcmd, cbResult); - acBuf[cbResult] = '\0'; - return OS2_SysToUTF8(acBuf); } diff --git a/src/filesystem/windows/SDL_sysfilesystem.c b/src/filesystem/windows/SDL_sysfilesystem.c index d50fb511b..b57546c67 100644 --- a/src/filesystem/windows/SDL_sysfilesystem.c +++ b/src/filesystem/windows/SDL_sysfilesystem.c @@ -35,39 +35,23 @@ char * SDL_GetBasePath(void) { - typedef DWORD (WINAPI *GetModuleFileNameExW_t)(HANDLE, HMODULE, LPWSTR, DWORD); - GetModuleFileNameExW_t pGetModuleFileNameExW; DWORD buflen = 128; WCHAR *path = NULL; - HANDLE psapi = LoadLibrary(TEXT("psapi.dll")); char *retval = NULL; DWORD len = 0; int i; - if (!psapi) { - WIN_SetError("Couldn't load psapi.dll"); - return NULL; - } - - pGetModuleFileNameExW = (GetModuleFileNameExW_t)GetProcAddress(psapi, "GetModuleFileNameExW"); - if (!pGetModuleFileNameExW) { - WIN_SetError("Couldn't find GetModuleFileNameExW"); - FreeLibrary(psapi); - return NULL; - } - while (SDL_TRUE) { void *ptr = SDL_realloc(path, buflen * sizeof (WCHAR)); if (!ptr) { SDL_free(path); - FreeLibrary(psapi); SDL_OutOfMemory(); return NULL; } path = (WCHAR *) ptr; - len = pGetModuleFileNameExW(GetCurrentProcess(), NULL, path, buflen); + len = GetModuleFileNameW(NULL, path, buflen); /* if it truncated, then len >= buflen - 1 */ /* if there was enough room (or failure), len < buflen - 1 */ if (len < buflen - 1) { @@ -78,8 +62,6 @@ SDL_GetBasePath(void) buflen *= 2; } - FreeLibrary(psapi); - if (len == 0) { SDL_free(path); WIN_SetError("Couldn't locate our .exe"); diff --git a/src/haptic/windows/SDL_dinputhaptic.c b/src/haptic/windows/SDL_dinputhaptic.c index 0ae71f4a9..f10c369af 100644 --- a/src/haptic/windows/SDL_dinputhaptic.c +++ b/src/haptic/windows/SDL_dinputhaptic.c @@ -492,8 +492,7 @@ SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) ++index; } - SDL_SetError("Couldn't find joystick in haptic device list"); - return -1; + return SDL_SetError("Couldn't find joystick in haptic device list"); } void @@ -959,8 +958,7 @@ SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SD REFGUID type = SDL_SYS_HapticEffectType(base); if (type == NULL) { - SDL_SetError("Haptic: Unknown effect type."); - return -1; + return SDL_SetError("Haptic: Unknown effect type."); } /* Get the effect. */ diff --git a/src/haptic/windows/SDL_xinputhaptic.c b/src/haptic/windows/SDL_xinputhaptic.c index 2e1da5987..9212fbf32 100644 --- a/src/haptic/windows/SDL_xinputhaptic.c +++ b/src/haptic/windows/SDL_xinputhaptic.c @@ -246,8 +246,7 @@ SDL_XINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) ++index; } - SDL_SetError("Couldn't find joystick in haptic device list"); - return -1; + return SDL_SetError("Couldn't find joystick in haptic device list"); } void diff --git a/src/hidapi/SDL_hidapi.c b/src/hidapi/SDL_hidapi.c index aacff63bf..369b616f5 100644 --- a/src/hidapi/SDL_hidapi.c +++ b/src/hidapi/SDL_hidapi.c @@ -951,6 +951,7 @@ DeleteHIDDeviceWrapper(SDL_hid_device *device) } #if !SDL_HIDAPI_DISABLED +#if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC) #define COPY_IF_EXISTS(var) \ if (pSrc->var != NULL) { \ @@ -987,6 +988,7 @@ CopyHIDDeviceInfo(struct SDL_hid_device_info *pSrc, struct SDL_hid_device_info * #undef COPY_IF_EXISTS #undef WCOPY_IF_EXISTS +#endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */ #endif /* !SDL_HIDAPI_DISABLED */ static int SDL_hidapi_refcount = 0; @@ -1185,9 +1187,9 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned #ifdef SDL_LIBUSB_DYNAMIC if (libusb_ctx.libhandle) { usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id); - #ifdef DEBUG_HIDAPI +#ifdef DEBUG_HIDAPI SDL_Log("libusb devices found:"); - #endif +#endif for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) { new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info)); if (!new_dev) { @@ -1197,11 +1199,11 @@ struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned return NULL; } CopyHIDDeviceInfo(usb_dev, new_dev); - #ifdef DEBUG_HIDAPI +#ifdef DEBUG_HIDAPI SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx", usb_dev->manufacturer_string, usb_dev->product_string, usb_dev->vendor_id, usb_dev->product_id); - #endif +#endif if (last != NULL) { last->next = new_dev; diff --git a/src/hidapi/android/hid.cpp b/src/hidapi/android/hid.cpp index faed88554..de365d005 100644 --- a/src/hidapi/android/hid.cpp +++ b/src/hidapi/android/hid.cpp @@ -24,6 +24,30 @@ // // This layer glues the hidapi API to Android's USB and BLE stack. + +// Common to stub version and non-stub version of functions +#include +#include + +#define TAG "hidapi" + +// Have error log always available +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) + +#ifdef DEBUG +#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) +#else +#define LOGV(...) +#define LOGD(...) +#endif + +#define SDL_JAVA_PREFIX org_libsdl_app +#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function) +#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function +#define HID_DEVICE_MANAGER_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function) + + #if !SDL_HIDAPI_DISABLED #include "SDL_hints.h" @@ -48,30 +72,10 @@ #define hid_get_indexed_string PLATFORM_hid_get_indexed_string #define hid_error PLATFORM_hid_error -#include -#include #include #include // For ETIMEDOUT and ECONNRESET #include // For malloc() and free() -#define TAG "hidapi" - -// Have error log always available -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) - -#ifdef DEBUG -#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) -#else -#define LOGV(...) -#define LOGD(...) -#endif - -#define SDL_JAVA_PREFIX org_libsdl_app -#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function) -#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function -#define HID_DEVICE_MANAGER_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function) - #include "../hidapi/hidapi.h" typedef uint32_t uint32; @@ -1336,4 +1340,79 @@ int hid_exit(void) } +#else + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol ); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value); + + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz ) +{ + LOGV("Stub HIDDeviceRegisterCallback()"); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz) +{ + LOGV("Stub HIDDeviceReleaseCallback()"); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol ) +{ + LOGV("Stub HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID) +{ + LOGV("Stub HIDDeviceOpenPending() id=%d\n", nDeviceID); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened) +{ + LOGV("Stub HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false"); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID) +{ + LOGV("Stub HIDDeviceDisconnected() id=%d\n", nDeviceID); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) +{ + LOGV("Stub HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize); +} + +extern "C" +JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) +{ + LOGV("Stub HIDDeviceFeatureReport() id=%d len=%u\n", nDeviceID, nBufSize); +} + #endif /* SDL_HIDAPI_DISABLED */ diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c index d4fd9da69..9cb597fa8 100644 --- a/src/hidapi/libusb/hid.c +++ b/src/hidapi/libusb/hid.c @@ -31,9 +31,24 @@ #include "SDL_thread.h" #include "SDL_mutex.h" -#if defined(HAVE__WCSDUP) && !defined(HAVE_WCSDUP) +#ifndef HAVE_WCSDUP +#ifdef HAVE__WCSDUP #define wcsdup _wcsdup +#else +#define wcsdup _dupwcs +static wchar_t *_dupwcs(const wchar_t *src) +{ + wchar_t *dst = NULL; + if (src) { + size_t len = SDL_wcslen(src) + 1; + len *= sizeof(wchar_t); + dst = (wchar_t *) malloc(len); + if (dst) memcpy(dst, src, len); + } + return dst; +} #endif +#endif /* HAVE_WCSDUP */ #include #include /* setlocale */ @@ -59,12 +74,8 @@ typedef struct _SDL_ThreadBarrier static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count) { - if (barrier == NULL) { - return SDL_SetError("barrier must be non-NULL"); - } - if (count == 0) { - return SDL_SetError("count must be > 0"); - } + SDL_assert(barrier != NULL); + SDL_assert(count != 0); barrier->mutex = SDL_CreateMutex(); if (barrier->mutex == NULL) { @@ -373,12 +384,16 @@ static int is_language_supported(libusb_device_handle *dev, uint16_t lang) /* This function returns a newly allocated wide string containing the USB device string numbered by the index. The returned string must be freed by using free(). */ +#if defined(__OS2__) /* don't use iconv on OS/2: no support for wchar_t. */ +#define NO_ICONV +#endif static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) { char buf[512]; int len; wchar_t *str = NULL; +#if !defined(NO_ICONV) wchar_t wbuf[256]; SDL_iconv_t ic; size_t inbytes; @@ -386,6 +401,9 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) size_t res; const char *inptr; char *outptr; +#else + int i; +#endif /* Determine which language to use. */ uint16_t lang; @@ -402,6 +420,23 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) if (len < 0) return NULL; +#if defined(NO_ICONV) /* original hidapi code for NO_ICONV : */ + + /* Bionic does not have wchar_t iconv support, so it + has to be done manually. The following code will only work for + code points that can be represented as a single UTF-16 character, + and will incorrectly convert any code points which require more + than one UTF-16 character. + + Skip over the first character (2-bytes). */ + len -= 2; + str = (wchar_t*) malloc((len / 2 + 1) * sizeof(wchar_t)); + for (i = 0; i < len / 2; i++) { + str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8); + } + str[len / 2] = 0x00000000; + +#else /* buf does not need to be explicitly NULL-terminated because it is only passed into iconv() which does not need it. */ @@ -434,6 +469,7 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx) err: SDL_iconv_close(ic); +#endif return str; } @@ -1461,6 +1497,7 @@ void HID_API_EXPORT hid_close(hid_device *dev) /* Clean up the Transfer objects allocated in read_thread(). */ free(dev->transfer->buffer); + dev->transfer->buffer = NULL; libusb_free_transfer(dev->transfer); /* release the interface */ diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c index 19314a6e0..ec7ffaf16 100644 --- a/src/hidapi/mac/hid.c +++ b/src/hidapi/mac/hid.c @@ -259,7 +259,7 @@ static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t buf[0] = 0; - if (str) { + if (str && CFGetTypeID(str) == CFStringGetTypeID()) { len --; CFIndex str_len = CFStringGetLength(str); @@ -298,7 +298,7 @@ static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, cha buf[0] = 0; - if (str) { + if (str && CFGetTypeID(str) == CFStringGetTypeID()) { len--; CFIndex str_len = CFStringGetLength(str); @@ -326,10 +326,7 @@ static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, cha static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len) { - // This crashes on M1 Macs, tracked by radar bug 79667729 - //return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); - buf[0] = 0; - return 0; + return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len); } static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len) @@ -557,6 +554,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, continue; } +#if 0 // Prefer direct HID support as that has extended functionality #if defined(SDL_JOYSTICK_MFI) // We want to prefer Game Controller support where available, // as Apple will likely be requiring that for supported devices. @@ -564,6 +562,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, if (IOS_SupportedHIDDevice(dev)) { continue; } +#endif #endif dev_vid = get_vendor_id(dev); @@ -573,8 +572,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, if ((vendor_id == 0x0 && product_id == 0x0) || (vendor_id == dev_vid && product_id == dev_pid)) { struct hid_device_info *tmp; - size_t len; - + /* VID/PID match. Create the record. */ tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info)); if (cur_dev) { @@ -591,7 +589,7 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, /* Fill out the record */ cur_dev->next = NULL; - len = make_path(dev, cbuf, sizeof(cbuf)); + make_path(dev, cbuf, sizeof(cbuf)); cur_dev->path = strdup(cbuf); /* Serial Number */ @@ -818,10 +816,9 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) CFSetGetValues(device_set, (const void **) device_array); for (i = 0; i < num_devices; i++) { char cbuf[BUF_LEN]; - size_t len; IOHIDDeviceRef os_dev = device_array[i]; - len = make_path(os_dev, cbuf, sizeof(cbuf)); + make_path(os_dev, cbuf, sizeof(cbuf)); if (!strcmp(cbuf, path)) { // Matched Paths. Open this Device. IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone); @@ -834,6 +831,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive) /* Create the buffers for receiving data */ dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev); + SDL_assert(dev->max_input_report_len > 0); dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t)); /* Create the Run Loop Mode for this device. @@ -937,11 +935,14 @@ static int return_data(hid_device *dev, unsigned char *data, size_t length) /* Copy the data out of the linked list item (rpt) into the return buffer (data), and delete the liked list item. */ struct input_report *rpt = dev->input_reports; - size_t len = (length < rpt->len)? length: rpt->len; - memcpy(data, rpt->data, len); - dev->input_reports = rpt->next; - free(rpt->data); - free(rpt); + size_t len = 0; + if (rpt != NULL) { + len = (length < rpt->len)? length: rpt->len; + memcpy(data, rpt->data, len); + dev->input_reports = rpt->next; + free(rpt->data); + free(rpt); + } return (int)len; } diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 43c5d38f9..9dab7cbba 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -187,6 +187,7 @@ static const char *s_ControllerMappings [] = "030000006d04000016c2000000000000,Logitech Dual Action,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,", "030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ + "030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,", "03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,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:a5,start:b9,x:b0,y:b3,", "03000000380700006382000000000000,MLG Gamepad 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,", "03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,", @@ -266,6 +267,12 @@ static const char *s_ControllerMappings [] = "030000000d0f00001100000000000000,REAL ARCADE PRO.3,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,", "030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,", "030000000d0f00002200000000000000,REAL ARCADE Pro.V3,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,", + "03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", + "03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", + "03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", + "03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", + "03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", + "03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,", "03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "03000000321500000204000000000000,Razer Panthera (PS3),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,", "03000000321500000104000000000000,Razer Panthera (PS4),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,", @@ -494,7 +501,7 @@ static const char *s_ControllerMappings [] = "03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,", #endif -#if defined(__LINUX__) +#ifdef SDL_JOYSTICK_LINUX "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,", "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", "03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", @@ -755,6 +762,7 @@ static const char *s_ControllerMappings [] = "0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,", "030000004f0400000ed0000011010000,ThrustMaster eSwap PRO 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,", "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", + "030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", "030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,", "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,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:a5,start:b9,x:b0,y:b3,", "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,", @@ -786,6 +794,7 @@ static const char *s_ControllerMappings [] = "030000005e040000ea02000001030000,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,", "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,", "050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", + "050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", "05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,", "03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,", "03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,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,", @@ -897,7 +906,7 @@ static const char *s_ControllerMappings [] = "50535669746120436f6e74726f6c6c65,PSVita Controller,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftstick:b14,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,", #endif #if defined(SDL_JOYSTICK_PSP) - "505350206275696c74696e206a6f7970,PSP builtin joypad,y:b0,b:b1,a:b2,x:b3,leftshoulder:b4,rightshoulder:b5,dpdown:b6,dpleft:b7,dpup:b8,dpright:b9,back:b10,start:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,", + "505350206275696c74696e206a6f7970,PSP builtin joypad,a:b2,b:b1,back:b10,dpdown:b6,dpleft:b7,dpright:b9,dpup:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,", #endif "hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", NULL diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 696038d2e..ae4591223 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -886,17 +886,18 @@ SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 h result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble); } - /* Save the rumble value regardless of success, so we don't spam the driver */ - joystick->low_frequency_rumble = low_frequency_rumble; - joystick->high_frequency_rumble = high_frequency_rumble; - - if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { - joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); - if (!joystick->rumble_expiration) { - joystick->rumble_expiration = 1; + if (result == 0) { + joystick->low_frequency_rumble = low_frequency_rumble; + joystick->high_frequency_rumble = high_frequency_rumble; + + if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { + joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); + if (!joystick->rumble_expiration) { + joystick->rumble_expiration = 1; + } + } else { + joystick->rumble_expiration = 0; } - } else { - joystick->rumble_expiration = 0; } SDL_UnlockJoysticks(); @@ -920,17 +921,18 @@ SDL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 ri result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble); } - /* Save the rumble value regardless of success, so we don't spam the driver */ - joystick->left_trigger_rumble = left_rumble; - joystick->right_trigger_rumble = right_rumble; + if (result == 0) { + joystick->left_trigger_rumble = left_rumble; + joystick->right_trigger_rumble = right_rumble; - if ((left_rumble || right_rumble) && duration_ms) { - joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); - if (!joystick->trigger_rumble_expiration) { - joystick->trigger_rumble_expiration = 1; + if ((left_rumble || right_rumble) && duration_ms) { + joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS); + if (!joystick->trigger_rumble_expiration) { + joystick->trigger_rumble_expiration = 1; + } + } else { + joystick->trigger_rumble_expiration = 0; } - } else { - joystick->trigger_rumble_expiration = 0; } SDL_UnlockJoysticks(); @@ -1588,11 +1590,13 @@ SDL_JoystickUpdate(void) for (joystick = SDL_joysticks; joystick; joystick = joystick->next) { if (joystick->attached) { - /* This should always be true, but seeing a crash in the wild...? */ - if (joystick->driver) { - joystick->driver->Update(joystick); + /* This driver should always be != NULL, but seeing a crash in the wild...? */ + if (!joystick->driver) { + continue; /* nothing we can do, and other things use joystick->driver below here. */ } + joystick->driver->Update(joystick); + if (joystick->delayed_guide_button) { SDL_GameControllerHandleDelayedGuideButton(joystick); } @@ -1882,7 +1886,7 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc 0x12ab, /* Unknown */ 0x1430, /* RedOctane */ 0x146b, /* BigBen */ - 0x1532, /* Razer Sabertooth */ + 0x1532, /* Razer */ 0x15e4, /* Numark */ 0x162e, /* Joytech */ 0x1689, /* Razer Onza */ @@ -1911,7 +1915,7 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc 0x0738, /* Mad Catz */ 0x0e6f, /* PDP */ 0x0f0d, /* Hori */ - 0x1532, /* Razer Wildcat */ + 0x1532, /* Razer */ 0x20d6, /* PowerA */ 0x24c6, /* PowerA */ 0x2e24, /* Hyperkin */ @@ -1944,6 +1948,9 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc } else if (vendor == 0x0001 && product == 0x0001) { type = SDL_CONTROLLER_TYPE_UNKNOWN; + } else if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER) { + type = SDL_CONTROLLER_TYPE_XBOXONE; + } else if ((vendor == USB_VENDOR_AMAZON && product == USB_PRODUCT_AMAZON_LUNA_CONTROLLER) || (vendor == BLUETOOTH_VENDOR_AMAZON && product == BLUETOOTH_PRODUCT_LUNA_CONTROLLER)) { type = SDL_CONTROLLER_TYPE_AMAZON_LUNA; @@ -2149,10 +2156,14 @@ static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid) MAKE_VIDPID(0x046d, 0xc261), /* Logitech G920 (initial mode) */ MAKE_VIDPID(0x046d, 0xc262), /* Logitech G920 (active mode) */ MAKE_VIDPID(0x046d, 0xc26e), /* Logitech G923 */ + MAKE_VIDPID(0x046d, 0xca03), /* Logitech Momo Racing */ MAKE_VIDPID(0x044f, 0xb65d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster Wheel FFB */ MAKE_VIDPID(0x044f, 0xb677), /* Thrustmaster T150 */ - MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS */ + MAKE_VIDPID(0x044f, 0xb696), /* Thrustmaster T248 */ + MAKE_VIDPID(0x044f, 0xb66e), /* Thrustmaster T300RS (normal mode) */ + MAKE_VIDPID(0x044f, 0xb66f), /* Thrustmaster T300RS (advanced mode) */ + MAKE_VIDPID(0x044f, 0xb66d), /* Thrustmaster T300RS (PS4 mode) */ MAKE_VIDPID(0x044f, 0xb65e), /* Thrustmaster T500RS */ MAKE_VIDPID(0x044f, 0xb664), /* Thrustmaster TX (initial mode) */ MAKE_VIDPID(0x044f, 0xb669), /* Thrustmaster TX (active mode) */ @@ -2438,11 +2449,24 @@ SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid) /* Additional entries */ /*****************************************************************/ - MAKE_VIDPID(0x04d9, 0x8009), /* OBINLB USB-HID Keyboard */ - MAKE_VIDPID(0x0b05, 0x1958), /* ROG Chakram Mouse */ + MAKE_VIDPID(0x04d9, 0x8008), /* OBINLB USB-HID Keyboard (Anne Pro II) */ + MAKE_VIDPID(0x04d9, 0x8009), /* OBINLB USB-HID Keyboard (Anne Pro II) */ + MAKE_VIDPID(0x04d9, 0xa292), /* OBINLB USB-HID Keyboard (Anne Pro II) */ + MAKE_VIDPID(0x04d9, 0xa293), /* OBINLB USB-HID Keyboard (Anne Pro II) */ + MAKE_VIDPID(0x1532, 0x0266), /* Razer Huntman V2 Analog, non-functional DInput device */ + MAKE_VIDPID(0x1532, 0x0282), /* Razer Huntman Mini Analog, non-functional DInput device */ MAKE_VIDPID(0x26ce, 0x01a2), /* ASRock LED Controller */ }; + static Uint32 rog_chakram_list[] = { + MAKE_VIDPID(0x0b05, 0x1958), /* ROG Chakram Core Mouse */ + MAKE_VIDPID(0x0b05, 0x18e3), /* ROG Chakram (wired) Mouse */ + MAKE_VIDPID(0x0b05, 0x18e5), /* ROG Chakram (wireless) Mouse */ + MAKE_VIDPID(0x0b05, 0x1a18), /* ROG Chakram X (wired) Mouse */ + MAKE_VIDPID(0x0b05, 0x1a1a), /* ROG Chakram X (wireless) Mouse */ + MAKE_VIDPID(0x0b05, 0x1a1c), /* ROG Chakram X (Bluetooth) Mouse */ + }; + unsigned int i; Uint32 id; Uint16 vendor; @@ -2458,6 +2482,13 @@ SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid) return SDL_TRUE; } } + if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_ROG_CHAKRAM, SDL_FALSE)) { + for (i = 0; i < SDL_arraysize(rog_chakram_list); ++i) { + if (id == rog_chakram_list[i]) { + return SDL_TRUE; + } + } + } type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0); if ((type == SDL_CONTROLLER_TYPE_PS4 || type == SDL_CONTROLLER_TYPE_PS5) && SDL_IsPS4RemapperRunning()) { @@ -2707,9 +2738,7 @@ int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger SDL_JoystickTouchpadInfo *touchpad_info; SDL_JoystickTouchpadFingerInfo *finger_info; int posted; -#if !SDL_EVENTS_DISABLED Uint32 event_type; -#endif if (touchpad < 0 || touchpad >= joystick->ntouchpads) { return 0; @@ -2753,7 +2782,6 @@ int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger } } -#if !SDL_EVENTS_DISABLED if (state == finger_info->state) { event_type = SDL_CONTROLLERTOUCHPADMOTION; } else if (state) { @@ -2761,7 +2789,6 @@ int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger } else { event_type = SDL_CONTROLLERTOUCHPADUP; } -#endif /* We ignore events if we don't have keyboard focus, except for touch release */ if (SDL_PrivateJoystickShouldIgnoreEvent()) { diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index b84c77db8..aef014d16 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -103,6 +103,7 @@ keycode_to_SDL(int keycode) case AKEYCODE_BUTTON_THUMBR: button = SDL_CONTROLLER_BUTTON_RIGHTSTICK; break; + case AKEYCODE_MENU: case AKEYCODE_BUTTON_START: button = SDL_CONTROLLER_BUTTON_START; break; diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c index 5af93da60..694556482 100644 --- a/src/joystick/hidapi/SDL_hidapi_gamecube.c +++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c @@ -53,6 +53,7 @@ typedef struct { /* Without this variable, hid_write starts to lag a TON */ SDL_bool rumbleUpdate; SDL_bool m_bUseButtonLabels; + SDL_bool useRumbleBrake; } SDL_DriverGameCube_Context; static SDL_bool @@ -92,6 +93,14 @@ static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE); } +static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + if (hint) { + SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)userdata; + ctx->useRumbleBrake = SDL_GetStringBoolean(hint, SDL_FALSE); + } +} + static Uint8 RemapButton(SDL_DriverGameCube_Context *ctx, Uint8 button) { if (!ctx->m_bUseButtonLabels) { @@ -142,6 +151,7 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) ctx->joysticks[2] = -1; ctx->joysticks[3] = -1; ctx->rumble[0] = rumbleMagic; + ctx->useRumbleBrake = SDL_FALSE; if (device->vendor_id != USB_VENDOR_NINTENDO) { ctx->pc_mode = SDL_TRUE; @@ -195,6 +205,8 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device) } } + SDL_AddHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, + SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_GameControllerButtonReportingHintChanged, ctx); @@ -439,12 +451,22 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo for (i = 0; i < MAX_CONTROLLERS; i += 1) { if (joystick->instance_id == ctx->joysticks[i]) { if (ctx->wireless[i]) { - return SDL_SetError("Ninteno GameCube WaveBird controllers do not support rumble"); + return SDL_SetError("Nintendo GameCube WaveBird controllers do not support rumble"); } if (!ctx->rumbleAllowed[i]) { return SDL_SetError("Second USB cable for WUP-028 not connected"); } - val = (low_frequency_rumble > 0 || high_frequency_rumble > 0); + if (ctx->useRumbleBrake) { + if (low_frequency_rumble == 0 && high_frequency_rumble > 0) { + val = 0; /* if only low is 0 we want to do a regular stop*/ + } else if (low_frequency_rumble == 0 && high_frequency_rumble == 0) { + val = 2; /* if both frequencies are 0 we want to do a hard stop */ + } else { + val = 1; /* normal rumble */ + } + } else { + val = (low_frequency_rumble > 0 || high_frequency_rumble > 0); + } if (val != ctx->rumble[i + 1]) { ctx->rumble[i + 1] = val; ctx->rumbleUpdate = SDL_TRUE; @@ -454,8 +476,7 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo } /* Should never get here! */ - SDL_SetError("Couldn't find joystick"); - return -1; + return SDL_SetError("Couldn't find joystick"); } static int @@ -523,6 +544,8 @@ HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device) SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_GameControllerButtonReportingHintChanged, ctx); + SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE, + SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx); SDL_LockMutex(device->dev_lock); { diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index 129541266..8e7699fe4 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -177,6 +177,12 @@ static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id) (product_id == USB_PRODUCT_RAZER_PANTHERA || product_id == USB_PRODUCT_RAZER_PANTHERA_EVO)) { return SDL_FALSE; } + + /* The Victrix Pro FS v2 will hang on reboot if we send output reports */ + if (vendor_id == USB_VENDOR_PDP && product_id == USB_PRODUCT_VICTRIX_FS_PRO_V2) { + return SDL_FALSE; + } + return SDL_TRUE; } diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index 6d7f87d59..2549c2afd 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -747,7 +747,11 @@ HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joy } } - return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size); + if (SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size) != report_size) { + return -1; + } + + return 0; } static int @@ -957,7 +961,10 @@ HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, axis = ((int)packet->ucRightJoystickY * 257) - 32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); - if (packet->ucBatteryLevel & 0x10) { + /* A check of packet->ucBatteryLevel & 0x10 should work as a check for BT vs USB but doesn't + * seem to always work. Possibly related to being 100% charged? + */ + if (!ctx->is_bluetooth) { /* 0x20 set means fully charged */ SDL_PrivateJoystickBatteryLevel(joystick, SDL_JOYSTICK_POWER_WIRED); } else { diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index d97e1f9c8..912d613ed 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -1023,8 +1023,7 @@ HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context *ctx, Uint16 ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE; if (!WriteRumble(ctx)) { - SDL_SetError("Couldn't send rumble packet"); - return -1; + return SDL_SetError("Couldn't send rumble packet"); } return 0; } diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index a5a58f875..1f0cf5b5a 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -478,30 +478,6 @@ HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Jo return SDL_Unsupported(); } -static Sint16 FilterLeftThumb(Sint16 axis) -{ - if (axis <= XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE && axis >= -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) { - return 0; - } - return axis; -} - -static Sint16 FilterRightThumb(Sint16 axis) -{ - if (axis <= XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE && axis >= -XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) { - return 0; - } - return axis; -} - -static Sint16 FilterTrigger(Sint16 axis) -{ - if (axis <= XINPUT_GAMEPAD_TRIGGER_THRESHOLD) { - return 0; - } - return axis; -} - static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) { @@ -636,7 +612,7 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne if (axis == -32768 && size == 30 && (data[22] & 0x80) != 0) { axis = 32767; } - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, FilterTrigger(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768; if (axis == -32768 && size == 30 && (data[22] & 0x40) != 0) { @@ -645,16 +621,16 @@ HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverXboxOne if (axis == 32704) { axis = 32767; } - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, FilterTrigger(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); axis = *(Sint16*)(&data[10]); - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, FilterLeftThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); axis = *(Sint16*)(&data[12]); - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, FilterLeftThumb(~axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis); axis = *(Sint16*)(&data[14]); - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, FilterRightThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); axis = *(Sint16*)(&data[16]); - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, FilterRightThumb(~axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis); SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); } @@ -854,22 +830,22 @@ HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joystick, SDL_Driv if (axis == 32704) { axis = 32767; } - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, FilterTrigger(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); axis = ((int)*(Sint16*)(&data[11]) * 64) - 32768; if (axis == 32704) { axis = 32767; } - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, FilterTrigger(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); axis = (int)*(Uint16*)(&data[1]) - 0x8000; - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, FilterLeftThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); axis = (int)*(Uint16*)(&data[3]) - 0x8000; - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, FilterLeftThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); axis = (int)*(Uint16*)(&data[5]) - 0x8000; - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, FilterRightThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); axis = (int)*(Uint16*)(&data[7]) - 0x8000; - SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, FilterRightThumb(axis)); + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state))); } diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 959b72414..f54b3c3f2 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -227,7 +227,7 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device) } /* Disconnect any joysticks */ - while (device->num_joysticks) { + while (device->num_joysticks && device->joysticks) { HIDAPI_JoystickDisconnected(device, device->joysticks[0]); } @@ -309,8 +309,7 @@ HIDAPI_JoystickInit(void) #endif if (SDL_hid_init() < 0) { - SDL_SetError("Couldn't initialize hidapi"); - return -1; + return SDL_SetError("Couldn't initialize hidapi"); } for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) { @@ -871,8 +870,7 @@ HIDAPI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint1 result = device->driver->RumbleJoystick(device, joystick, low_frequency_rumble, high_frequency_rumble); } else { - SDL_SetError("Rumble failed, device disconnected"); - result = -1; + result = SDL_SetError("Rumble failed, device disconnected"); } return result; @@ -888,8 +886,7 @@ HIDAPI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 result = device->driver->RumbleJoystickTriggers(device, joystick, left_rumble, right_rumble); } else { - SDL_SetError("Rumble failed, device disconnected"); - result = -1; + result = SDL_SetError("Rumble failed, device disconnected"); } return result; @@ -919,8 +916,7 @@ HIDAPI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue result = device->driver->SetJoystickLED(device, joystick, red, green, blue); } else { - SDL_SetError("SetLED failed, device disconnected"); - result = -1; + result = SDL_SetError("SetLED failed, device disconnected"); } return result; @@ -936,8 +932,7 @@ HIDAPI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) result = device->driver->SendJoystickEffect(device, joystick, data, size); } else { - SDL_SetError("SendEffect failed, device disconnected"); - result = -1; + result = SDL_SetError("SendEffect failed, device disconnected"); } return result; @@ -953,8 +948,7 @@ HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) result = device->driver->SetJoystickSensorsEnabled(device, joystick, enabled); } else { - SDL_SetError("SetSensorsEnabled failed, device disconnected"); - result = -1; + result = SDL_SetError("SetSensorsEnabled failed, device disconnected"); } return result; diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m index ed2384255..38ab3fe60 100644 --- a/src/joystick/iphoneos/SDL_mfijoystick.m +++ b/src/joystick/iphoneos/SDL_mfijoystick.m @@ -69,6 +69,9 @@ + (BOOL)supportsHIDDevice:(IOHIDDeviceRef)device; #if !((__IPHONE_OS_VERSION_MAX_ALLOWED >= 130000) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 130000) || (__MAC_OS_VERSION_MAX_ALLOWED >= 1500000)) @property(nonatomic, readonly) NSString *productCategory; #endif +#if !((__IPHONE_OS_VERSION_MAX_ALLOWED >= 140500) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 140500) || (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110300)) +@property(class, nonatomic, readwrite) BOOL shouldMonitorBackgroundEvents; +#endif @end @interface GCExtendedGamepad (SDL) #if !((__IPHONE_OS_VERSION_MAX_ALLOWED >= 121000) || (__APPLETV_OS_VERSION_MAX_ALLOWED >= 121000) || (__MAC_OS_VERSION_MAX_ALLOWED >= 1401000)) @@ -327,6 +330,19 @@ @interface GCMicroGamepad (SDL) subtype = 1; } + if (SDL_strcmp(name, "Backbone One") == 0) { + /* The Backbone app uses the guide and share buttons */ + if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_GUIDE)) != 0) { + device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_GUIDE); + --nbuttons; + } + if ((device->button_mask & (1 << SDL_CONTROLLER_BUTTON_MISC1)) != 0) { + device->button_mask &= ~(1 << SDL_CONTROLLER_BUTTON_MISC1); + --nbuttons; + device->has_xbox_share_button = SDL_FALSE; + } + } + device->naxes = 6; /* 2 thumbsticks and 2 triggers */ device->nhats = 1; /* d-pad */ device->nbuttons = nbuttons; @@ -572,6 +588,10 @@ static int is_macos11(void) return 0; } + if (@available(macOS 11.3, iOS 14.5, tvOS 14.5, *)) { + GCController.shouldMonitorBackgroundEvents = YES; + } + /* For whatever reason, this always returns an empty array on macOS 11.0.1 */ for (GCController *controller in [GCController controllers]) { @@ -1169,7 +1189,7 @@ -(id) initWithController:(GCController*)controller locality:(GCHapticsLocality)l return nil; } - __weak typeof(self) weakSelf = self; + __weak __typeof(self) weakSelf = self; self.engine.stoppedHandler = ^(CHHapticEngineStoppedReason stoppedReason) { SDL_RumbleMotor *_this = weakSelf; if (_this == nil) { diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 851448acd..a268c0d9b 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -109,6 +109,7 @@ typedef struct SDL_joylist_item /* Steam Controller support */ SDL_bool m_bSteamController; + SDL_bool checked_mapping; SDL_GamepadMapping *mapping; } SDL_joylist_item; @@ -605,6 +606,26 @@ LINUX_InotifyJoystickDetect(void) } #endif /* HAVE_INOTIFY */ +static int get_event_joystick_index(int event) +{ + int joystick_index = -1; + int i, count; + struct dirent **entries = NULL; + char path[PATH_MAX]; + + SDL_snprintf(path, SDL_arraysize(path), "/sys/class/input/event%d/device", event); + count = scandir(path, &entries, NULL, alphasort); + for (i = 0; i < count; ++i) { + if (SDL_strncmp(entries[i]->d_name, "js", 2) == 0) { + joystick_index = SDL_atoi(entries[i]->d_name+2); + } + free(entries[i]); /* This should NOT be SDL_free() */ + } + free(entries); /* This should NOT be SDL_free() */ + + return joystick_index; +} + /* Detect devices by reading /dev/input. In the inotify code path we * have to do this the first time, to detect devices that already existed * before we started; in the non-inotify code path we do this repeatedly @@ -615,12 +636,39 @@ filter_entries(const struct dirent *entry) return IsJoystickDeviceNode(entry->d_name); } static int -sort_entries(const struct dirent **a, const struct dirent **b) +sort_entries(const void *_a, const void *_b) { - int numA = SDL_atoi((*a)->d_name+5); - int numB = SDL_atoi((*b)->d_name+5); + const struct dirent **a = (const struct dirent **)_a; + const struct dirent **b = (const struct dirent **)_b; + int numA, numB; + int offset; + + if (SDL_classic_joysticks) { + offset = 2; /* strlen("js") */ + numA = SDL_atoi((*a)->d_name+offset); + numB = SDL_atoi((*b)->d_name+offset); + } else { + offset = 5; /* strlen("event") */ + numA = SDL_atoi((*a)->d_name+offset); + numB = SDL_atoi((*b)->d_name+offset); + + /* See if we can get the joystick ordering */ + { + int jsA = get_event_joystick_index(numA); + int jsB = get_event_joystick_index(numB); + if (jsA >= 0 && jsB >= 0) { + numA = jsA; + numB = jsB; + } else if (jsA >= 0) { + return -1; + } else if (jsB >= 0) { + return 1; + } + } + } return (numA - numB); } + static void LINUX_FallbackJoystickDetect(void) { @@ -633,10 +681,13 @@ LINUX_FallbackJoystickDetect(void) /* Opening input devices can generate synchronous device I/O, so avoid it if we can */ if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) { int i, count; - struct dirent **entries; + struct dirent **entries = NULL; char path[PATH_MAX]; - count = scandir("/dev/input", &entries, filter_entries, sort_entries); + count = scandir("/dev/input", &entries, filter_entries, NULL); + if (count > 1) { + qsort(entries, count, sizeof(*entries), sort_entries); + } for (i = 0; i < count; ++i) { SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name); MaybeAddDevice(path); @@ -683,29 +734,7 @@ LINUX_JoystickInit(void) SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_CLASSIC, SDL_FALSE); -#if SDL_USE_LIBUDEV - if (enumeration_method == ENUMERATION_UNSET) { - if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "udev disabled by SDL_JOYSTICK_DISABLE_UDEV"); - enumeration_method = ENUMERATION_FALLBACK; - - } else if (access("/.flatpak-info", F_OK) == 0 - || access("/run/host/container-manager", F_OK) == 0) { - /* Explicitly check `/.flatpak-info` because, for old versions of - * Flatpak, this was the only available way to tell if we were in - * a Flatpak container. */ - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Container detected, disabling udev integration"); - enumeration_method = ENUMERATION_FALLBACK; - - } else { - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, - "Using udev for joystick device discovery"); - enumeration_method = ENUMERATION_LIBUDEV; - } - } -#endif + enumeration_method = ENUMERATION_UNSET; /* First see if the user specified one or more joysticks to use */ if (devices != NULL) { @@ -734,6 +763,28 @@ LINUX_JoystickInit(void) LINUX_JoystickDetect(); #if SDL_USE_LIBUDEV + if (enumeration_method == ENUMERATION_UNSET) { + if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "udev disabled by SDL_JOYSTICK_DISABLE_UDEV"); + enumeration_method = ENUMERATION_FALLBACK; + + } else if (access("/.flatpak-info", F_OK) == 0 + || access("/run/host/container-manager", F_OK) == 0) { + /* Explicitly check `/.flatpak-info` because, for old versions of + * Flatpak, this was the only available way to tell if we were in + * a Flatpak container. */ + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Container detected, disabling udev integration"); + enumeration_method = ENUMERATION_FALLBACK; + + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Using udev for joystick device discovery"); + enumeration_method = ENUMERATION_LIBUDEV; + } + } + if (enumeration_method == ENUMERATION_LIBUDEV) { if (SDL_UDEV_Init() < 0) { return SDL_SetError("Could not initialize UDEV"); @@ -1573,9 +1624,13 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) SDL_Joystick *joystick; SDL_joylist_item *item = JoystickByDevIndex(device_index); - if (item->mapping) { - SDL_memcpy(out, item->mapping, sizeof(*out)); - return SDL_TRUE; + if (item->checked_mapping) { + if (item->mapping) { + SDL_memcpy(out, item->mapping, sizeof(*out)); + return SDL_TRUE; + } else { + return SDL_FALSE; + } } /* We temporarily open the device to check how it's configured. Make @@ -1595,6 +1650,8 @@ LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) return SDL_FALSE; } + item->checked_mapping = SDL_TRUE; + if (PrepareJoystickHwdata(joystick, item) == -1) { SDL_free(joystick->hwdata); SDL_free(joystick); diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index 5b2648e3e..97f37b0f8 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -54,6 +54,7 @@ #define USB_PRODUCT_SONY_DS4_DONGLE 0x0ba0 #define USB_PRODUCT_SONY_DS4_SLIM 0x09cc #define USB_PRODUCT_SONY_DS5 0x0ce6 +#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207 #define USB_PRODUCT_XBOX360_XUSB_CONTROLLER 0x02a1 /* XUSB driver software PID */ #define USB_PRODUCT_XBOX360_WIRED_CONTROLLER 0x028e #define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER 0x0719 diff --git a/src/joystick/vita/SDL_sysjoystick.c b/src/joystick/vita/SDL_sysjoystick.c index 3ef1fc178..aa52cd77f 100644 --- a/src/joystick/vita/SDL_sysjoystick.c +++ b/src/joystick/vita/SDL_sysjoystick.c @@ -147,7 +147,7 @@ int VITA_JoystickInit(void) // after the app has already started. SDL_numjoysticks = 1; - + SDL_PrivateJoystickAdded(0); // How many additional paired controllers are there? sceCtrlGetControllerPortInfo(&myPortInfo); @@ -157,6 +157,7 @@ int VITA_JoystickInit(void) { if (myPortInfo.port[i]!=SCE_CTRL_TYPE_UNPAIRED) { + SDL_PrivateJoystickAdded(SDL_numjoysticks); SDL_numjoysticks++; } } diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c index 8178ee624..df40232df 100644 --- a/src/joystick/windows/SDL_rawinputjoystick.c +++ b/src/joystick/windows/SDL_rawinputjoystick.c @@ -62,11 +62,18 @@ typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState; #define GamepadButtons_GUIDE 0x40000000 #define COBJMACROS #include "windows.gaming.input.h" +#include #endif #if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_WGI) #define SDL_JOYSTICK_RAWINPUT_MATCHING #define SDL_JOYSTICK_RAWINPUT_MATCH_AXES +#define SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS +#define SDL_JOYSTICK_RAWINPUT_MATCH_COUNT 6 // stick + trigger axes +#else +#define SDL_JOYSTICK_RAWINPUT_MATCH_COUNT 4 // stick axes +#endif #endif /*#define DEBUG_RAWINPUT*/ @@ -128,7 +135,7 @@ struct joystick_hwdata USHORT trigger_hack_index; #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING - Uint32 match_state; /* Low 16 bits for button states, high 16 for 4 4bit axes */ + Uint64 match_state; /* Lowest 16 bits for button states, higher 24 for 6 4bit axes */ Uint32 last_state_packet; #endif @@ -173,7 +180,7 @@ static struct { typedef struct WindowsMatchState { #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES - SHORT match_axes[4]; + SHORT match_axes[SDL_JOYSTICK_RAWINPUT_MATCH_COUNT]; #endif #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT WORD xinput_buttons; @@ -184,13 +191,13 @@ typedef struct WindowsMatchState { SDL_bool any_data; } WindowsMatchState; -static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state) +static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint64 match_state) { #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES int ii; #endif - state->any_data = SDL_FALSE; + SDL_bool any_axes_data = SDL_FALSE; #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES /* SHORT state->match_axes[4] = { (match_state & 0x000F0000) >> 4, @@ -199,12 +206,18 @@ static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state (match_state & 0xF0000000) >> 16, }; */ for (ii = 0; ii < 4; ii++) { - state->match_axes[ii] = (match_state & (0x000F0000 << (ii * 4))) >> (4 + ii * 4); - if ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000) { /* match_state bit is not 0xF, 0x1, or 0x2 */ - state->any_data = SDL_TRUE; - } + state->match_axes[ii] = (SHORT)((match_state & (0x000F0000ull << (ii * 4))) >> (4 + ii * 4)); + any_axes_data |= ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000); /* match_state bit is not 0xF, 0x1, or 0x2 */ } #endif /* SDL_JOYSTICK_RAWINPUT_MATCH_AXES */ +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS + for (; ii < SDL_JOYSTICK_RAWINPUT_MATCH_COUNT; ii++) { + state->match_axes[ii] = (SHORT)((match_state & (0x000F0000ull << (ii * 4))) >> (4 + ii * 4)); + any_axes_data |= (state->match_axes[ii] != SDL_MIN_SINT16); + } +#endif /* SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS */ + + state->any_data = any_axes_data; #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */ @@ -220,9 +233,16 @@ static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \ SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */ + /* Can only match trigger values if a single trigger has a value. */ +#define XInputTriggersMatch(gamepad) ( \ + ((state->match_axes[4] == SDL_MIN_SINT16) && (state->match_axes[5] == SDL_MIN_SINT16)) || \ + ((gamepad.bLeftTrigger != 0) && (gamepad.bRightTrigger != 0)) || \ + ((Uint32)((((int)gamepad.bLeftTrigger * 257) - 32768) - state->match_axes[4]) <= 0x2fff) || \ + ((Uint32)((((int)gamepad.bRightTrigger * 257) - 32768) - state->match_axes[5]) <= 0x2fff)) + state->xinput_buttons = /* Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU */ - match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11; + (WORD)(match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11); /* Explicit ((match_state & (1<match_axes[2] + 0x1000) <= 0x2fff && \ (Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff) +#define WindowsGamingInputTriggersMatch(gamepad) ( \ + ((state->match_axes[4] == SDL_MIN_SINT16) && (state->match_axes[5] == SDL_MIN_SINT16)) || \ + ((gamepad.LeftTrigger == 0.0f) && (gamepad.RightTrigger == 0.0f)) || \ + ((Uint16)((((int)(gamepad.LeftTrigger * SDL_MAX_UINT16)) - 32768) - state->match_axes[4]) <= 0x2fff) || \ + ((Uint16)((((int)(gamepad.RightTrigger * SDL_MAX_UINT16)) - 32768) - state->match_axes[5]) <= 0x2fff)) state->wgi_buttons = /* Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS */ @@ -354,6 +379,9 @@ RAWINPUT_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx) if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad) +#endif +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS + && XInputTriggersMatch(xinput_state[slot_idx].state.Gamepad) #endif ) { return SDL_TRUE; @@ -538,22 +566,24 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) if (!wgi_state.initialized) { static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } }; HRESULT hr; - HMODULE hModule; - /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */ - if (FAILED(WIN_CoInitialize())) { + if (FAILED(WIN_RoInitialize())) { return; } wgi_state.initialized = SDL_TRUE; wgi_state.dirty = SDL_TRUE; - hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { + { typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string); typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory); - WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference"); - RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory"); +#ifdef __WINRT__ + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = WindowsCreateStringReference; + RoGetActivationFactory_t RoGetActivationFactoryFunc = RoGetActivationFactory; +#else + WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); +#endif if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { PCWSTR pNamespace = L"Windows.Gaming.Input.Gamepad"; HSTRING_HEADER hNamespaceStringHeader; @@ -564,18 +594,21 @@ RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, (void **)&wgi_state.gamepad_statics); } } - FreeLibrary(hModule); } } } static SDL_bool -RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot) +RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot, SDL_bool xinput_correlated) { Uint32 wgi_buttons = slot->state.Buttons; if ((wgi_buttons & 0x3FFF) == state->wgi_buttons #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES && WindowsGamingInputAxesMatch(slot->state) +#endif +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS + // Don't try to match WGI triggers if getting values from XInput + && (xinput_correlated || WindowsGamingInputTriggersMatch(slot->state)) #endif ) { return SDL_TRUE; @@ -584,14 +617,14 @@ RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGa } static SDL_bool -RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot) +RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot, SDL_bool xinput_correlated) { int match_count, user_index; match_count = 0; for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) { WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index]; - if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state)) { + if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state, xinput_correlated)) { ++match_count; *slot = gamepad_state; /* Incrementing correlation_id for any match, as negative evidence for others being correlated */ @@ -626,7 +659,7 @@ RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx) __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics); wgi_state.gamepad_statics = NULL; } - WIN_CoUninitialize(); + WIN_RoUninitialize(); wgi_state.initialized = SDL_FALSE; } } @@ -890,9 +923,12 @@ RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, co return SDL_TRUE; } - /* The Xbox 360 wireless controller shows up as product 0 in WGI */ + /* The Xbox 360 wireless controller shows up as product 0 in WGI. + Try to match it to a Raw Input device via name or known product ID. */ if (vendor_id == device->vendor_id && product_id == 0 && - name && SDL_strstr(device->name, name) != NULL) { + ((name && SDL_strstr(device->name, name) != NULL) || + (device->vendor_id == USB_VENDOR_MICROSOFT && + device->product_id == USB_PRODUCT_XBOX360_XUSB_CONTROLLER))) { return SDL_TRUE; } @@ -1261,6 +1297,13 @@ RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uin } #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */ + if (!rumbled) { +#if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT) + return SDL_SetError("Controller isn't correlated yet, try hitting a button first"); +#else + return SDL_Unsupported(); +#endif + } return 0; } @@ -1279,8 +1322,10 @@ RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint if (!SUCCEEDED(hr)) { return SDL_SetError("Setting vibration failed: 0x%lx\n", hr); } + return 0; + } else { + return SDL_SetError("Controller isn't correlated yet, try hitting a button first"); } - return 0; #else return SDL_Unsupported(); #endif @@ -1383,12 +1428,13 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size) (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT), (1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT), }; - Uint32 match_state = ctx->match_state; + Uint64 match_state = ctx->match_state; /* Update match_state with button bit, then fall through */ -#define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) { if (state) match_state |= 1 << button_map[button]; else match_state &= ~(1 << button_map[button]); } SDL_PrivateJoystickButton(joystick, button, state) +#define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) { Uint64 button_bit = 1ull << button_map[button]; match_state = (match_state & ~button_bit) | (button_bit * (state)); } SDL_PrivateJoystickButton(joystick, button, state) #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES /* Grab high 4 bits of value, then fall through */ -#define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < 4) match_state = (match_state & ~(0xF << (4 * axis + 16))) | ((value) & 0xF000) << (4 * axis + 4); SDL_PrivateJoystickAxis(joystick, axis, value) +#define AddAxisToMatchState(axis, value) { match_state = (match_state & ~(0xFull << (4 * axis + 16))) | ((value) & 0xF000ull) << (4 * axis + 4); } +#define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < 4) AddAxisToMatchState(axis, value); SDL_PrivateJoystickAxis(joystick, axis, value) #endif #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */ @@ -1453,8 +1499,14 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size) #undef SDL_PrivateJoystickAxis #endif +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS +#define AddTriggerToMatchState(axis, value) { int match_axis = axis + SDL_JOYSTICK_RAWINPUT_MATCH_COUNT - joystick->naxes; AddAxisToMatchState(match_axis, value); } +#endif /* SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS */ + if (ctx->trigger_hack) { SDL_bool has_trigger_data = SDL_FALSE; + int left_trigger = joystick->naxes - 2; + int right_trigger = joystick->naxes - 1; #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */ @@ -1469,28 +1521,36 @@ RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size) } #endif /* SDL_JOYSTICK_RAWINPUT_WGI */ - if (!has_trigger_data) { +#ifndef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS + if (!has_trigger_data) +#endif + { HIDP_DATA *item = GetData(ctx->trigger_hack_index, ctx->data, data_length); if (item) { - int left_trigger = joystick->naxes - 2; - int right_trigger = joystick->naxes - 1; Sint16 value = (int)(Uint16)item->RawValue - 0x8000; - if (value < 0) { - value = -value * 2 - 32769; - SDL_PrivateJoystickAxis(joystick, left_trigger, SDL_MIN_SINT16); - SDL_PrivateJoystickAxis(joystick, right_trigger, value); - } else if (value > 0) { - value = value * 2 - 32767; - SDL_PrivateJoystickAxis(joystick, left_trigger, value); - SDL_PrivateJoystickAxis(joystick, right_trigger, SDL_MIN_SINT16); - } else { - SDL_PrivateJoystickAxis(joystick, left_trigger, SDL_MIN_SINT16); - SDL_PrivateJoystickAxis(joystick, right_trigger, SDL_MIN_SINT16); + Sint16 left_value = (value > 0) ? (value * 2 - 32767) : SDL_MIN_SINT16; + Sint16 right_value = (value < 0) ? (-value * 2 - 32769) : SDL_MIN_SINT16; + +#ifdef SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS + AddTriggerToMatchState(left_trigger, left_value); + AddTriggerToMatchState(right_trigger, right_value); + if (!has_trigger_data) +#endif /* SDL_JOYSTICK_RAWINPUT_MATCH_TRIGGERS */ + { + SDL_PrivateJoystickAxis(joystick, left_trigger, left_value); + SDL_PrivateJoystickAxis(joystick, right_trigger, right_value); } } } } +#ifdef AddAxisToMatchState +#undef AddAxisToMatchState +#endif +#ifdef AddTriggerToMatchState +#undef AddTriggerToMatchState +#endif + #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING if (ctx->is_xinput) { ctx->match_state = match_state; @@ -1520,7 +1580,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) !joystick->low_frequency_rumble && !joystick->high_frequency_rumble && !joystick->left_trigger_rumble && !joystick->right_trigger_rumble) { /* We have been previously correlated, ensure we are still matching, see comments in XINPUT section */ - if (RAWINPUT_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot)) { + if (RAWINPUT_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot, ctx->xinput_correlated)) { ctx->wgi_uncorrelate_count = 0; } else { ++ctx->wgi_uncorrelate_count; @@ -1549,7 +1609,7 @@ RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick) if (RAWINPUT_MissingWindowsGamingInputSlot()) { Uint8 correlation_id; WindowsGamingInputGamepadState *slot_idx = NULL; - if (RAWINPUT_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) { + if (RAWINPUT_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx, ctx->xinput_correlated)) { /* we match exactly one WindowsGamingInput device */ /* Probably can do without wgi_correlation_count, just check and clear wgi_slot to NULL, unless we need even more frames to be sure. */ diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c index 2cb5f2cb7..6c5ec5528 100644 --- a/src/joystick/windows/SDL_windows_gaming_input.c +++ b/src/joystick/windows/SDL_windows_gaming_input.c @@ -68,6 +68,7 @@ static struct { EventRegistrationToken controller_added_token; EventRegistrationToken controller_removed_token; int controller_count; + SDL_bool ro_initialized; WindowsGamingInputControllerState *controllers; } wgi; @@ -260,10 +261,9 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde WindowsGetStringRawBufferFunc = WindowsGetStringRawBuffer; WindowsDeleteStringFunc = WindowsDeleteString; #else - HMODULE hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { - WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer"); - WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString"); + { + WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)WIN_LoadComBaseFunction("WindowsGetStringRawBuffer"); + WindowsDeleteStringFunc = (WindowsDeleteString_t)WIN_LoadComBaseFunction("WindowsDeleteString"); } #endif /* __WINRT__ */ if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) { @@ -277,15 +277,10 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde WindowsDeleteStringFunc(hString); } } -#ifndef __WINRT__ - if (hModule != NULL) { - FreeLibrary(hModule); - } -#endif __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2); } if (!name) { - name = ""; + name = SDL_strdup(""); } hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller); @@ -444,23 +439,43 @@ WGI_JoystickInit(void) WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL; RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL; -#ifndef __WINRT__ - HMODULE hModule; -#endif HRESULT hr; - if (FAILED(WIN_CoInitialize())) { - return SDL_SetError("CoInitialize() failed"); + if (FAILED(WIN_RoInitialize())) { + return SDL_SetError("RoInitialize() failed"); + } + wgi.ro_initialized = SDL_TRUE; + +#ifndef __WINRT__ + { + /* There seems to be a bug in Windows where a dependency of WGI can be unloaded from memory prior to WGI itself. + * This results in Windows_Gaming_Input!GameController::~GameController() invoking an unloaded DLL and crashing. + * As a workaround, we will keep a reference to the MTA to prevent COM from unloading DLLs later. + * See https://github.com/libsdl-org/SDL/issues/5552 for more details. + */ + static PVOID cookie = NULL; + if (!cookie) { + typedef HRESULT (WINAPI *CoIncrementMTAUsage_t)(PVOID* pCookie); + CoIncrementMTAUsage_t CoIncrementMTAUsageFunc = (CoIncrementMTAUsage_t)WIN_LoadComBaseFunction("CoIncrementMTAUsage"); + if (CoIncrementMTAUsageFunc) { + if (FAILED(CoIncrementMTAUsageFunc(&cookie))) { + return SDL_SetError("CoIncrementMTAUsage() failed"); + } + } else { + /* CoIncrementMTAUsage() is present since Win8, so we should never make it here. */ + return SDL_SetError("CoIncrementMTAUsage() not found"); + } + } } +#endif #ifdef __WINRT__ WindowsCreateStringReferenceFunc = WindowsCreateStringReference; RoGetActivationFactoryFunc = RoGetActivationFactory; #else - hModule = LoadLibraryA("combase.dll"); - if (hModule != NULL) { - WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference"); - RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory"); + { + WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)WIN_LoadComBaseFunction("WindowsCreateStringReference"); + RoGetActivationFactoryFunc = (RoGetActivationFactory_t)WIN_LoadComBaseFunction("RoGetActivationFactory"); } #endif /* __WINRT__ */ if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { @@ -519,11 +534,6 @@ WGI_JoystickInit(void) } } } -#ifndef __WINRT__ - if (hModule != NULL) { - FreeLibrary(hModule); - } -#endif if (wgi.statics) { __FIVectorView_1_Windows__CGaming__CInput__CRawGameController *controllers; @@ -863,53 +873,12 @@ WGI_JoystickQuit(void) __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerRemoved(wgi.statics, wgi.controller_removed_token); __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.statics); } - SDL_zero(wgi); - /* Don't uninitialize COM because of what appears to be a bug in Microsoft WGI reference counting. - * - * If you plug in a non-Xbox controller and let the application run for 30 seconds, then it crashes in CoUninitialize() - * with this stack trace: - - Windows.Gaming.Input.dll!GameController::~GameController(void) Unknown - Windows.Gaming.Input.dll!GameController::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl,1,1,0,struct Windows::Gaming::Input::IGameController,struct Windows::Gaming::Input::IGameControllerBatteryInfo,struct Microsoft::WRL::CloakedIid,class Microsoft::WRL::FtmBase>::Release(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::AggregableRuntimeClass,struct Microsoft::WRL::CloakedIid,struct Microsoft::WRL::CloakedIid,struct Microsoft::WRL::CloakedIid,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil,class Microsoft::WRL::Details::Nil>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>() Unknown - Windows.Gaming.Input.dll!`eh vector destructor iterator'(void *,unsigned int,int,void (*)(void *)) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection::~GameControllerCollection(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::GameControllerCollection::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::RuntimeClassImpl,1,1,0,struct Windows::Foundation::Collections::IIterable,struct Windows::Foundation::Collections::IVectorView,class Microsoft::WRL::FtmBase>::Release(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase::~CustomGameControllerFactoryBase(void) Unknown - Windows.Gaming.Input.dll!Windows::Gaming::Input::Custom::Details::CustomGameControllerFactoryBase::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory >,struct Windows::Gaming::Input::IFlightStickStatics,class Microsoft::WRL::Details::Nil,0>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>::~ComPtr<`WaitForCompletion,Windows::Foundation::IAsyncOperationWithProgress>'::`2'::FTMEventDelegate>() Unknown - Windows.Gaming.Input.dll!NtList::~NtList(void) Unknown - Windows.Gaming.Input.dll!FactoryManager::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::ActivationFactory,struct Windows::Gaming::Input::Custom::IGameControllerFactoryManagerStatics2,struct Microsoft::WRL::CloakedIid,0>::Release(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::TerminateMap(class Microsoft::WRL::Details::ModuleBase *,unsigned short const *,bool) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Module<1,class Microsoft::WRL::Details::DefaultModule<1> >::~Module<1,class Microsoft::WRL::Details::DefaultModule<1> >(void) Unknown - Windows.Gaming.Input.dll!Microsoft::WRL::Details::DefaultModule<1>::`vector deleting destructor'(unsigned int) Unknown - Windows.Gaming.Input.dll!`dynamic atexit destructor for 'Microsoft::WRL::Details::StaticStorage,0,int>::instance_''() Unknown - Windows.Gaming.Input.dll!__CRT_INIT@12() Unknown - Windows.Gaming.Input.dll!__DllMainCRTStartup() Unknown - ntdll.dll!_LdrxCallInitRoutine@16() Unknown - ntdll.dll!LdrpCallInitRoutine() Unknown - ntdll.dll!LdrpProcessDetachNode() Unknown - ntdll.dll!LdrpUnloadNode() Unknown - ntdll.dll!LdrpDecrementModuleLoadCountEx() Unknown - ntdll.dll!LdrUnloadDll() Unknown - KernelBase.dll!FreeLibrary() Unknown - combase.dll!FreeLibraryWithLogging(LoadOrFreeWhy why, HINSTANCE__ * hMod, const wchar_t * pswzOptionalFileName) Line 193 C++ - combase.dll!CClassCache::CDllPathEntry::CFinishObject::Finish() Line 3311 C++ - combase.dll!CClassCache::CFinishComposite::Finish() Line 3421 C++ - combase.dll!CClassCache::CleanUpDllsForProcess() Line 7009 C++ - [Inline Frame] combase.dll!CCCleanUpDllsForProcess() Line 8773 C++ - combase.dll!ProcessUninitialize() Line 2243 C++ - combase.dll!DecrementProcessInitializeCount() Line 993 C++ - combase.dll!wCoUninitialize(COleTls & Tls, int fHostThread) Line 4126 C++ - combase.dll!CoUninitialize() Line 3945 C++ - */ - /* WIN_CoUninitialize(); */ + if (wgi.ro_initialized) { + WIN_RoUninitialize(); + } + + SDL_zero(wgi); } static SDL_bool diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index a8eece5d3..f3ab8a0b2 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -201,9 +201,20 @@ GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion) * userid, but we'll record it so we'll at least be consistent * when the raw device list changes. */ - *pVID = (Uint16)rdi.hid.dwVendorId; - *pPID = (Uint16)rdi.hid.dwProductId; - *pVersion = (Uint16)rdi.hid.dwVersionNumber; + if (rdi.hid.dwVendorId == USB_VENDOR_VALVE && + rdi.hid.dwProductId == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) { + /* Steam encodes the real device in the path */ + int realVID = rdi.hid.dwVendorId; + int realPID = rdi.hid.dwProductId; + SDL_sscanf(devName, "\\\\.\\pipe\\HID#VID_045E&PID_028E&IG_00#%x&%x&", &realVID, &realPID); + *pVID = (Uint16)realVID; + *pPID = (Uint16)realPID; + *pVersion = 0; + } else { + *pVID = (Uint16)rdi.hid.dwVendorId; + *pPID = (Uint16)rdi.hid.dwProductId; + *pVersion = (Uint16)rdi.hid.dwVersionNumber; + } if (s_arrXInputDevicePath[userid]) { SDL_free(s_arrXInputDevicePath[userid]); } diff --git a/src/loadso/os2/SDL_sysloadso.c b/src/loadso/os2/SDL_sysloadso.c index 5e6971252..2b96848ac 100644 --- a/src/loadso/os2/SDL_sysloadso.c +++ b/src/loadso/os2/SDL_sysloadso.c @@ -41,7 +41,7 @@ SDL_LoadObject(const char *sofile) PSZ pszModName; if (!sofile) { - SDL_SetError("NULL sofile"); + SDL_InvalidParamError("sofile"); return NULL; } diff --git a/src/loadso/windows/SDL_sysloadso.c b/src/loadso/windows/SDL_sysloadso.c index 7e5730a89..d3c84042b 100644 --- a/src/loadso/windows/SDL_sysloadso.c +++ b/src/loadso/windows/SDL_sysloadso.c @@ -36,7 +36,7 @@ SDL_LoadObject(const char *sofile) LPTSTR tstr; if (!sofile) { - SDL_SetError("NULL sofile"); + SDL_InvalidParamError("sofile"); return NULL; } tstr = WIN_UTF8ToString(sofile); diff --git a/src/locale/vita/SDL_syslocale.c b/src/locale/vita/SDL_syslocale.c new file mode 100644 index 000000000..0a057cbfa --- /dev/null +++ b/src/locale/vita/SDL_syslocale.c @@ -0,0 +1,71 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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" +#include "../SDL_syslocale.h" + +#include +#include + +void +SDL_SYS_GetPreferredLocales(char *buf, size_t buflen) +{ + const char *vita_locales[] = { + "ja_JP", + "en_US", + "fr_FR", + "es_ES", + "de_DE", + "it_IT", + "nl_NL", + "pt_PT", + "ru_RU", + "ko_KR", + "zh_TW", + "zh_CN", + "fi_FI", + "sv_SE", + "da_DK", + "no_NO", + "pl_PL", + "pt_BR", + "en_GB", + "tr_TR", + }; + + Sint32 language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US; + SceAppUtilInitParam initParam; + SceAppUtilBootParam bootParam; + SDL_zero(initParam); + SDL_zero(bootParam); + sceAppUtilInit(&initParam, &bootParam); + sceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_LANG, &language); + + if (language < 0 || language > SCE_SYSTEM_PARAM_LANG_TURKISH) + language = SCE_SYSTEM_PARAM_LANG_ENGLISH_US; // default to english + + SDL_strlcpy(buf, vita_locales[language], buflen); + + sceAppUtilShutdown(); +} + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/main/haiku/SDL_BApp.h b/src/main/haiku/SDL_BApp.h index 56b1fa0d6..215f83662 100644 --- a/src/main/haiku/SDL_BApp.h +++ b/src/main/haiku/SDL_BApp.h @@ -21,6 +21,7 @@ #ifndef SDL_BAPP_H #define SDL_BAPP_H +#include #include #include #if SDL_VIDEO_OPENGL @@ -93,6 +94,15 @@ class SDL_BApp : public BApplication { } + virtual void RefsReceived(BMessage* message) { + char filePath[512]; + entry_ref entryRef; + for (int32 i = 0; message->FindRef("refs", i, &entryRef) == B_OK; i++) { + BPath referencePath = BPath(&entryRef); + SDL_SendDropFile(NULL, referencePath.Path()); + } + return; + } /* Event-handling functions */ virtual void MessageReceived(BMessage* message) { @@ -198,6 +208,10 @@ class SDL_BApp : public BApplication { } #if SDL_VIDEO_OPENGL + BGLView *GetCurrentContext() { + return _current_context; + } + void SetCurrentContext(BGLView *newContext) { if(_current_context) _current_context->UnlockGL(); @@ -234,25 +248,22 @@ class SDL_BApp : public BApplication { } win = GetSDLWindow(winID); - // Simple relative mode support for mouse. - if (SDL_GetMouse()->relative_mode) { - int winWidth, winHeight, winPosX, winPosY; - SDL_GetWindowSize(win, &winWidth, &winHeight); - SDL_GetWindowPosition(win, &winPosX, &winPosY); - int dx = x - (winWidth / 2); - int dy = y - (winHeight / 2); - SDL_SendMouseMotion(win, 0, SDL_GetMouse()->relative_mode, dx, dy); - set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2)); - if (!be_app->IsCursorHidden()) - be_app->HideCursor(); - } else { - SDL_SendMouseMotion(win, 0, 0, x, y); - if (SDL_ShowCursor(-1) && be_app->IsCursorHidden()) - be_app->ShowCursor(); - } - - /* Tell the application that the mouse passed over, redraw needed */ - HAIKU_UpdateWindowFramebuffer(NULL,win,NULL,-1); + // Simple relative mode support for mouse. + if (SDL_GetMouse()->relative_mode) { + int winWidth, winHeight, winPosX, winPosY; + SDL_GetWindowSize(win, &winWidth, &winHeight); + SDL_GetWindowPosition(win, &winPosX, &winPosY); + int dx = x - (winWidth / 2); + int dy = y - (winHeight / 2); + SDL_SendMouseMotion(win, 0, SDL_GetMouse()->relative_mode, dx, dy); + set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2)); + if (!be_app->IsCursorHidden()) + be_app->HideCursor(); + } else { + SDL_SendMouseMotion(win, 0, 0, x, y); + if (SDL_ShowCursor(-1) && be_app->IsCursorHidden()) + be_app->ShowCursor(); + } } void _HandleMouseButton(BMessage *msg) { @@ -300,7 +311,7 @@ class SDL_BApp : public BApplication { } HAIKU_SetKeyState(scancode, state); SDL_SendKeyboardKey(state, HAIKU_GetScancodeFromBeKey(scancode)); - + if (state == SDL_PRESSED && SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { const int8 *keyUtf8; ssize_t count; diff --git a/src/main/windows/version.rc b/src/main/windows/version.rc index bedde9b19..f106c5f48 100644 --- a/src/main/windows/version.rc +++ b/src/main/windows/version.rc @@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,20,0 - PRODUCTVERSION 2,0,20,0 + FILEVERSION 2,0,22,0 + PRODUCTVERSION 2,0,22,0 FILEFLAGSMASK 0x3fL FILEFLAGS 0x0L FILEOS 0x40004L @@ -23,12 +23,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "SDL\0" - VALUE "FileVersion", "2, 0, 20, 0\0" + VALUE "FileVersion", "2, 0, 22, 0\0" VALUE "InternalName", "SDL\0" VALUE "LegalCopyright", "Copyright (C) 2022 Sam Lantinga\0" VALUE "OriginalFilename", "SDL2.dll\0" VALUE "ProductName", "Simple DirectMedia Layer\0" - VALUE "ProductVersion", "2, 0, 20, 0\0" + VALUE "ProductVersion", "2, 0, 22, 0\0" END END BLOCK "VarFileInfo" diff --git a/src/misc/emscripten/SDL_sysurl.c b/src/misc/emscripten/SDL_sysurl.c new file mode 100644 index 000000000..f344232ab --- /dev/null +++ b/src/misc/emscripten/SDL_sysurl.c @@ -0,0 +1,37 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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_sysurl.h" + +#include + +int +SDL_SYS_OpenURL(const char *url) +{ + EM_ASM({ + window.open(UTF8ToString($0), "_blank"); + }, url); + + return 0; +} + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/misc/winrt/SDL_sysurl.cpp b/src/misc/winrt/SDL_sysurl.cpp index c83cc8513..111a14413 100644 --- a/src/misc/winrt/SDL_sysurl.cpp +++ b/src/misc/winrt/SDL_sysurl.cpp @@ -18,10 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include -#include "../../core/windows/SDL_windows.h" #include "../SDL_sysurl.h" +#include "../../core/windows/SDL_windows.h" int SDL_SYS_OpenURL(const char *url) diff --git a/src/power/linux/SDL_syspower.c b/src/power/linux/SDL_syspower.c index 3b9ab1ba9..f4e1ecc3d 100644 --- a/src/power/linux/SDL_syspower.c +++ b/src/power/linux/SDL_syspower.c @@ -561,20 +561,30 @@ check_upower_device(DBusConnection *conn, const char *path, SDL_PowerState *stat return; } else if (!ui32) { return; /* we don't care about random devices with batteries, like wireless controllers, etc */ - } else if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "IsPresent", DBUS_TYPE_BOOLEAN, &ui32)) { + } + + if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "IsPresent", DBUS_TYPE_BOOLEAN, &ui32)) { return; - } else if (!ui32) { + } + if (!ui32) { st = SDL_POWERSTATE_NO_BATTERY; - } else if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "State", DBUS_TYPE_UINT32, &ui32)) { - st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ - } else if (ui32 == 1) { /* 1 == charging */ - st = SDL_POWERSTATE_CHARGING; - } else if ((ui32 == 2) || (ui32 == 3)) { /* 2 == discharging, 3 == empty. */ - st = SDL_POWERSTATE_ON_BATTERY; - } else if (ui32 == 4) { /* 4 == full */ - st = SDL_POWERSTATE_CHARGED; } else { - st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ + /* Get updated information on the battery status + * This can occasionally fail, and we'll just return slightly stale data in that case + */ + SDL_DBus_CallMethodOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "Refresh", DBUS_TYPE_INVALID, DBUS_TYPE_INVALID); + + if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "State", DBUS_TYPE_UINT32, &ui32)) { + st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ + } else if (ui32 == 1) { /* 1 == charging */ + st = SDL_POWERSTATE_CHARGING; + } else if ((ui32 == 2) || (ui32 == 3)) { /* 2 == discharging, 3 == empty. */ + st = SDL_POWERSTATE_ON_BATTERY; + } else if (ui32 == 4) { /* 4 == full */ + st = SDL_POWERSTATE_CHARGED; + } else { + st = SDL_POWERSTATE_UNKNOWN; /* uh oh */ + } } if (!SDL_DBus_QueryPropertyOnConnection(conn, UPOWER_DBUS_NODE, path, UPOWER_DEVICE_DBUS_INTERFACE, "Percentage", DBUS_TYPE_DOUBLE, &d)) { diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 0cdb9e272..254af5773 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -48,13 +48,13 @@ this should probably be removed at some point in the future. --ryan. */ #define CHECK_RENDERER_MAGIC(renderer, retval) \ if (!renderer || renderer->magic != &renderer_magic) { \ - SDL_SetError("Invalid renderer"); \ + SDL_InvalidParamError("renderer"); \ return retval; \ } #define CHECK_TEXTURE_MAGIC(texture, retval) \ if (!texture || texture->magic != &texture_magic) { \ - SDL_SetError("Invalid texture"); \ + SDL_InvalidParamError("texture"); \ return retval; \ } @@ -356,7 +356,7 @@ QueueCmdSetViewport(SDL_Renderer *renderer) if (cmd != NULL) { cmd->command = SDL_RENDERCMD_SETVIEWPORT; cmd->data.viewport.first = 0; /* render backend will fill this in. */ - /* Convert SDL_FRect to SDL_Rect */ + /* Convert SDL_DRect to SDL_Rect */ cmd->data.viewport.rect.x = (int)SDL_floor(renderer->viewport.x); cmd->data.viewport.rect.y = (int)SDL_floor(renderer->viewport.y); cmd->data.viewport.rect.w = (int)SDL_floor(renderer->viewport.w); @@ -386,7 +386,7 @@ QueueCmdSetClipRect(SDL_Renderer *renderer) } else { cmd->command = SDL_RENDERCMD_SETCLIPRECT; cmd->data.cliprect.enabled = renderer->clipping_enabled; - /* Convert SDL_FRect to SDL_Rect */ + /* Convert SDL_DRect to SDL_Rect */ cmd->data.cliprect.rect.x = (int)SDL_floor(renderer->clip_rect.x); cmd->data.cliprect.rect.y = (int)SDL_floor(renderer->clip_rect.y); cmd->data.cliprect.rect.w = (int)SDL_floor(renderer->clip_rect.w); @@ -580,10 +580,10 @@ QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect * rects, const int cou if (retval < 0) { cmd->command = SDL_RENDERCMD_NO_OP; } - - SDL_small_free(xy, isstack1); - SDL_small_free(indices, isstack2); } + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + } else { retval = renderer->QueueFillRects(renderer, cmd, rects, count); if (retval < 0) { @@ -611,12 +611,12 @@ QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * src static int QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture * texture, const SDL_Rect * srcquad, const SDL_FRect * dstrect, - const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) { SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY_EX, texture); int retval = -1; if (cmd != NULL) { - retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip); + retval = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip, scale_x, scale_y); if (retval < 0) { cmd->command = SDL_RENDERCMD_NO_OP; } @@ -676,7 +676,7 @@ SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info) #endif } -static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_FRect *viewport, SDL_FPoint *scale) +static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_DRect *viewport, SDL_FPoint *scale) { SDL_LockMutex(renderer->target_mutex); *logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w; @@ -698,7 +698,17 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) renderer->WindowEvent(renderer, &event->window); } - if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + /* In addition to size changes, we also want to do this block for + * moves as well, for two reasons: + * + * 1. The window could be moved to a new display, which has a new + * DPI and therefore a new window/drawable ratio + * 2. For whatever reason, the viewport can get messed up during + * window movement (this has been observed on macOS), so this is + * also a good opportunity to force viewport updates + */ + if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED || + event->window.event == SDL_WINDOWEVENT_MOVED) { /* Make sure we're operating on the default render target */ SDL_Texture *saved_target = SDL_GetRenderTarget(renderer); if (saved_target) { @@ -728,19 +738,12 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_GetWindowSize(renderer->window, &w, &h); } - if (renderer->target) { - renderer->viewport_backup.x = 0; - renderer->viewport_backup.y = 0; - renderer->viewport_backup.w = (float) w; - renderer->viewport_backup.h = (float) h; - } else { - renderer->viewport.x = 0; - renderer->viewport.y = 0; - renderer->viewport.w = (float) w; - renderer->viewport.h = (float) h; - QueueCmdSetViewport(renderer); - FlushRenderCommandsIfNotBatching(renderer); - } + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)w; + renderer->viewport.h = (double)h; + QueueCmdSetViewport(renderer); + FlushRenderCommandsIfNotBatching(renderer); } if (saved_target) { @@ -765,7 +768,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); if (window == renderer->window) { int logical_w, logical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); if (logical_w) { @@ -792,7 +795,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); if (window == renderer->window) { int logical_w, logical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); if (logical_w) { @@ -807,7 +810,7 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event) event->type == SDL_FINGERMOTION) { int logical_w, logical_h; float physical_w, physical_h; - SDL_FRect viewport; + SDL_DRect viewport; SDL_FPoint scale; GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); @@ -930,7 +933,7 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) #endif if (!window) { - SDL_SetError("Invalid window"); + SDL_InvalidParamError("window"); goto error; } @@ -979,24 +982,24 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) } } } - if (index == n) { + if (!renderer) { SDL_SetError("Couldn't find matching render driver"); goto error; } } else { - if (index >= SDL_GetNumRenderDrivers()) { + if (index >= n) { SDL_SetError("index must be -1 or in the range of 0 - %d", - SDL_GetNumRenderDrivers() - 1); + n - 1); goto error; } /* Create a new renderer instance */ renderer = render_drivers[index]->CreateRenderer(window, flags); batching = SDL_FALSE; + if (!renderer) { + goto error; + } } - if (!renderer) { - goto error; - } VerifyDrawQueueFunctions(renderer); @@ -1102,6 +1105,13 @@ SDL_GetRenderer(SDL_Window * window) return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA); } +SDL_Window * +SDL_RenderGetWindow(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + return renderer->window; +} + int SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) { @@ -1326,7 +1336,7 @@ SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface) CHECK_RENDERER_MAGIC(renderer, NULL); if (!surface) { - SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); + SDL_InvalidParamError("SDL_CreateTextureFromSurface(): surface"); return NULL; } @@ -1636,10 +1646,11 @@ SDL_SetTextureScaleMode(SDL_Texture * texture, SDL_ScaleMode scaleMode) CHECK_TEXTURE_MAGIC(texture, -1); renderer = texture->renderer; - renderer->SetTextureScaleMode(renderer, texture, scaleMode); texture->scaleMode = scaleMode; if (texture->native) { return SDL_SetTextureScaleMode(texture->native, scaleMode); + } else { + renderer->SetTextureScaleMode(renderer, texture, scaleMode); } return 0; } @@ -2261,10 +2272,10 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) } if (texture) { - renderer->viewport.x = 0.0f; - renderer->viewport.y = 0.0f; - renderer->viewport.w = (float) texture->w; - renderer->viewport.h = (float) texture->h; + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)texture->w; + renderer->viewport.h = (double)texture->h; SDL_zero(renderer->clip_rect); renderer->clipping_enabled = SDL_FALSE; renderer->scale.x = 1.0f; @@ -2296,6 +2307,8 @@ SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) SDL_Texture * SDL_GetRenderTarget(SDL_Renderer *renderer) { + CHECK_RENDERER_MAGIC(renderer, NULL); + return renderer->target; } @@ -2471,19 +2484,19 @@ SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) CHECK_RENDERER_MAGIC(renderer, -1); if (rect) { - renderer->viewport.x = rect->x * renderer->scale.x; - renderer->viewport.y = rect->y * renderer->scale.y; - renderer->viewport.w = rect->w * renderer->scale.x; - renderer->viewport.h = rect->h * renderer->scale.y; + renderer->viewport.x = (double)rect->x * renderer->scale.x; + renderer->viewport.y = (double)rect->y * renderer->scale.y; + renderer->viewport.w = (double)rect->w * renderer->scale.x; + renderer->viewport.h = (double)rect->h * renderer->scale.y; } else { int w, h; if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { return -1; } - renderer->viewport.x = 0.0f; - renderer->viewport.y = 0.0f; - renderer->viewport.w = (float) w; - renderer->viewport.h = (float) h; + renderer->viewport.x = (double)0; + renderer->viewport.y = (double)0; + renderer->viewport.w = (double)w; + renderer->viewport.h = (double)h; } retval = QueueCmdSetViewport(renderer); return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer); @@ -2507,8 +2520,8 @@ RenderGetViewportSize(SDL_Renderer * renderer, SDL_FRect * rect) { rect->x = 0.0f; rect->y = 0.0f; - rect->w = renderer->viewport.w / renderer->scale.x; - rect->h = renderer->viewport.h / renderer->scale.y; + rect->w = (float)(renderer->viewport.w / renderer->scale.x); + rect->h = (float)(renderer->viewport.h / renderer->scale.y); } int @@ -2519,10 +2532,10 @@ SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect) if (rect) { renderer->clipping_enabled = SDL_TRUE; - renderer->clip_rect.x = rect->x * renderer->scale.x; - renderer->clip_rect.y = rect->y * renderer->scale.y; - renderer->clip_rect.w = rect->w * renderer->scale.x; - renderer->clip_rect.h = rect->h * renderer->scale.y; + renderer->clip_rect.x = (double)rect->x * renderer->scale.x; + renderer->clip_rect.y = (double)rect->y * renderer->scale.y; + renderer->clip_rect.w = (double)rect->w * renderer->scale.x; + renderer->clip_rect.h = (double)rect->h * renderer->scale.y; } else { renderer->clipping_enabled = SDL_FALSE; SDL_zero(renderer->clip_rect); @@ -2586,10 +2599,10 @@ SDL_RenderWindowToLogical(SDL_Renderer * renderer, int windowX, int windowY, flo window_physical_y = ((float) windowY) / renderer->dpi_scale.y; if (logicalX) { - *logicalX = (window_physical_x - renderer->viewport.x) / renderer->scale.x; + *logicalX = (float)((window_physical_x - renderer->viewport.x) / renderer->scale.x); } if (logicalY) { - *logicalY = (window_physical_y - renderer->viewport.y) / renderer->scale.y; + *logicalY = (float)((window_physical_y - renderer->viewport.y) / renderer->scale.y); } } @@ -2600,8 +2613,8 @@ SDL_RenderLogicalToWindow(SDL_Renderer * renderer, float logicalX, float logical CHECK_RENDERER_MAGIC(renderer, ); - window_physical_x = (logicalX * renderer->scale.x) + renderer->viewport.x; - window_physical_y = (logicalY * renderer->scale.y) + renderer->viewport.y; + window_physical_x = (float)((logicalX * renderer->scale.x) + renderer->viewport.x); + window_physical_y = (float)((logicalY * renderer->scale.y) + renderer->viewport.y); if (windowX) { *windowX = (int)(window_physical_x * renderer->dpi_scale.x); @@ -2738,7 +2751,7 @@ SDL_RenderDrawPoints(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!points) { - return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points"); + return SDL_InvalidParamError("SDL_RenderDrawPoints(): points"); } if (count < 1) { return 0; @@ -2808,7 +2821,7 @@ SDL_RenderDrawPointsF(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!points) { - return SDL_SetError("SDL_RenderDrawPointsF(): Passed NULL points"); + return SDL_InvalidParamError("SDL_RenderDrawPointsF(): points"); } if (count < 1) { return 0; @@ -3017,7 +3030,7 @@ SDL_RenderDrawLines(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!points) { - return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points"); + return SDL_InvalidParamError("SDL_RenderDrawLines(): points"); } if (count < 2) { return 0; @@ -3056,7 +3069,7 @@ SDL_RenderDrawLinesF(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!points) { - return SDL_SetError("SDL_RenderDrawLinesF(): Passed NULL points"); + return SDL_InvalidParamError("SDL_RenderDrawLinesF(): points"); } if (count < 2) { return 0; @@ -3189,10 +3202,11 @@ SDL_RenderDrawLinesF(SDL_Renderer * renderer, num_vertices, indices, num_indices, size_indices, 1.0f, 1.0f); - SDL_small_free(xy, isstack1); - SDL_small_free(indices, isstack2); } + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + } else if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { retval = RenderDrawLinesWithRectsF(renderer, points, count); } else { @@ -3255,7 +3269,7 @@ SDL_RenderDrawRects(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!rects) { - return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects"); + return SDL_InvalidParamError("SDL_RenderDrawRects(): rects"); } if (count < 1) { return 0; @@ -3285,7 +3299,7 @@ SDL_RenderDrawRectsF(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!rects) { - return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects"); + return SDL_InvalidParamError("SDL_RenderDrawRectsF(): rects"); } if (count < 1) { return 0; @@ -3352,7 +3366,7 @@ SDL_RenderFillRects(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!rects) { - return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects"); + return SDL_InvalidParamError("SDL_RenderFillRects(): rects"); } if (count < 1) { return 0; @@ -3395,7 +3409,7 @@ SDL_RenderFillRectsF(SDL_Renderer * renderer, CHECK_RENDERER_MAGIC(renderer, -1); if (!rects) { - return SDL_SetError("SDL_RenderFillFRects(): Passed NULL rects"); + return SDL_InvalidParamError("SDL_RenderFillRectsF(): rects"); } if (count < 1) { return 0; @@ -3426,60 +3440,6 @@ SDL_RenderFillRectsF(SDL_Renderer * renderer, return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer); } -/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */ -SDL_FORCE_INLINE SDL_bool SDL_FRectEmpty(const SDL_FRect *r) -{ - return ((!r) || (r->w <= 0.0f) || (r->h <= 0.0f)) ? SDL_TRUE : SDL_FALSE; -} - -/* !!! FIXME: move this to a public API if we want to do float versions of all of these later */ -static SDL_bool -SDL_HasIntersectionF(const SDL_FRect * A, const SDL_FRect * B) -{ - float Amin, Amax, Bmin, Bmax; - - if (!A) { - SDL_InvalidParamError("A"); - return SDL_FALSE; - } - - if (!B) { - SDL_InvalidParamError("B"); - return SDL_FALSE; - } - - /* Special cases for empty rects */ - if (SDL_FRectEmpty(A) || SDL_FRectEmpty(B)) { - return SDL_FALSE; - } - - /* Horizontal intersection */ - Amin = A->x; - Amax = Amin + A->w; - Bmin = B->x; - Bmax = Bmin + B->w; - if (Bmin > Amin) - Amin = Bmin; - if (Bmax < Amax) - Amax = Bmax; - if (Amax <= Amin) - return SDL_FALSE; - - /* Vertical intersection */ - Amin = A->y; - Amax = Amin + A->h; - Bmin = B->y; - Bmax = Bmin + B->h; - if (Bmin > Amin) - Amin = Bmin; - if (Bmax < Amax) - Amax = Bmax; - if (Amax <= Amin) - return SDL_FALSE; - - return SDL_TRUE; -} - int SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect) @@ -3778,15 +3738,7 @@ SDL_RenderCopyExF(SDL_Renderer * renderer, SDL_Texture * texture, renderer->scale.x, renderer->scale.y); } else { - real_dstrect.x *= renderer->scale.x; - real_dstrect.y *= renderer->scale.y; - real_dstrect.w *= renderer->scale.x; - real_dstrect.h *= renderer->scale.y; - - real_center.x *= renderer->scale.x; - real_center.y *= renderer->scale.y; - - retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip); + retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip, renderer->scale.x, renderer->scale.y); } return retval < 0 ? retval : FlushRenderCommandsIfNotBatching(renderer); } @@ -4283,7 +4235,11 @@ SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, FlushRenderCommands(renderer); /* we need to render before we read the results. */ if (!format) { - format = SDL_GetWindowPixelFormat(renderer->window); + if (renderer->target == NULL) { + format = SDL_GetWindowPixelFormat(renderer->window); + } else { + format = renderer->target->format; + } } real_rect.x = (int)SDL_floor(renderer->viewport.x); diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 5bfb07be6..a597806ce 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -28,6 +28,19 @@ #include "SDL_mutex.h" #include "SDL_yuv_sw_c.h" + +/** + * A rectangle, with the origin at the upper left (double precision). + */ +typedef struct SDL_DRect +{ + double x; + double y; + double w; + double h; +} SDL_DRect; + + /* The SDL 2D rendering system */ typedef struct SDL_RenderDriver SDL_RenderDriver; @@ -144,7 +157,7 @@ struct SDL_Renderer const SDL_Rect * srcrect, const SDL_FRect * dstrect); int (*QueueCopyEx) (SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, const SDL_Rect * srcquad, const SDL_FRect * dstrect, - const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip); + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y); int (*QueueGeometry) (SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride, int num_vertices, const void *indices, int num_indices, int size_indices, @@ -202,12 +215,12 @@ struct SDL_Renderer SDL_bool integer_scale; /* The drawable area within the window */ - SDL_FRect viewport; - SDL_FRect viewport_backup; + SDL_DRect viewport; + SDL_DRect viewport_backup; /* The clip rectangle within the window */ - SDL_FRect clip_rect; - SDL_FRect clip_rect_backup; + SDL_DRect clip_rect; + SDL_DRect clip_rect_backup; /* Wether or not the clipping rectangle is used. */ SDL_bool clipping_enabled; @@ -245,8 +258,8 @@ struct SDL_Renderer SDL_RenderCommand *render_commands_pool; Uint32 render_command_generation; Uint32 last_queued_color; - SDL_FRect last_queued_viewport; - SDL_FRect last_queued_cliprect; + SDL_DRect last_queued_viewport; + SDL_DRect last_queued_cliprect; SDL_bool last_queued_cliprect_enabled; SDL_bool color_queued; SDL_bool viewport_queued; diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index deb324c7d..477f4e975 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/src/render/direct3d/SDL_render_d3d.c @@ -71,7 +71,9 @@ typedef struct IDirect3DSurface9 *defaultRenderTarget; IDirect3DSurface9 *currentRenderTarget; void* d3dxDLL; +#if SDL_HAVE_YUV LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS]; +#endif LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8]; size_t vertexBufferSize[8]; int currentVertexBuffer; @@ -95,6 +97,7 @@ typedef struct D3D_TextureRep texture; D3DTEXTUREFILTERTYPE scaleMode; +#if SDL_HAVE_YUV /* YV12 texture support */ SDL_bool yuv; D3D_TextureRep utexture; @@ -102,6 +105,7 @@ typedef struct Uint8 *pixels; int pitch; SDL_Rect locked_rect; +#endif } D3D_TextureData; typedef struct @@ -343,7 +347,8 @@ D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) } } -static D3DBLEND GetBlendFunc(SDL_BlendFactor factor) +static D3DBLEND +GetBlendFunc(SDL_BlendFactor factor) { switch (factor) { case SDL_BLENDFACTOR_ZERO: @@ -366,9 +371,28 @@ static D3DBLEND GetBlendFunc(SDL_BlendFactor factor) return D3DBLEND_DESTALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3DBLEND_INVDESTALPHA; - default: - return (D3DBLEND)0; + default: break; } + return (D3DBLEND) 0; +} + +static D3DBLENDOP +GetBlendEquation(SDL_BlendOperation operation) +{ + switch (operation) { + case SDL_BLENDOPERATION_ADD: + return D3DBLENDOP_ADD; + case SDL_BLENDOPERATION_SUBTRACT: + return D3DBLENDOP_SUBTRACT; + case SDL_BLENDOPERATION_REV_SUBTRACT: + return D3DBLENDOP_REVSUBTRACT; + case SDL_BLENDOPERATION_MINIMUM: + return D3DBLENDOP_MIN; + case SDL_BLENDOPERATION_MAXIMUM: + return D3DBLENDOP_MAX; + default: break; + } + return (D3DBLENDOP) 0; } static SDL_bool @@ -383,14 +407,16 @@ D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) || - !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) { + !GetBlendEquation(colorOperation) || + !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) || + !GetBlendEquation(alphaOperation)) { return SDL_FALSE; } - if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) { - return SDL_FALSE; - } - if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) { - return SDL_FALSE; + + if (!data->enableSeparateAlphaBlend) { + if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) { + return SDL_FALSE; + } } return SDL_TRUE; } @@ -534,7 +560,7 @@ D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) { return -1; } - +#if SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { texturedata->yuv = SDL_TRUE; @@ -547,6 +573,7 @@ D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) return -1; } } +#endif return 0; } @@ -563,7 +590,7 @@ D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) { return -1; } - +#if SDL_HAVE_YUV if (texturedata->yuv) { if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) { return -1; @@ -573,6 +600,7 @@ D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) return -1; } } +#endif return 0; } @@ -584,14 +612,13 @@ D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; if (!texturedata) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) { return -1; } - +#if SDL_HAVE_YUV if (texturedata->yuv) { /* Skip to the correct offset into the next texture */ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); @@ -606,6 +633,7 @@ D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, return -1; } } +#endif return 0; } @@ -621,8 +649,7 @@ D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; if (!texturedata) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { @@ -647,10 +674,9 @@ D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, IDirect3DDevice9 *device = data->device; if (!texturedata) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } - +#if SDL_HAVE_YUV texturedata->locked_rect = *rect; if (texturedata->yuv) { @@ -666,7 +692,9 @@ D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format)); *pitch = texturedata->pitch; - } else { + } else +#endif + { RECT d3drect; D3DLOCKED_RECT locked; HRESULT result; @@ -699,14 +727,17 @@ D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (!texturedata) { return; } - +#if SDL_HAVE_YUV if (texturedata->yuv) { const SDL_Rect *rect = &texturedata->locked_rect; void *pixels = (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch + rect->x * SDL_BYTESPERPIXEL(texture->format)); D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch); - } else { + } + else +#endif + { IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0); texturedata->texture.dirty = SDL_TRUE; if (data->drawstate.texture == texture) { @@ -714,10 +745,6 @@ D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) data->drawstate.shader = NULL; IDirect3DDevice9_SetPixelShader(data->device, NULL); IDirect3DDevice9_SetTexture(data->device, 0, NULL); - if (texturedata->yuv) { - IDirect3DDevice9_SetTexture(data->device, 1, NULL); - IDirect3DDevice9_SetTexture(data->device, 2, NULL); - } } } } @@ -756,8 +783,7 @@ D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture) texturedata = (D3D_TextureData *)texture->driverdata; if (!texturedata) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } /* Make sure the render target is updated if it was locked and written to */ @@ -942,8 +968,7 @@ SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSH SDL_assert(*shader == NULL); if (!texturedata) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } UpdateTextureScaleMode(data, texturedata, 0); @@ -951,7 +976,7 @@ SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSH if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) { return -1; } - +#if SDL_HAVE_YUV if (texturedata->yuv) { switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { case SDL_YUV_CONVERSION_JPEG: @@ -977,6 +1002,7 @@ SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSH return -1; } } +#endif return 0; } @@ -987,18 +1013,22 @@ SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) const SDL_BlendMode blend = cmd->data.draw.blend; if (texture != data->drawstate.texture) { +#if SDL_HAVE_YUV D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL; D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL; +#endif LPDIRECT3DPIXELSHADER9 shader = NULL; /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */ if (texture == NULL) { IDirect3DDevice9_SetTexture(data->device, 0, NULL); } +#if SDL_HAVE_YUV if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) { IDirect3DDevice9_SetTexture(data->device, 1, NULL); IDirect3DDevice9_SetTexture(data->device, 2, NULL); } +#endif if (texture && SetupTextureState(data, texture, &shader) < 0) { return -1; } @@ -1015,10 +1045,12 @@ SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) } else if (texture) { D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; UpdateDirtyTexture(data->device, &texturedata->texture); +#if SDL_HAVE_YUV if (texturedata->yuv) { UpdateDirtyTexture(data->device, &texturedata->utexture); UpdateDirtyTexture(data->device, &texturedata->vtexture); } +#endif } if (blend != data->drawstate.blend) { @@ -1030,11 +1062,15 @@ SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend))); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP, + GetBlendEquation(SDL_GetBlendModeColorOperation(blend))); if (data->enableSeparateAlphaBlend) { IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend))); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA, + GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend))); } } @@ -1276,6 +1312,7 @@ D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, RECT d3drect; D3DLOCKED_RECT locked; HRESULT result; + int status; if (data->currentRenderTarget) { backBuffer = data->currentRenderTarget; @@ -1310,7 +1347,7 @@ D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, return D3D_SetError("LockRect()", result); } - SDL_ConvertPixels(rect->w, rect->h, + status = SDL_ConvertPixels(rect->w, rect->h, D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch, format, pixels, pitch); @@ -1318,7 +1355,7 @@ D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, IDirect3DSurface9_Release(surface); - return 0; + return status; } static void @@ -1357,10 +1394,12 @@ D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) renderdata->drawstate.shader = NULL; IDirect3DDevice9_SetPixelShader(renderdata->device, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL); +#if SDL_HAVE_YUV if (data->yuv) { IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL); IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL); } +#endif } if (!data) { @@ -1368,9 +1407,11 @@ D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) } D3D_DestroyTextureRep(&data->texture); +#if SDL_HAVE_YUV D3D_DestroyTextureRep(&data->utexture); D3D_DestroyTextureRep(&data->vtexture); SDL_free(data->pixels); +#endif SDL_free(data); texture->driverdata = NULL; } @@ -1392,12 +1433,14 @@ D3D_DestroyRenderer(SDL_Renderer * renderer) IDirect3DSurface9_Release(data->currentRenderTarget); data->currentRenderTarget = NULL; } +#if SDL_HAVE_YUV for (i = 0; i < SDL_arraysize(data->shaders); ++i) { if (data->shaders[i]) { IDirect3DPixelShader9_Release(data->shaders[i]); data->shaders[i] = NULL; } } +#endif /* Release all vertex buffers */ for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { if (data->vertexBuffers[i]) { @@ -1670,7 +1713,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags) /* Set up parameters for rendering */ D3D_InitRenderState(data); - +#if SDL_HAVE_YUV if (caps.MaxSimultaneousTextures >= 3) { int i; for (i = 0; i < SDL_arraysize(data->shaders); ++i) { @@ -1684,7 +1727,7 @@ D3D_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; } } - +#endif data->drawstate.blend = SDL_BLENDMODE_INVALID; return renderer; diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 2e3518fa9..a1ce3874c 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -91,7 +91,7 @@ typedef struct int lockedTexturePositionX; int lockedTexturePositionY; D3D11_FILTER scaleMode; - +#if SDL_HAVE_YUV /* YV12 texture support */ SDL_bool yuv; ID3D11Texture2D *mainTextureU; @@ -107,6 +107,7 @@ typedef struct Uint8 *pixels; int pitch; SDL_Rect locked_rect; +#endif } D3D11_TextureData; /* Blend mode data */ @@ -487,6 +488,11 @@ D3D11_CreateDeviceResources(SDL_Renderer * renderer) creationFlags |= D3D11_CREATE_DEVICE_DEBUG; } + /* Create a single-threaded device unless the app requests otherwise. */ + if (!SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) { + creationFlags |= D3D11_CREATE_DEVICE_SINGLETHREADED; + } + /* Create the Direct3D 11 API device object and a corresponding context. */ result = D3D11CreateDeviceFunc( data->dxgiAdapter, @@ -992,6 +998,16 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) goto done; } + /* Set the swap chain target immediately, so that a target is always set + * even before we get to SetDrawState. Without this it's possible to hit + * null references in places like ReadPixels! + */ + ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, + 1, + &data->mainRenderTargetView, + NULL + ); + data->viewportDirty = SDL_TRUE; done: @@ -1109,10 +1125,9 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); } - +#if SDL_HAVE_YUV if (texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { textureData->yuv = SDL_TRUE; @@ -1127,8 +1142,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); } result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, @@ -1138,8 +1152,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); } } @@ -1160,11 +1173,10 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); } } - +#endif /* SDL_HAVE_YUV */ resourceViewDesc.Format = textureDesc.Format; resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; resourceViewDesc.Texture2D.MostDetailedMip = 0; @@ -1176,10 +1188,9 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); } - +#if SDL_HAVE_YUV if (textureData->yuv) { result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, (ID3D11Resource *)textureData->mainTextureU, @@ -1188,8 +1199,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); } result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, (ID3D11Resource *)textureData->mainTextureV, @@ -1198,8 +1208,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); } } @@ -1215,8 +1224,7 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) ); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); } } @@ -1232,11 +1240,10 @@ D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) &textureData->mainTextureRenderTargetView); if (FAILED(result)) { D3D11_DestroyTexture(renderer, texture); - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result); } } - +#endif /* SDL_HAVE_YUV */ return 0; } @@ -1343,6 +1350,7 @@ D3D11_DestroyTexture(SDL_Renderer * renderer, SAFE_RELEASE(data->mainTextureResourceView); SAFE_RELEASE(data->mainTextureRenderTargetView); SAFE_RELEASE(data->stagingTexture); +#if SDL_HAVE_YUV SAFE_RELEASE(data->mainTextureU); SAFE_RELEASE(data->mainTextureResourceViewU); SAFE_RELEASE(data->mainTextureV); @@ -1350,6 +1358,7 @@ D3D11_DestroyTexture(SDL_Renderer * renderer, SAFE_RELEASE(data->mainTextureNV); SAFE_RELEASE(data->mainTextureResourceViewNV); SDL_free(data->pixels); +#endif SDL_free(data); texture->driverdata = NULL; } @@ -1379,8 +1388,7 @@ D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *tex NULL, &stagingTexture); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); } /* Get a write-only pointer to data in the staging texture: */ @@ -1392,9 +1400,8 @@ D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *tex &textureMemory ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); SAFE_RELEASE(stagingTexture); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); } src = (const Uint8 *)pixels; @@ -1446,14 +1453,13 @@ D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata; if (!textureData) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch) < 0) { return -1; } - +#if SDL_HAVE_YUV if (textureData->yuv) { /* Skip to the correct offset into the next texture */ srcPixels = (const void*)((const Uint8*)srcPixels + rect->h * srcPitch); @@ -1477,6 +1483,7 @@ D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, return -1; } } +#endif /* SDL_HAVE_YUV */ return 0; } @@ -1492,8 +1499,7 @@ D3D11_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata; if (!textureData) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { @@ -1518,8 +1524,7 @@ D3D11_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata; if (!textureData) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { @@ -1544,10 +1549,9 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, D3D11_MAPPED_SUBRESOURCE textureMemory; if (!textureData) { - SDL_SetError("Texture is not currently available"); - return -1; + return SDL_SetError("Texture is not currently available"); } - +#if SDL_HAVE_YUV if (textureData->yuv || textureData->nv12) { /* It's more efficient to upload directly... */ if (!textureData->pixels) { @@ -1564,7 +1568,7 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, *pitch = textureData->pitch; return 0; } - +#endif if (textureData->stagingTexture) { return SDL_SetError("texture is already locked"); } @@ -1589,8 +1593,7 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, NULL, &textureData->stagingTexture); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); } /* Get a write-only pointer to data in the staging texture: */ @@ -1602,9 +1605,8 @@ D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, &textureMemory ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); SAFE_RELEASE(textureData->stagingTexture); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); } /* Make note of where the staging texture will be written to @@ -1630,7 +1632,7 @@ D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (!textureData) { return; } - +#if SDL_HAVE_YUV if (textureData->yuv || textureData->nv12) { const SDL_Rect *rect = &textureData->locked_rect; void *pixels = @@ -1639,7 +1641,7 @@ D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) D3D11_UpdateTexture(renderer, texture, rect, pixels, textureData->pitch); return; } - +#endif /* Commit the pixel buffer's changes back to the staging texture: */ ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)textureData->stagingTexture, @@ -1802,8 +1804,7 @@ D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, &mappedResource ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result); } SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes); ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffers[vbidx], 0); @@ -1830,8 +1831,7 @@ D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, &rendererData->vertexBuffers[vbidx] ); if (FAILED(result)) { - WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result); - return -1; + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result); } rendererData->vertexBufferSizes[vbidx] = dataSizeInBytes; @@ -2084,7 +2084,7 @@ D3D11_SetCopyState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, const default: return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); } - +#if SDL_HAVE_YUV if (textureData->yuv) { ID3D11ShaderResourceView *shaderResources[] = { textureData->mainTextureResourceView, @@ -2135,7 +2135,7 @@ D3D11_SetCopyState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, const SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix); } - +#endif /* SDL_HAVE_YUV */ return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_RGB], 1, &textureData->mainTextureResourceView, textureSampler, matrix); } @@ -2338,30 +2338,20 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, /* Copy the data into the desired buffer, converting pixels to the * desired format at the same time: */ - if (SDL_ConvertPixels( + status = SDL_ConvertPixels( rect->w, rect->h, D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), textureMemory.pData, textureMemory.RowPitch, format, pixels, - pitch) != 0) { - /* When SDL_ConvertPixels fails, it'll have already set the format. - * Get the error message, and attach some extra data to it. - */ - char errorMessage[1024]; - SDL_snprintf(errorMessage, sizeof(errorMessage), "%s, Convert Pixels failed: %s", __FUNCTION__, SDL_GetError()); - SDL_SetError("%s", errorMessage); - goto done; - } + pitch); /* Unmap the texture: */ ID3D11DeviceContext_Unmap(data->d3dContext, (ID3D11Resource *)stagingTexture, 0); - status = 0; - done: SAFE_RELEASE(backBuffer); SAFE_RELEASE(stagingTexture); @@ -2454,6 +2444,7 @@ D3D11_CreateRenderer(SDL_Window * window, Uint32 flags) data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data)); if (!data) { + SDL_free(renderer); SDL_OutOfMemory(); return NULL; } diff --git a/src/render/direct3d11/SDL_shaders_d3d11.c b/src/render/direct3d11/SDL_shaders_d3d11.c index 4c49cfe34..3a6807b5f 100644 --- a/src/render/direct3d11/SDL_shaders_d3d11.c +++ b/src/render/direct3d11/SDL_shaders_d3d11.c @@ -1886,9 +1886,10 @@ static struct { const void *shader_data; SIZE_T shader_size; -} D3D11_shaders[] = { +} D3D11_shaders[NUM_SHADERS] = { { D3D11_PixelShader_Colors, sizeof(D3D11_PixelShader_Colors) }, { D3D11_PixelShader_Textures, sizeof(D3D11_PixelShader_Textures) }, +#if SDL_HAVE_YUV { D3D11_PixelShader_YUV_JPEG, sizeof(D3D11_PixelShader_YUV_JPEG) }, { D3D11_PixelShader_YUV_BT601, sizeof(D3D11_PixelShader_YUV_BT601) }, { D3D11_PixelShader_YUV_BT709, sizeof(D3D11_PixelShader_YUV_BT709) }, @@ -1898,6 +1899,7 @@ static struct { D3D11_PixelShader_NV21_JPEG, sizeof(D3D11_PixelShader_NV21_JPEG) }, { D3D11_PixelShader_NV21_BT601, sizeof(D3D11_PixelShader_NV21_BT601) }, { D3D11_PixelShader_NV21_BT709, sizeof(D3D11_PixelShader_NV21_BT709) }, +#endif }; int D3D11_CreateVertexShader(ID3D11Device1 *d3dDevice, ID3D11VertexShader **vertexShader, ID3D11InputLayout **inputLayout) diff --git a/src/render/direct3d11/SDL_shaders_d3d11.h b/src/render/direct3d11/SDL_shaders_d3d11.h index d25a79ada..d877c0906 100644 --- a/src/render/direct3d11/SDL_shaders_d3d11.h +++ b/src/render/direct3d11/SDL_shaders_d3d11.h @@ -25,6 +25,7 @@ typedef enum { SHADER_SOLID, SHADER_RGB, +#if SDL_HAVE_YUV SHADER_YUV_JPEG, SHADER_YUV_BT601, SHADER_YUV_BT709, @@ -34,6 +35,7 @@ typedef enum { SHADER_NV21_JPEG, SHADER_NV21_BT601, SHADER_NV21_BT709, +#endif NUM_SHADERS } D3D11_Shader; diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m index b017abc63..afb2b18dd 100644 --- a/src/render/metal/SDL_render_metal.m +++ b/src/render/metal/SDL_render_metal.m @@ -169,11 +169,12 @@ @interface METAL_TextureData : NSObject @property (nonatomic, retain) id mtltexture_uv; @property (nonatomic, retain) id mtlsampler; @property (nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction; +#if SDL_HAVE_YUV @property (nonatomic, assign) BOOL yuv; @property (nonatomic, assign) BOOL nv12; @property (nonatomic, assign) size_t conversionBufferOffset; +#endif @property (nonatomic, assign) BOOL hasdata; - @property (nonatomic, retain) id lockedbuffer; @property (nonatomic, assign) SDL_Rect lockedrect; @end @@ -607,14 +608,14 @@ - (void)dealloc mtltexdesc.usage = MTLTextureUsageShaderRead; } } - + id mtltexture = [data.mtldevice newTextureWithDescriptor:mtltexdesc]; if (mtltexture == nil) { return SDL_SetError("Texture allocation failed"); } id mtltexture_uv = nil; - +#if SDL_HAVE_YUV BOOL yuv = (texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12); BOOL nv12 = (texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21); @@ -639,7 +640,7 @@ - (void)dealloc return SDL_SetError("Texture allocation failed"); } } - +#endif /* SDL_HAVE_YUV */ METAL_TextureData *texturedata = [[METAL_TextureData alloc] init]; if (texture->scaleMode == SDL_ScaleModeNearest) { texturedata.mtlsampler = data.mtlsamplernearest; @@ -648,7 +649,7 @@ - (void)dealloc } texturedata.mtltexture = mtltexture; texturedata.mtltexture_uv = mtltexture_uv; - +#if SDL_HAVE_YUV texturedata.yuv = yuv; texturedata.nv12 = nv12; @@ -658,10 +659,12 @@ - (void)dealloc texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV12; } else if (texture->format == SDL_PIXELFORMAT_NV21) { texturedata.fragmentFunction = SDL_METAL_FRAGMENT_NV21; - } else { + } else +#endif + { texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY; } - +#if SDL_HAVE_YUV if (yuv || nv12) { size_t offset = 0; SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionModeForResolution(texture->w, texture->h); @@ -673,7 +676,7 @@ - (void)dealloc } texturedata.conversionBufferOffset = offset; } - +#endif texture->driverdata = (void*)CFBridgingRetain(texturedata); #if !__has_feature(objc_arc) @@ -895,7 +898,7 @@ - (void)dealloc if (METAL_UpdateTextureInternal(renderer, texturedata, texturedata.mtltexture, *rect, 0, pixels, pitch) < 0) { return -1; } - +#if SDL_HAVE_YUV if (texturedata.yuv) { int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0; int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1; @@ -925,7 +928,7 @@ - (void)dealloc return -1; } } - +#endif texturedata.hasdata = YES; return 0; @@ -1006,10 +1009,12 @@ - (void)dealloc } *pitch = SDL_BYTESPERPIXEL(texture->format) * rect->w; - +#if SDL_HAVE_YUV if (texturedata.yuv || texturedata.nv12) { buffersize = ((*pitch) * rect->h) + (2 * (*pitch + 1) / 2) * ((rect->h + 1) / 2); - } else { + } else +#endif + { buffersize = (*pitch) * rect->h; } @@ -1063,7 +1068,7 @@ - (void)dealloc destinationSlice:0 destinationLevel:0 destinationOrigin:MTLOriginMake(rect.x, rect.y, 0)]; - +#if SDL_HAVE_YUV if (texturedata.yuv) { int Uslice = texture->format == SDL_PIXELFORMAT_YV12 ? 1 : 0; int Vslice = texture->format == SDL_PIXELFORMAT_YV12 ? 0 : 1; @@ -1103,7 +1108,7 @@ - (void)dealloc destinationLevel:0 destinationOrigin:MTLOriginMake(UVrect.x, UVrect.y, 0)]; } - +#endif [blitcmd endEncoding]; [data.mtlcmdbuffer commit]; @@ -1360,22 +1365,29 @@ - (void)dealloc } if (statecache->cliprect_dirty) { - MTLScissorRect mtlrect; + SDL_Rect output; + SDL_Rect clip; if (statecache->cliprect_enabled) { - const SDL_Rect *rect = &statecache->cliprect; - mtlrect.x = statecache->viewport.x + rect->x; - mtlrect.y = statecache->viewport.y + rect->y; - mtlrect.width = rect->w; - mtlrect.height = rect->h; + clip = statecache->cliprect; + clip.x += statecache->viewport.x; + clip.y += statecache->viewport.y; } else { - mtlrect.x = statecache->viewport.x; - mtlrect.y = statecache->viewport.y; - mtlrect.width = statecache->viewport.w; - mtlrect.height = statecache->viewport.h; + clip = statecache->viewport; } - if (mtlrect.width > 0 && mtlrect.height > 0) { + + /* Set Scissor Rect Validation: w/h must be <= render pass */ + SDL_zero(output); + METAL_GetOutputSize(renderer, &output.w, &output.h); + + if (SDL_IntersectRect(&output, &clip, &clip)) { + MTLScissorRect mtlrect; + mtlrect.x = clip.x; + mtlrect.y = clip.y; + mtlrect.width = clip.w; + mtlrect.height = clip.h; [data.mtlcmdencoder setScissorRect:mtlrect]; } + statecache->cliprect_dirty = SDL_FALSE; } @@ -1423,10 +1435,12 @@ - (void)dealloc } [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0]; +#if SDL_HAVE_YUV if (texturedata.yuv || texturedata.nv12) { [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture_uv atIndex:1]; [data.mtlcmdencoder setFragmentBuffer:data.mtlbufconstants offset:texturedata.conversionBufferOffset atIndex:1]; } +#endif statecache->texture = texture; } return SDL_TRUE; diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 47d5ae8a1..b5af52af3 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -30,6 +30,11 @@ #include #endif +#ifdef SDL_VIDEO_VITA_PVR_OGL +#include +#include +#endif + /* To prevent unnecessary window recreation, * these should match the defaults selected in SDL_GL_ResetAttributes */ @@ -319,6 +324,20 @@ GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h) return result; } +static void +GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ + /* If the window x/y/w/h changed at all, assume the viewport has been + * changed behind our backs. x/y changes might seem weird but viewport + * resets have been observed on macOS at minimum! + */ + if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED || + event->event == SDL_WINDOWEVENT_MOVED) { + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + data->drawstate.viewport_dirty = SDL_TRUE; + } +} + static int GL_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) { @@ -1038,7 +1057,7 @@ GL_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *te return 0; } -static void +static int SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader shader) { const SDL_BlendMode blend = cmd->data.draw.blend; @@ -1111,7 +1130,8 @@ SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader } } - vertex_array = cmd->command == SDL_RENDERCMD_DRAW_LINES + vertex_array = cmd->command == SDL_RENDERCMD_DRAW_POINTS + || cmd->command == SDL_RENDERCMD_DRAW_LINES || cmd->command == SDL_RENDERCMD_GEOMETRY; color_array = cmd->command == SDL_RENDERCMD_GEOMETRY; texture_array = cmd->data.draw.texture != NULL; @@ -1144,9 +1164,11 @@ SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const GL_Shader } data->drawstate.texture_array = texture_array; } + + return 0; } -static void +static int SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) { SDL_Texture *texture = cmd->data.draw.texture; @@ -1182,6 +1204,8 @@ SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) data->drawstate.texture = texture; } + + return 0; } static int @@ -1189,7 +1213,6 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic { /* !!! FIXME: it'd be nice to use a vertex buffer instead of immediate mode... */ GL_RenderData *data = (GL_RenderData *) renderer->driverdata; - size_t i; if (GL_ActivateRenderer(renderer) < 0) { return -1; @@ -1208,9 +1231,9 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic } #ifdef __MACOSX__ - // On macOS, moving the window seems to invalidate the OpenGL viewport state, - // so don't bother trying to persist it across frames; always reset it. - // Workaround for: https://github.com/libsdl-org/SDL/issues/1504 + // On macOS on older systems, the OpenGL view change and resize events aren't + // necessarily synchronized, so just always reset it. + // Workaround for: https://discourse.libsdl.org/t/sdl-2-0-22-prerelease/35306/6 data->drawstate.viewport_dirty = SDL_TRUE; #endif @@ -1244,6 +1267,7 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; data->drawstate.cliprect_enabled_dirty = SDL_TRUE; } + if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) { SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)); data->drawstate.cliprect_dirty = SDL_TRUE; @@ -1272,31 +1296,6 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic } data->glClear(GL_COLOR_BUFFER_BIT); - - break; - } - - case SDL_RENDERCMD_DRAW_POINTS: { - const size_t count = cmd->data.draw.count; - const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); - SetDrawState(data, cmd, SHADER_SOLID); - data->glBegin(GL_POINTS); - for (i = 0; i < count; i++, verts += 2) { - data->glVertex2f(verts[0], verts[1]); - } - data->glEnd(); - break; - } - - case SDL_RENDERCMD_DRAW_LINES: { - const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); - const size_t count = cmd->data.draw.count; - SDL_assert(count >= 2); - SetDrawState(data, cmd, SHADER_SOLID); - - /* SetDrawState handles glEnableClientState. */ - data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, verts); - data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count); break; } @@ -1309,42 +1308,113 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic case SDL_RENDERCMD_COPY_EX: /* unused */ break; + case SDL_RENDERCMD_DRAW_LINES: { + if (SetDrawState(data, cmd, SHADER_SOLID) == 0) { + size_t count = cmd->data.draw.count; + const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); + + /* SetDrawState handles glEnableClientState. */ + data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, verts); + + if (count > 2) { + /* joined lines cannot be grouped */ + data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei)count); + } else { + /* let's group non joined lines */ + SDL_RenderCommand *finalcmd = cmd; + SDL_RenderCommand *nextcmd = cmd->next; + SDL_BlendMode thisblend = cmd->data.draw.blend; + + while (nextcmd != NULL) { + const SDL_RenderCommandType nextcmdtype = nextcmd->command; + if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) { + break; /* can't go any further on this draw call, different render command up next. */ + } else if (nextcmd->data.draw.count != 2) { + break; /* can't go any further on this draw call, those are joined lines */ + } else if (nextcmd->data.draw.blend != thisblend) { + break; /* can't go any further on this draw call, different blendmode copy up next. */ + } else { + finalcmd = nextcmd; /* we can combine copy operations here. Mark this one as the furthest okay command. */ + count += nextcmd->data.draw.count; + } + nextcmd = nextcmd->next; + } + + data->glDrawArrays(GL_LINES, 0, (GLsizei)count); + cmd = finalcmd; /* skip any copy commands we just combined in here. */ + } + } + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: case SDL_RENDERCMD_GEOMETRY: { - const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); - SDL_Texture *texture = cmd->data.draw.texture; - const size_t count = cmd->data.draw.count; + /* as long as we have the same copy command in a row, with the + same texture, we can combine them all into a single draw call. */ + SDL_Texture *thistexture = cmd->data.draw.texture; + SDL_BlendMode thisblend = cmd->data.draw.blend; + const SDL_RenderCommandType thiscmdtype = cmd->command; + SDL_RenderCommand *finalcmd = cmd; + SDL_RenderCommand *nextcmd = cmd->next; + size_t count = cmd->data.draw.count; + int ret; + while (nextcmd != NULL) { + const SDL_RenderCommandType nextcmdtype = nextcmd->command; + if (nextcmdtype != thiscmdtype) { + break; /* can't go any further on this draw call, different render command up next. */ + } else if (nextcmd->data.draw.texture != thistexture || nextcmd->data.draw.blend != thisblend) { + break; /* can't go any further on this draw call, different texture/blendmode copy up next. */ + } else { + finalcmd = nextcmd; /* we can combine copy operations here. Mark this one as the furthest okay command. */ + count += nextcmd->data.draw.count; + } + nextcmd = nextcmd->next; + } - if (texture) { - SetCopyState(data, cmd); + if (thistexture) { + ret = SetCopyState(data, cmd); } else { - SetDrawState(data, cmd, SHADER_SOLID); + ret = SetDrawState(data, cmd, SHADER_SOLID); } - { - Uint32 color = data->drawstate.color; - GLubyte a = (GLubyte)((color >> 24) & 0xFF); - GLubyte r = (GLubyte)((color >> 16) & 0xFF); - GLubyte g = (GLubyte)((color >> 8) & 0xFF); - GLubyte b = (GLubyte)((color >> 0) & 0xFF); + if (ret == 0) { + const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first); + int op = GL_TRIANGLES; /* SDL_RENDERCMD_GEOMETRY */ + if (thiscmdtype == SDL_RENDERCMD_DRAW_POINTS) { + op = GL_POINTS; + } - /* SetDrawState handles glEnableClientState. */ - if (texture) { - data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 5, verts + 0); - data->glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(float) * 5, verts + 2); - data->glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 5, verts + 3); + if (thiscmdtype == SDL_RENDERCMD_DRAW_POINTS) { + /* SetDrawState handles glEnableClientState. */ + data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 2, verts); } else { - data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 3, verts + 0); - data->glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(float) * 3, verts + 2); + /* SetDrawState handles glEnableClientState. */ + if (thistexture) { + data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 5, verts + 0); + data->glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(float) * 5, verts + 2); + data->glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 5, verts + 3); + } else { + data->glVertexPointer(2, GL_FLOAT, sizeof(float) * 3, verts + 0); + data->glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(float) * 3, verts + 2); + } } - data->glDrawArrays(GL_TRIANGLES, 0, (GLsizei) count); + data->glDrawArrays(op, 0, (GLsizei) count); /* Restore previously set color when we're done. */ - data->glColor4ub(r, g, b, a); + if (thiscmdtype != SDL_RENDERCMD_DRAW_POINTS) { + Uint32 color = data->drawstate.color; + GLubyte a = (GLubyte)((color >> 24) & 0xFF); + GLubyte r = (GLubyte)((color >> 16) & 0xFF); + GLubyte g = (GLubyte)((color >> 8) & 0xFF); + GLubyte b = (GLubyte)((color >> 0) & 0xFF); + data->glColor4ub(r, g, b, a); + } } - break; - } + cmd = finalcmd; /* skip any copy commands we just combined in here. */ + break; + } case SDL_RENDERCMD_NO_OP: break; @@ -1639,6 +1709,32 @@ GL_SetVSync(SDL_Renderer * renderer, const int vsync) return retval; } +static SDL_bool +GL_IsProbablyAccelerated(const GL_RenderData *data) +{ + /*const char *vendor = (const char *) data->glGetString(GL_VENDOR);*/ + const char *renderer = (const char *) data->glGetString(GL_RENDERER); + +#ifdef __WINDOWS__ + if (SDL_strcmp(renderer, "GDI Generic") == 0) { + return SDL_FALSE; /* Microsoft's fallback software renderer. Fix your system! */ + } +#endif + +#ifdef __APPLE__ + if (SDL_strcmp(renderer, "Apple Software Renderer") == 0) { + return SDL_FALSE; /* (a probably very old) Apple software-based OpenGL. */ + } +#endif + + if (SDL_strcmp(renderer, "Software Rasterizer") == 0) { + return SDL_FALSE; /* (a probably very old) Software Mesa, or some other generic thing. */ + } + + /* !!! FIXME: swrast? llvmpipe? softpipe? */ + + return SDL_TRUE; +} static SDL_Renderer * GL_CreateRenderer(SDL_Window * window, Uint32 flags) @@ -1649,11 +1745,14 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) Uint32 window_flags; int profile_mask = 0, major = 0, minor = 0; SDL_bool changed_window = SDL_FALSE; + const char *hint; + SDL_bool non_power_of_two_supported = 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); +#ifndef SDL_VIDEO_VITA_PVR_OGL window_flags = SDL_GetWindowFlags(window); if (!(window_flags & SDL_WINDOW_OPENGL) || profile_mask == SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) { @@ -1667,6 +1766,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) goto error; } } +#endif renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { @@ -1681,6 +1781,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) goto error; } + renderer->WindowEvent = GL_WindowEvent; renderer->GetOutputSize = GL_GetOutputSize; renderer->SupportsBlendMode = GL_SupportsBlendMode; renderer->CreateTexture = GL_CreateTexture; @@ -1707,7 +1808,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; + renderer->info.flags = 0; /* will set some flags below. */ renderer->driverdata = data; renderer->window = window; @@ -1731,6 +1832,10 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) goto error; } + if (GL_IsProbablyAccelerated(data)) { + renderer->info.flags |= SDL_RENDERER_ACCELERATED; + } + #ifdef __MACOSX__ /* Enable multi-threaded rendering */ /* Disabled until Ryan finishes his VBO/PBO code... @@ -1764,15 +1869,37 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) data->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); } + hint = SDL_getenv("GL_ARB_texture_non_power_of_two"); + if (!hint || *hint != '0') { + SDL_bool isGL2 = SDL_FALSE; + const char *verstr = (const char *)data->glGetString(GL_VERSION); + if (verstr) { + char verbuf[16]; + char *ptr; + SDL_strlcpy(verbuf, verstr, sizeof (verbuf)); + ptr = SDL_strchr(verbuf, '.'); + if (ptr) { + *ptr = '\0'; + if (SDL_atoi(verbuf) >= 2) { + isGL2 = SDL_TRUE; + } + } + } + if (isGL2 || SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) { + non_power_of_two_supported = SDL_TRUE; + } + } + data->textype = GL_TEXTURE_2D; - if (SDL_GL_ExtensionSupported("GL_ARB_texture_non_power_of_two")) { + if (non_power_of_two_supported) { data->GL_ARB_texture_non_power_of_two_supported = SDL_TRUE; + data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); + renderer->info.max_texture_width = value; + renderer->info.max_texture_height = value; } else if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle") || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) { data->GL_ARB_texture_rectangle_supported = SDL_TRUE; data->textype = GL_TEXTURE_RECTANGLE_ARB; - } - if (data->GL_ARB_texture_rectangle_supported) { data->glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &value); renderer->info.max_texture_width = value; renderer->info.max_texture_height = value; @@ -1797,7 +1924,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) } SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s", data->shaders ? "ENABLED" : "DISABLED"); - +#if SDL_HAVE_YUV /* We support YV12 textures using 3 textures and a shader */ if (data->shaders && data->num_texture_units >= 3) { renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; @@ -1805,7 +1932,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12; renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21; } - +#endif #ifdef __MACOSX__ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_UYVY; #endif diff --git a/src/render/opengl/SDL_shaders_gl.c b/src/render/opengl/SDL_shaders_gl.c index b4f7aa39f..4db083555 100644 --- a/src/render/opengl/SDL_shaders_gl.c +++ b/src/render/opengl/SDL_shaders_gl.c @@ -284,7 +284,7 @@ static const char *shader_source[NUM_SHADERS][2] = " gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n" "}" }, - +#if SDL_HAVE_YUV /* SHADER_YUV_JPEG */ { /* vertex shader */ @@ -384,6 +384,7 @@ static const char *shader_source[NUM_SHADERS][2] = BT709_SHADER_CONSTANTS NV21_SHADER_BODY }, +#endif /* SDL_HAVE_YUV */ }; static SDL_bool diff --git a/src/render/opengl/SDL_shaders_gl.h b/src/render/opengl/SDL_shaders_gl.h index 56382b4be..d3e6c398a 100644 --- a/src/render/opengl/SDL_shaders_gl.h +++ b/src/render/opengl/SDL_shaders_gl.h @@ -32,6 +32,7 @@ typedef enum { SHADER_SOLID, SHADER_RGB, SHADER_RGBA, +#if SDL_HAVE_YUV SHADER_YUV_JPEG, SHADER_YUV_BT601, SHADER_YUV_BT709, @@ -43,6 +44,7 @@ typedef enum { SHADER_NV21_JPEG, SHADER_NV21_BT601, SHADER_NV21_BT709, +#endif NUM_SHADERS } GL_Shader; diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index c38ee9723..c2f5d640f 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -28,6 +28,17 @@ #include "../../video/SDL_blit.h" #include "SDL_shaders_gles2.h" +/* WebGL doesn't offer client-side arrays, so use Vertex Buffer Objects + on Emscripten, which converts GLES2 into WebGL calls. + In all other cases, attempt to use client-side arrays, as they tend to + be dramatically faster when not batching, and about the same when + we are. */ +#if defined(__EMSCRIPTEN__) +#define USE_VERTEX_BUFFER_OBJECTS 1 +#else +#define USE_VERTEX_BUFFER_OBJECTS 0 +#endif + /* To prevent unnecessary window recreation, * these should match the defaults selected in SDL_GL_ResetAttributes */ @@ -151,9 +162,12 @@ typedef struct GLES2_RenderData GLES2_ProgramCache program_cache; Uint8 clear_r, clear_g, clear_b, clear_a; +#if USE_VERTEX_BUFFER_OBJECTS GLuint vertex_buffers[8]; size_t vertex_buffer_size[8]; int current_vertex_buffer; +#endif + GLES2_DrawStateCache drawstate; } GLES2_RenderData; @@ -547,6 +561,7 @@ GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int case GLES2_IMAGESOURCE_TEXTURE_BGR: ftype = GLES2_SHADER_FRAGMENT_TEXTURE_BGR; break; +#if SDL_HAVE_YUV case GLES2_IMAGESOURCE_TEXTURE_YUV: switch (SDL_GetYUVConversionModeForResolution(w, h)) { case SDL_YUV_CONVERSION_JPEG: @@ -603,6 +618,7 @@ GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int goto fault; } break; +#endif /* SDL_HAVE_YUV */ case GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES: ftype = GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES; break; @@ -844,7 +860,7 @@ GLES2_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture } static int -SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc) +SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_ImageSource imgsrc, void *vertices) { SDL_Texture *texture = cmd->data.draw.texture; const SDL_BlendMode blend = cmd->data.draw.blend; @@ -884,39 +900,14 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I data->drawstate.cliprect_dirty = SDL_FALSE; } - if (texture != data->drawstate.texture) { - if ((texture != NULL) != data->drawstate.texturing) { - if (texture == NULL) { - data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD); - data->drawstate.texturing = SDL_FALSE; - } else { - data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD); - data->drawstate.texturing = SDL_TRUE; - } - } - - if (texture) { - GLES2_TextureData *tdata = (GLES2_TextureData *) texture->driverdata; -#if SDL_HAVE_YUV - if (tdata->yuv) { - data->glActiveTexture(GL_TEXTURE2); - data->glBindTexture(tdata->texture_type, tdata->texture_v); - - data->glActiveTexture(GL_TEXTURE1); - data->glBindTexture(tdata->texture_type, tdata->texture_u); - - data->glActiveTexture(GL_TEXTURE0); - } else if (tdata->nv12) { - data->glActiveTexture(GL_TEXTURE1); - data->glBindTexture(tdata->texture_type, tdata->texture_u); - - data->glActiveTexture(GL_TEXTURE0); - } -#endif - data->glBindTexture(tdata->texture_type, tdata->texture); + if ((texture != NULL) != data->drawstate.texturing) { + if (texture == NULL) { + data->glDisableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD); + data->drawstate.texturing = SDL_FALSE; + } else { + data->glEnableVertexAttribArray((GLenum) GLES2_ATTRIBUTE_TEXCOORD); + data->drawstate.texturing = SDL_TRUE; } - - data->drawstate.texture = texture; } if (texture) { @@ -926,7 +917,7 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I } if (texture) { - SDL_Vertex *verts = (SDL_Vertex *) (cmd->data.draw.first); + SDL_Vertex *verts = (SDL_Vertex *) (((Uint8 *) vertices) + cmd->data.draw.first); data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->tex_coord); } @@ -960,7 +951,7 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I /* all drawing commands use this */ { - SDL_VertexSolid *verts = (SDL_VertexSolid *) (cmd->data.draw.first); + SDL_VertexSolid *verts = (SDL_VertexSolid *) (((Uint8 *) vertices) + cmd->data.draw.first); data->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *) &verts->position); data->glVertexAttribPointer(GLES2_ATTRIBUTE_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE /* Normalized */, stride, (const GLvoid *) &verts->color); } @@ -969,11 +960,12 @@ SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, const GLES2_I } static int -SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) +SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices) { GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata; GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR; SDL_Texture *texture = cmd->data.draw.texture; + int ret; /* Pick an appropriate shader */ if (renderer->target) { @@ -1028,6 +1020,7 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) break; } break; +#if SDL_HAVE_YUV case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_YV12: sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; @@ -1038,6 +1031,7 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) case SDL_PIXELFORMAT_NV21: sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; break; +#endif case SDL_PIXELFORMAT_EXTERNAL_OES: sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; break; @@ -1061,6 +1055,7 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) case SDL_PIXELFORMAT_BGR888: sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR; break; +#if SDL_HAVE_YUV case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_YV12: sourceType = GLES2_IMAGESOURCE_TEXTURE_YUV; @@ -1071,6 +1066,7 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) case SDL_PIXELFORMAT_NV21: sourceType = GLES2_IMAGESOURCE_TEXTURE_NV21; break; +#endif case SDL_PIXELFORMAT_EXTERNAL_OES: sourceType = GLES2_IMAGESOURCE_TEXTURE_EXTERNAL_OES; break; @@ -1079,7 +1075,31 @@ SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) } } - return SetDrawState(data, cmd, sourceType); + ret = SetDrawState(data, cmd, sourceType, vertices); + + if (texture != data->drawstate.texture) { + GLES2_TextureData *tdata = (GLES2_TextureData *) texture->driverdata; +#if SDL_HAVE_YUV + if (tdata->yuv) { + data->glActiveTexture(GL_TEXTURE2); + data->glBindTexture(tdata->texture_type, tdata->texture_v); + + data->glActiveTexture(GL_TEXTURE1); + data->glBindTexture(tdata->texture_type, tdata->texture_u); + + data->glActiveTexture(GL_TEXTURE0); + } else if (tdata->nv12) { + data->glActiveTexture(GL_TEXTURE1); + data->glBindTexture(tdata->texture_type, tdata->texture_u); + + data->glActiveTexture(GL_TEXTURE0); + } +#endif + data->glBindTexture(tdata->texture_type, tdata->texture); + data->drawstate.texture = texture; + } + + return ret; } static int @@ -1087,8 +1107,11 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver { GLES2_RenderData *data = (GLES2_RenderData *) renderer->driverdata; const SDL_bool colorswap = (renderer->target && (renderer->target->format == SDL_PIXELFORMAT_ARGB8888 || renderer->target->format == SDL_PIXELFORMAT_RGB888)); + +#if USE_VERTEX_BUFFER_OBJECTS const int vboidx = data->current_vertex_buffer; const GLuint vbo = data->vertex_buffers[vboidx]; +#endif if (GLES2_ActivateRenderer(renderer) < 0) { return -1; @@ -1106,6 +1129,7 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver } } +#if USE_VERTEX_BUFFER_OBJECTS /* upload the new VBO data for this set of commands. */ data->glBindBuffer(GL_ARRAY_BUFFER, vbo); if (data->vertex_buffer_size[vboidx] < vertsize) { @@ -1120,6 +1144,8 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver if (data->current_vertex_buffer >= SDL_arraysize(data->vertex_buffers)) { data->current_vertex_buffer = 0; } + vertices = NULL; /* attrib pointers will be offsets into the VBO. */ +#endif while (cmd) { switch (cmd->command) { @@ -1184,7 +1210,7 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver break; case SDL_RENDERCMD_DRAW_LINES: { - if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) { + if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices) == 0) { size_t count = cmd->data.draw.count; if (count > 2) { /* joined lines cannot be grouped */ @@ -1242,9 +1268,9 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver } if (thistexture) { - ret = SetCopyState(renderer, cmd); + ret = SetCopyState(renderer, cmd, vertices); } else { - ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID); + ret = SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID, vertices); } if (ret == 0) { @@ -1308,8 +1334,10 @@ GLES2_DestroyRenderer(SDL_Renderer *renderer) data->framebuffers = nextnode; } +#if USE_VERTEX_BUFFER_OBJECTS data->glDeleteBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers); GL_CheckError("", renderer); +#endif SDL_GL_DeleteContext(data->context); } @@ -1342,6 +1370,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) format = GL_RGBA; type = GL_UNSIGNED_BYTE; break; +#if SDL_HAVE_YUV case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_NV12: @@ -1349,6 +1378,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) format = GL_LUMINANCE; type = GL_UNSIGNED_BYTE; break; +#endif #ifdef GL_TEXTURE_EXTERNAL_OES case SDL_PIXELFORMAT_EXTERNAL_OES: format = GL_NONE; @@ -2071,8 +2101,10 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value); renderer->info.max_texture_height = value; +#if USE_VERTEX_BUFFER_OBJECTS /* we keep a few of these and cycle through them, so data can live for a few frames. */ data->glGenBuffers(SDL_arraysize(data->vertex_buffers), data->vertex_buffers); +#endif data->framebuffers = NULL; data->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &window_framebuffer); @@ -2105,11 +2137,12 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->SetVSync = GLES2_SetVSync; renderer->GL_BindTexture = GLES2_BindTexture; renderer->GL_UnbindTexture = GLES2_UnbindTexture; - +#if SDL_HAVE_YUV renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV12; renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_NV21; +#endif #ifdef GL_TEXTURE_EXTERNAL_OES renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_EXTERNAL_OES; #endif @@ -2165,3 +2198,4 @@ SDL_RenderDriver GLES2_RenderDriver = { #endif /* SDL_VIDEO_RENDER_OGL_ES2 && !SDL_RENDER_DISABLED */ /* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/render/opengles2/SDL_shaders_gles2.c b/src/render/opengles2/SDL_shaders_gles2.c index 49b2a3606..a1f78fdd9 100644 --- a/src/render/opengles2/SDL_shaders_gles2.c +++ b/src/render/opengles2/SDL_shaders_gles2.c @@ -121,6 +121,8 @@ static const Uint8 GLES2_Fragment_TextureBGR[] = " \ } \ "; +#if SDL_HAVE_YUV + #define JPEG_SHADER_CONSTANTS \ "// YUV offset \n" \ "const vec3 offset = vec3(0, -0.501960814, -0.501960814);\n" \ @@ -299,6 +301,7 @@ static const Uint8 GLES2_Fragment_TextureNV21BT709[] = \ BT709_SHADER_CONSTANTS \ NV21_SHADER_BODY \ ; +#endif /* Custom Android video format texture */ static const Uint8 GLES2_Fragment_TextureExternalOES[] = " \ @@ -335,6 +338,7 @@ const Uint8 *GLES2_GetShader(GLES2_ShaderType type) return GLES2_Fragment_TextureRGB; case GLES2_SHADER_FRAGMENT_TEXTURE_BGR: return GLES2_Fragment_TextureBGR; +#if SDL_HAVE_YUV case GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG: return GLES2_Fragment_TextureYUVJPEG; case GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601: @@ -357,6 +361,7 @@ const Uint8 *GLES2_GetShader(GLES2_ShaderType type) return GLES2_Fragment_TextureNV21BT601; case GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709: return GLES2_Fragment_TextureNV21BT709; +#endif case GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES: return GLES2_Fragment_TextureExternalOES; default: diff --git a/src/render/opengles2/SDL_shaders_gles2.h b/src/render/opengles2/SDL_shaders_gles2.h index 32c4309ca..09780239d 100644 --- a/src/render/opengles2/SDL_shaders_gles2.h +++ b/src/render/opengles2/SDL_shaders_gles2.h @@ -34,6 +34,7 @@ typedef enum GLES2_SHADER_FRAGMENT_TEXTURE_ARGB, GLES2_SHADER_FRAGMENT_TEXTURE_BGR, GLES2_SHADER_FRAGMENT_TEXTURE_RGB, +#if SDL_HAVE_YUV GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG, GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601, GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709, @@ -45,6 +46,7 @@ typedef enum GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG, GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601, GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709, +#endif GLES2_SHADER_FRAGMENT_TEXTURE_EXTERNAL_OES, GLES2_SHADER_COUNT } GLES2_ShaderType; diff --git a/src/render/psp/SDL_render_psp.c b/src/render/psp/SDL_render_psp.c index 9431b929b..cdc0b9156 100644 --- a/src/render/psp/SDL_render_psp.c +++ b/src/render/psp/SDL_render_psp.c @@ -442,8 +442,8 @@ TextureSpillLRU(PSP_RenderData* data, size_t wanted) { } LRUTargetRemove(data, lru); } else { - SDL_SetError("Could not spill more VRAM to system memory. VRAM : %dKB,(%dKB), wanted %dKB", vmemavail()/1024, vlargestblock()/1024, wanted/1024); - return -1; //Asked to spill but there nothing to spill + // Asked to spill but there nothing to spill + return SDL_SetError("Could not spill more VRAM to system memory. VRAM : %dKB,(%dKB), wanted %dKB", vmemavail()/1024, vlargestblock()/1024, wanted/1024); } return 0; } @@ -556,7 +556,8 @@ static int TextureShouldSwizzle(PSP_TextureData* psp_texture, SDL_Texture *texture) { return !((texture->access == SDL_TEXTUREACCESS_TARGET) && InVram(psp_texture->data)) - && (texture->w >= 16 || texture->h >= 16); + && texture->access != SDL_TEXTUREACCESS_STREAMING + && (texture->w >= 16 || texture->h >= 16); } static void @@ -774,14 +775,13 @@ PSP_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FR cmd->data.draw.count = count; for (i = 0; i < count; i++, rects++) { - const SDL_FRect *rect = &rects[i]; - verts->x = rect->x; - verts->y = rect->y; + verts->x = rects->x; + verts->y = rects->y; verts->z = 0.0f; verts++; - verts->x = rect->x + rect->w; - verts->y = rect->y + rect->h; + verts->x = rects->x + rects->w + 0.5f; + verts->y = rects->y + rects->h + 0.5f; verts->z = 0.0f; verts++; } @@ -881,7 +881,7 @@ PSP_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * tex static int PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect, - const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) { VertTV *verts = (VertTV *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertTV), 4, &cmd->data.draw.first); const float centerx = center->x; @@ -891,27 +891,29 @@ PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * t const float width = dstrect->w - centerx; const float height = dstrect->h - centery; float s, c; - float cw, sw, ch, sh; + float cw1, sw1, ch1, sh1, cw2, sw2, ch2, sh2; float u0 = srcrect->x; float v0 = srcrect->y; float u1 = srcrect->x + srcrect->w; float v1 = srcrect->y + srcrect->h; - - if (!verts) { return -1; } cmd->data.draw.count = 1; - MathSincos(degToRad(angle), &s, &c); + MathSincos(degToRad(360-angle), &s, &c); - cw = c * width; - sw = s * width; - ch = c * height; - sh = s * height; + cw1 = c * -centerx; + sw1 = s * -centerx; + ch1 = c * -centery; + sh1 = s * -centery; + cw2 = c * width; + sw2 = s * width; + ch2 = c * height; + sh2 = s * height; if (flip & SDL_FLIP_VERTICAL) { Swap(&v0, &v1); @@ -923,31 +925,44 @@ PSP_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * t verts->u = u0; verts->v = v0; - verts->x = x - cw + sh; - verts->y = y - sw - ch; + verts->x = x + cw1 + sh1; + verts->y = y - sw1 + ch1; verts->z = 0; verts++; verts->u = u0; verts->v = v1; - verts->x = x - cw - sh; - verts->y = y - sw + ch; + verts->x = x + cw1 + sh2; + verts->y = y - sw1 + ch2; verts->z = 0; verts++; verts->u = u1; verts->v = v1; - verts->x = x + cw - sh; - verts->y = y + sw + ch; + verts->x = x + cw2 + sh2; + verts->y = y - sw2 + ch2; verts->z = 0; verts++; verts->u = u1; verts->v = v0; - verts->x = x + cw + sh; - verts->y = y + sw - ch; + verts->x = x + cw2 + sh1; + verts->y = y - sw2 + ch1; verts->z = 0; - verts++; + + if (scale_x != 1.0f || scale_y != 1.0f) { + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + } return 0; } diff --git a/src/render/software/SDL_blendfillrect.c b/src/render/software/SDL_blendfillrect.c index 5f4912655..569c15058 100644 --- a/src/render/software/SDL_blendfillrect.c +++ b/src/render/software/SDL_blendfillrect.c @@ -220,7 +220,7 @@ SDL_BlendFillRect(SDL_Surface * dst, const SDL_Rect * rect, SDL_Rect clipped; if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_BlendFillRect(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ @@ -291,7 +291,7 @@ SDL_BlendFillRects(SDL_Surface * dst, const SDL_Rect * rects, int count, int status = 0; if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_BlendFillRects(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ diff --git a/src/render/software/SDL_blendline.c b/src/render/software/SDL_blendline.c index c38c4425a..4921bf101 100644 --- a/src/render/software/SDL_blendline.c +++ b/src/render/software/SDL_blendline.c @@ -809,7 +809,7 @@ SDL_BlendLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, BlendLineFunc func; if (!dst) { - return SDL_SetError("SDL_BlendLine(): Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_BlendLine(): dst"); } func = SDL_CalculateBlendLineFunc(dst->format); diff --git a/src/render/software/SDL_blendpoint.c b/src/render/software/SDL_blendpoint.c index d5b662cce..613169b7b 100644 --- a/src/render/software/SDL_blendpoint.c +++ b/src/render/software/SDL_blendpoint.c @@ -218,7 +218,7 @@ SDL_BlendPoint(SDL_Surface * dst, int x, int y, SDL_BlendMode blendMode, Uint8 r Uint8 g, Uint8 b, Uint8 a) { if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_BlendPoint(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ @@ -287,7 +287,7 @@ SDL_BlendPoints(SDL_Surface * dst, const SDL_Point * points, int count, int status = 0; if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_BlendPoints(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ diff --git a/src/render/software/SDL_drawline.c b/src/render/software/SDL_drawline.c index 8dbd3d219..e309f1619 100644 --- a/src/render/software/SDL_drawline.c +++ b/src/render/software/SDL_drawline.c @@ -144,7 +144,7 @@ SDL_DrawLine(SDL_Surface * dst, int x1, int y1, int x2, int y2, Uint32 color) DrawLineFunc func; if (!dst) { - return SDL_SetError("SDL_DrawLine(): Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_DrawLine(): dst"); } func = SDL_CalculateDrawLineFunc(dst->format); @@ -173,7 +173,7 @@ SDL_DrawLines(SDL_Surface * dst, const SDL_Point * points, int count, DrawLineFunc func; if (!dst) { - return SDL_SetError("SDL_DrawLines(): Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_DrawLines(): dst"); } func = SDL_CalculateDrawLineFunc(dst->format); diff --git a/src/render/software/SDL_drawpoint.c b/src/render/software/SDL_drawpoint.c index 999f015cd..b99838ac6 100644 --- a/src/render/software/SDL_drawpoint.c +++ b/src/render/software/SDL_drawpoint.c @@ -30,7 +30,7 @@ int SDL_DrawPoint(SDL_Surface * dst, int x, int y, Uint32 color) { if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_DrawPoint(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ @@ -71,7 +71,7 @@ SDL_DrawPoints(SDL_Surface * dst, const SDL_Point * points, int count, int x, y; if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_DrawPoints(): dst"); } /* This function doesn't work on surfaces < 8 bpp */ diff --git a/src/render/software/SDL_render_sw.c b/src/render/software/SDL_render_sw.c index 7a2aac295..a1af12cd6 100644 --- a/src/render/software/SDL_render_sw.c +++ b/src/render/software/SDL_render_sw.c @@ -99,8 +99,7 @@ SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) return 0; } - SDL_SetError("Software renderer doesn't have an output surface"); - return -1; + return SDL_SetError("Software renderer doesn't have an output surface"); } static int @@ -274,12 +273,14 @@ typedef struct CopyExData double angle; SDL_FPoint center; SDL_RendererFlip flip; + float scale_x; + float scale_y; } CopyExData; static int SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_FRect * dstrect, - const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip) + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) { CopyExData *verts = (CopyExData *) SDL_AllocateRenderVertices(renderer, sizeof (CopyExData), 0, &cmd->data.draw.first); @@ -298,21 +299,41 @@ SW_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * te verts->angle = angle; SDL_memcpy(&verts->center, center, sizeof (SDL_FPoint)); verts->flip = flip; + verts->scale_x = scale_x; + verts->scale_y = scale_y; return 0; } +static int +Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect, + float scale_x, float scale_y, SDL_ScaleMode scaleMode) +{ + int retval; + /* Renderer scaling, if needed */ + if (scale_x != 1.0f || scale_y != 1.0f) { + SDL_Rect r; + r.x = (int)((float) dstrect->x * scale_x); + r.y = (int)((float) dstrect->y * scale_y); + r.w = (int)((float) dstrect->w * scale_x); + r.h = (int)((float) dstrect->h * scale_y); + retval = SDL_PrivateUpperBlitScaled(src, srcrect, surface, &r, scaleMode); + } else { + retval = SDL_BlitSurface(src, srcrect, surface, dstrect); + } + return retval; +} + static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * final_rect, - const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) + const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip, float scale_x, float scale_y) { SDL_Surface *src = (SDL_Surface *) texture->driverdata; SDL_Rect tmp_rect; SDL_Surface *src_clone, *src_rotated, *src_scaled; SDL_Surface *mask = NULL, *mask_rotated = NULL; - int retval = 0, dstwidth, dstheight, abscenterx, abscentery; - double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; + int retval = 0; SDL_BlendMode blendmode; Uint8 alphaMod, rMod, gMod, bMod; int applyModulation = SDL_FALSE; @@ -414,53 +435,32 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex SDL_SetSurfaceBlendMode(src_clone, blendmode); if (!retval) { - SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle); - src_rotated = SDLgfx_rotateSurface(src_clone, angle, dstwidth/2, dstheight/2, (texture->scaleMode == SDL_ScaleModeNearest) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle); + SDL_Rect rect_dest; + double cangle, sangle; + + SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, center, + &rect_dest, &cangle, &sangle); + src_rotated = SDLgfx_rotateSurface(src_clone, angle, + (texture->scaleMode == SDL_ScaleModeNearest) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, + &rect_dest, cangle, sangle, center); if (src_rotated == NULL) { retval = -1; } if (!retval && mask != NULL) { /* The mask needed for the NONE blend mode gets rotated with the same parameters. */ - mask_rotated = SDLgfx_rotateSurface(mask, angle, dstwidth/2, dstheight/2, SDL_FALSE, 0, 0, dstwidth, dstheight, cangle, sangle); + mask_rotated = SDLgfx_rotateSurface(mask, angle, + SDL_FALSE, 0, 0, + &rect_dest, cangle, sangle, center); if (mask_rotated == NULL) { retval = -1; } } if (!retval) { - /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */ - abscenterx = final_rect->x + (int)center->x; - abscentery = final_rect->y + (int)center->y; - /* Compensate the angle inversion to match the behaviour of the other backends */ - sangle = -sangle; - - /* Top Left */ - px = final_rect->x - abscenterx; - py = final_rect->y - abscentery; - p1x = px * cangle - py * sangle + abscenterx; - p1y = px * sangle + py * cangle + abscentery; - - /* Top Right */ - px = final_rect->x + final_rect->w - abscenterx; - py = final_rect->y - abscentery; - p2x = px * cangle - py * sangle + abscenterx; - p2y = px * sangle + py * cangle + abscentery; - - /* Bottom Left */ - px = final_rect->x - abscenterx; - py = final_rect->y + final_rect->h - abscentery; - p3x = px * cangle - py * sangle + abscenterx; - p3y = px * sangle + py * cangle + abscentery; - - /* Bottom Right */ - px = final_rect->x + final_rect->w - abscenterx; - py = final_rect->y + final_rect->h - abscentery; - p4x = px * cangle - py * sangle + abscenterx; - p4y = px * sangle + py * cangle + abscentery; - - tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x)); - tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y)); - tmp_rect.w = dstwidth; - tmp_rect.h = dstheight; + + tmp_rect.x = final_rect->x + rect_dest.x; + tmp_rect.y = final_rect->y + rect_dest.y; + tmp_rect.w = rect_dest.w; + tmp_rect.h = rect_dest.h; /* The NONE blend mode needs some special care with non-opaque surfaces. * Other blend modes or opaque surfaces can be blitted directly. @@ -471,7 +471,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex SDL_SetSurfaceAlphaMod(src_rotated, alphaMod); SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod); } - retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect); + /* Renderer scaling, if needed */ + retval = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode); } else { /* The NONE blend mode requires three steps to get the pixels onto the destination surface. * First, the area where the rotated pixels will be blitted to get set to zero. @@ -480,7 +481,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex */ SDL_Rect mask_rect = tmp_rect; SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE); - retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect); + /* Renderer scaling, if needed */ + retval = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); if (!retval) { /* The next step copies the alpha value. This is done with the BLEND blend mode and * by modulating the source colors with 0. Since the destination is all zeros, this @@ -488,7 +490,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex */ SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0); mask_rect = tmp_rect; - retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect); + /* Renderer scaling, if needed */ + retval = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, texture->scaleMode); if (!retval) { /* The last step gets the color values in place. The ADD blend mode simply adds them to * the destination (where the color values are all zero). However, because the ADD blend @@ -504,7 +507,8 @@ SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Surface *surface, SDL_Texture * tex retval = -1; } else { SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); - retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect); + /* Renderer scaling, if needed */ + retval = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, texture->scaleMode); SDL_FreeSurface(src_rotated_rgb); } } @@ -823,7 +827,42 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic * to avoid potentially frequent RLE encoding/decoding. */ SDL_SetSurfaceRLE(surface, 0); - SDL_PrivateUpperBlitScaled(src, srcrect, surface, dstrect, texture->scaleMode); + + /* Prevent to do scaling + clipping on viewport boundaries as it may lose proportion */ + if (dstrect->x < 0 || dstrect->y < 0 || dstrect->x + dstrect->w > surface->w || dstrect->y + dstrect->h > surface->h) { + SDL_Surface *tmp = SDL_CreateRGBSurfaceWithFormat(0, dstrect->w, dstrect->h, 0, src->format->format); + /* Scale to an intermediate surface, then blit */ + if (tmp) { + SDL_Rect r; + SDL_BlendMode blendmode; + Uint8 alphaMod, rMod, gMod, bMod; + + SDL_GetSurfaceBlendMode(src, &blendmode); + SDL_GetSurfaceAlphaMod(src, &alphaMod); + SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); + + r.x = 0; + r.y = 0; + r.w = dstrect->w; + r.h = dstrect->h; + + SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE); + SDL_SetSurfaceColorMod(src, 255, 255, 255); + SDL_SetSurfaceAlphaMod(src, 255); + + SDL_PrivateUpperBlitScaled(src, srcrect, tmp, &r, texture->scaleMode); + + SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod); + SDL_SetSurfaceAlphaMod(tmp, alphaMod); + SDL_SetSurfaceBlendMode(tmp, blendmode); + + SDL_BlitSurface(tmp, NULL, surface, dstrect); + SDL_FreeSurface(tmp); + /* No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy() */ + } + } else{ + SDL_PrivateUpperBlitScaled(src, srcrect, surface, dstrect, texture->scaleMode); + } } break; } @@ -840,7 +879,8 @@ SW_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic } SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect, - ©data->dstrect, copydata->angle, ©data->center, copydata->flip); + ©data->dstrect, copydata->angle, ©data->center, copydata->flip, + copydata->scale_x, copydata->scale_y); break; } @@ -977,7 +1017,7 @@ SW_CreateRendererForSurface(SDL_Surface * surface) SW_RenderData *data; if (!surface) { - SDL_SetError("Can't create renderer for NULL surface"); + SDL_InvalidParamError("surface"); return NULL; } diff --git a/src/render/software/SDL_rotate.c b/src/render/software/SDL_rotate.c index b5ac715e8..6a9efac9c 100644 --- a/src/render/software/SDL_rotate.c +++ b/src/render/software/SDL_rotate.c @@ -82,7 +82,7 @@ to a situation where the program can segfault. \brief Returns colorkey info for a surface */ static Uint32 -_colorkey(SDL_Surface *src) +get_colorkey(SDL_Surface *src) { Uint32 key = 0; if (SDL_HasColorKey(src)) { @@ -91,6 +91,18 @@ _colorkey(SDL_Surface *src) return key; } +/* rotate (sx, sy) by (angle, center) into (dx, dy) */ +static void +rotate(double sx, double sy, double sinangle, double cosangle, const SDL_FPoint *center, double *dx, double *dy) { + sx -= center->x; + sy -= center->y; + + *dx = cosangle * sx - sinangle * sy; + *dy = sinangle * sx + cosangle * sy; + + *dx += center->x; + *dy += center->y; +} /* ! \brief Internal target surface sizing function for rotations with trig result return. @@ -105,49 +117,61 @@ _colorkey(SDL_Surface *src) */ void -SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, - int *dstwidth, int *dstheight, - double *cangle, double *sangle) +SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center, + SDL_Rect *rect_dest, double *cangle, double *sangle) { - /* 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; + int minx, maxx, miny, maxy; + double radangle; + double x0, x1, x2, x3; + double y0, y1, y2, y3; + double sinangle; + double cosangle; + + radangle = angle * (M_PI / 180.0); + sinangle = SDL_sin(radangle); + cosangle = SDL_cos(radangle); + + /* + * Determine destination width and height by rotating a source box, at pixel center + */ + rotate(0.5, 0.5, sinangle, cosangle, center, &x0, &y0); + rotate(width - 0.5, 0.5, sinangle, cosangle, center, &x1, &y1); + rotate(0.5, height - 0.5, sinangle, cosangle, center, &x2, &y2); + rotate(width - 0.5, height - 0.5, sinangle, cosangle, center, &x3, &y3); + + minx = (int)SDL_floor( SDL_min( SDL_min(x0, x1), SDL_min(x2, x3) ) ); + maxx = (int)SDL_ceil( SDL_max( SDL_max(x0, x1), SDL_max(x2, x3) ) ); + + miny = (int)SDL_floor( SDL_min( SDL_min(y0, y1), SDL_min(y2, y3) ) ); + maxy = (int)SDL_ceil( SDL_max( SDL_max(y0, y1), SDL_max(y2, y3) ) ); + + rect_dest->w = maxx - minx; + rect_dest->h = maxy - miny; + rect_dest->x = minx; + rect_dest->y = miny; + + /* reverse the angle because our rotations are clockwise */ + *sangle = -sinangle; + *cangle = cosangle; + + { + /* 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) { + rect_dest->w = height; + rect_dest->h = width; + *cangle = 0; + *sangle = angle90 == 1 ? -1 : 1; /* reversed because our rotations are clockwise */ + } else { + rect_dest->w = width; + rect_dest->h = 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; } } @@ -220,48 +244,56 @@ Assumes dst surface was allocated with the correct dimensions. \param src Source surface. \param dst Destination surface. -\param cx Horizontal center coordinate. -\param cy Vertical center coordinate. \param isin Integer version of sine of angle. \param icos Integer version of cosine of angle. \param flipx Flag indicating horizontal mirroring should be applied. \param flipy Flag indicating vertical mirroring should be applied. \param smooth Flag indicating anti-aliasing should be used. +\param dst_rect destination coordinates +\param center true center. */ static void -_transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy, int smooth) +transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int isin, int icos, + int flipx, int flipy, int smooth, + const SDL_Rect *rect_dest, + const SDL_FPoint *center) { - int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh; + int sw, sh; + int cx, cy; tColorRGBA c00, c01, c10, c11, cswap; tColorRGBA *pc, *sp; int gap; + const int fp_half = (1<<15); /* * Variable setup */ - xd = ((src->w - dst->w) << 15); - yd = ((src->h - dst->h) << 15); - ax = (cx << 16) - (icos * cx); - ay = (cy << 16) - (isin * cx); sw = src->w - 1; sh = src->h - 1; pc = (tColorRGBA*) dst->pixels; gap = dst->pitch - dst->w * 4; + cx = (int)(center->x * 65536.0); + cy = (int)(center->y * 65536.0); /* * Switch between interpolating and non-interpolating code */ if (smooth) { + int y; for (y = 0; y < dst->h; y++) { - dy = cy - y; - sdx = (ax + (isin * dy)) + xd; - sdy = (ay - (icos * dy)) + yd; + int x; + double src_x = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); for (x = 0; x < dst->w; x++) { - dx = (sdx >> 16); - dy = (sdy >> 16); + int dx = (sdx >> 16); + int dy = (sdy >> 16); if (flipx) dx = sw - dx; if (flipy) dy = sh - dy; if ((dx > -1) && (dy > -1) && (dx < (src->w-1)) && (dy < (src->h-1))) { + int ex, ey; + int t1, t2; sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy) + dx; c00 = *sp; sp += 1; @@ -303,13 +335,16 @@ _transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int pc = (tColorRGBA *) ((Uint8 *) pc + gap); } } else { + int y; for (y = 0; y < dst->h; y++) { - dy = cy - y; - sdx = (ax + (isin * dy)) + xd; - sdy = (ay - (icos * dy)) + yd; + int x; + double src_x = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); for (x = 0; x < dst->w; x++) { - dx = (sdx >> 16); - dy = (sdy >> 16); + int dx = (sdx >> 16); + int dy = (sdy >> 16); if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { if(flipx) dx = sw - dx; if(flipy) dy = sh - dy; @@ -335,46 +370,54 @@ Assumes dst surface was allocated with the correct dimensions. \param src Source surface. \param dst Destination surface. -\param cx Horizontal center coordinate. -\param cy Vertical center coordinate. \param isin Integer version of sine of angle. \param icos Integer version of cosine of angle. \param flipx Flag indicating horizontal mirroring should be applied. \param flipy Flag indicating vertical mirroring should be applied. +\param dst_rect destination coordinates +\param center true center. */ static void -transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int flipx, int flipy) +transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int isin, int icos, int flipx, int flipy, + const SDL_Rect *rect_dest, + const SDL_FPoint *center) { - int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay; + int sw, sh; + int cx, cy; tColorY *pc; int gap; + const int fp_half = (1<<15); + int y; /* * Variable setup */ - xd = ((src->w - dst->w) << 15); - yd = ((src->h - dst->h) << 15); - ax = (cx << 16) - (icos * cx); - ay = (cy << 16) - (isin * cx); + sw = src->w - 1; + sh = src->h - 1; pc = (tColorY*) dst->pixels; gap = dst->pitch - dst->w; + cx = (int)(center->x * 65536.0); + cy = (int)(center->y * 65536.0); + /* * Clear surface to colorkey */ - SDL_memset(pc, (int)(_colorkey(src) & 0xff), dst->pitch * dst->h); + SDL_memset(pc, (int)(get_colorkey(src) & 0xff), dst->pitch * dst->h); /* * Iterate through destination surface */ for (y = 0; y < dst->h; y++) { - dy = cy - y; - sdx = (ax + (isin * dy)) + xd; - sdy = (ay - (icos * dy)) + yd; + int x; + double src_x = (rect_dest->x + 0 + 0.5 - center->x); + double src_y = (rect_dest->y + y + 0.5 - center->y); + int sdx = (int)((icos * src_x - isin * src_y) + cx - fp_half); + int sdy = (int)((isin * src_x + icos * src_y) + cy - fp_half); for (x = 0; x < dst->w; x++) { - dx = (sdx >> 16); - dy = (sdy >> 16); + int dx = (sdx >> 16); + int dy = (sdy >> 16); if ((unsigned)dx < (unsigned)src->w && (unsigned)dy < (unsigned)src->h) { - if (flipx) dx = (src->w-1)-dx; - if (flipy) dy = (src->h-1)-dy; + if (flipx) dx = sw - dx; + if (flipy) dy = sh- dy; *pc = *((tColorY *)src->pixels + src->pitch * dy + dx); } sdx += icos; @@ -390,7 +433,7 @@ transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin \brief Rotates and zooms a surface with different horizontal and vertival scaling factors and optional anti-aliasing. Rotates a 32-bit or 8-bit 'src' surface to newly created 'dst' surface. -'angle' is the rotation in degrees, 'centerx' and 'centery' the rotation center. If 'smooth' is set +'angle' is the rotation in degrees, 'center' the rotation center. If 'smooth' is set then the destination 32-bit surface is anti-aliased. 8-bit surfaces must have a colorkey. 32-bit surfaces must have a 8888 layout with red, green, blue and alpha masks (any ordering goes). The blend mode of the 'src' surface has some effects on generation of the 'dst' surface: The NONE @@ -400,21 +443,21 @@ When using the NONE and MOD modes, color and alpha modulation must be applied be \param src The surface to rotozoom. \param angle The angle to rotate in degrees. -\param centerx The horizontal coordinate of the center of rotation \param zoomy The vertical coordinate of the center of rotation \param smooth Antialiasing flag; set to SMOOTHING_ON to enable. \param flipx Set to 1 to flip the image horizontally \param flipy Set to 1 to flip the image vertically -\param dstwidth The destination surface width -\param dstheight The destination surface height +\param rect_dest The destination rect bounding box \param cangle The angle cosine \param sangle The angle sine +\param center The true coordinate of the center of rotation \return The new rotated surface. */ SDL_Surface * -SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle) +SDLgfx_rotateSurface(SDL_Surface * src, double angle, int smooth, int flipx, int flipy, + const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center) { SDL_Surface *rz_dst; int is8bit, angle90; @@ -433,7 +476,6 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, colorKeyAvailable = SDL_TRUE; } } - /* This function requires a 32-bit surface or 8-bit surface with a colorkey */ is8bit = src->format->BitsPerPixel == 8 && colorKeyAvailable; if (!(is8bit || (src->format->BitsPerPixel == 32 && src->format->Amask))) @@ -447,16 +489,18 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, rz_dst = NULL; if (is8bit) { /* Target surface is 8 bit */ - rz_dst = SDL_CreateRGBSurface(0, dstwidth, dstheight + GUARD_ROWS, 8, 0, 0, 0, 0); + rz_dst = SDL_CreateRGBSurfaceWithFormat(0, rect_dest->w, rect_dest->h + GUARD_ROWS, 8, src->format->format); if (rz_dst != NULL) { - for (i = 0; i < src->format->palette->ncolors; i++) { - rz_dst->format->palette->colors[i] = src->format->palette->colors[i]; + if (src->format->palette) { + for (i = 0; i < src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = src->format->palette->ncolors; } - rz_dst->format->palette->ncolors = src->format->palette->ncolors; } } else { /* Target surface is 32 bit with source RGBA ordering */ - rz_dst = SDL_CreateRGBSurface(0, dstwidth, dstheight + GUARD_ROWS, 32, + rz_dst = SDL_CreateRGBSurface(0, rect_dest->w, rect_dest->h + GUARD_ROWS, 32, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask); } @@ -466,7 +510,7 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, return NULL; /* Adjust for guard rows */ - rz_dst->h = dstheight; + rz_dst->h = rect_dest->h; SDL_GetSurfaceBlendMode(src, &blendmode); @@ -497,7 +541,7 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, } /* 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 + * the off-by-one problem in transformSurfaceRGBA that expresses itself when the rotation is near * multiples of 90 degrees. */ angle90 = (int)(angle/90); @@ -513,16 +557,16 @@ SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, if(angle90 >= 0) { transformSurfaceY90(src, rz_dst, angle90, flipx, flipy); } else { - transformSurfaceY(src, rz_dst, centerx, centery, (int)sangleinv, (int)cangleinv, - flipx, flipy); + transformSurfaceY(src, rz_dst, (int)sangleinv, (int)cangleinv, + flipx, flipy, rect_dest, center); } } else { /* Call the 32-bit transformation routine to do the rotation */ if (angle90 >= 0) { transformSurfaceRGBA90(src, rz_dst, angle90, flipx, flipy); } else { - _transformSurfaceRGBA(src, rz_dst, centerx, centery, (int)sangleinv, (int)cangleinv, - flipx, flipy, smooth); + transformSurfaceRGBA(src, rz_dst, (int)sangleinv, (int)cangleinv, + flipx, flipy, smooth, rect_dest, center); } } diff --git a/src/render/software/SDL_rotate.h b/src/render/software/SDL_rotate.h index e1746c92c..171baa5dd 100644 --- a/src/render/software/SDL_rotate.h +++ b/src/render/software/SDL_rotate.h @@ -26,7 +26,9 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -extern SDL_Surface *SDLgfx_rotateSurface(SDL_Surface * src, double angle, int centerx, int centery, int smooth, int flipx, int flipy, int dstwidth, int dstheight, double cangle, double sangle); -extern void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, int *dstwidth, int *dstheight, double *cangle, double *sangle); +extern SDL_Surface *SDLgfx_rotateSurface(SDL_Surface * src, double angle, int smooth, int flipx, int flipy, + const SDL_Rect *rect_dest, double cangle, double sangle, const SDL_FPoint *center); +extern void SDLgfx_rotozoomSurfaceSizeTrig(int width, int height, double angle, const SDL_FPoint *center, + SDL_Rect *rect_dest, double *cangle, double *sangle); #endif /* SDL_rotate_h_ */ diff --git a/src/render/software/SDL_triangle.c b/src/render/software/SDL_triangle.c index ce003e169..694cb4d91 100644 --- a/src/render/software/SDL_triangle.c +++ b/src/render/software/SDL_triangle.c @@ -718,6 +718,21 @@ int SDL_SW_BlitTriangle( } +#define FORMAT_ALPHA 0 +#define FORMAT_NO_ALPHA -1 +#define FORMAT_2101010 1 +#define FORMAT_HAS_ALPHA(format) format == 0 +#define FORMAT_HAS_NO_ALPHA(format) format < 0 +static int SDL_INLINE detect_format(SDL_PixelFormat *pf) { + if (pf->format == SDL_PIXELFORMAT_ARGB2101010) { + return FORMAT_2101010; + } else if (pf->Amask) { + return FORMAT_ALPHA; + } else { + return FORMAT_NO_ALPHA; + } +} + static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, @@ -738,25 +753,32 @@ SDL_BlitTriangle_Slow(SDL_BlitInfo *info, SDL_PixelFormat *dst_fmt = info->dst_fmt; int srcbpp = src_fmt->BytesPerPixel; int dstbpp = dst_fmt->BytesPerPixel; + int srcfmt_val; + int dstfmt_val; Uint32 rgbmask = ~src_fmt->Amask; Uint32 ckey = info->colorkey & rgbmask; Uint8 *dst_ptr = info->dst; int dst_pitch = info->dst_pitch;; + srcfmt_val = detect_format(src_fmt); + dstfmt_val = detect_format(dst_fmt); + TRIANGLE_BEGIN_LOOP { Uint8 *src; Uint8 *dst = dptr; TRIANGLE_GET_TEXTCOORD src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp)); - if (src_fmt->Amask) { - DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, - srcB, srcA); - } else { - DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, - srcB); + if (FORMAT_HAS_ALPHA(srcfmt_val)) { + DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA); + } else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) { + DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB); srcA = 0xFF; + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + srcpixel = *((Uint32 *)(src)); + RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA); } if (flags & SDL_COPY_COLORKEY) { /* srcpixel isn't set for 24 bpp */ @@ -768,13 +790,15 @@ SDL_BlitTriangle_Slow(SDL_BlitInfo *info, continue; } } - if (dst_fmt->Amask) { - DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, - dstB, dstA); - } else { - DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, - dstB); + if (FORMAT_HAS_ALPHA(dstfmt_val)) { + DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA); + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { + DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB); dstA = 0xFF; + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + dstpixel = *((Uint32 *)(dst)); + RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA); } if (! is_uniform) { @@ -845,10 +869,15 @@ SDL_BlitTriangle_Slow(SDL_BlitInfo *info, dstA = 255; break; } - if (dst_fmt->Amask) { + if (FORMAT_HAS_ALPHA(dstfmt_val)) { ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA); - } else { + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB); + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + Uint32 pixel; + ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA); + *(Uint32 *)dst = pixel; } } TRIANGLE_END_LOOP diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c index 937701298..98b03e629 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm.c +++ b/src/render/vitagxm/SDL_render_vita_gxm.c @@ -61,6 +61,11 @@ static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * text const Uint8 *Uplane, int Upitch, const Uint8 *Vplane, int Vpitch); +static int VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); + static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch); @@ -105,12 +110,16 @@ SDL_RenderDriver VITA_GXM_RenderDriver = { .info = { .name = "VITA gxm", .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, - .num_texture_formats = 4, + .num_texture_formats = 8, .texture_formats = { [0] = SDL_PIXELFORMAT_ABGR8888, [1] = SDL_PIXELFORMAT_ARGB8888, [2] = SDL_PIXELFORMAT_RGB565, - [3] = SDL_PIXELFORMAT_BGR565 + [3] = SDL_PIXELFORMAT_BGR565, + [4] = SDL_PIXELFORMAT_YV12, + [5] = SDL_PIXELFORMAT_IYUV, + [6] = SDL_PIXELFORMAT_NV12, + [7] = SDL_PIXELFORMAT_NV21, }, .max_texture_width = 4096, .max_texture_height = 4096, @@ -133,6 +142,15 @@ PixelFormatToVITAFMT(Uint32 format) return SCE_GXM_TEXTURE_FORMAT_U5U6U5_RGB; case SDL_PIXELFORMAT_BGR565: return SCE_GXM_TEXTURE_FORMAT_U5U6U5_BGR; + case SDL_PIXELFORMAT_YV12: + return SCE_GXM_TEXTURE_FORMAT_YVU420P3_CSC0; + case SDL_PIXELFORMAT_IYUV: + return SCE_GXM_TEXTURE_FORMAT_YUV420P3_CSC0; + // should be the other way around. looks like SCE bug. + case SDL_PIXELFORMAT_NV12: + return SCE_GXM_TEXTURE_FORMAT_YVU420P2_CSC0; + case SDL_PIXELFORMAT_NV21: + return SCE_GXM_TEXTURE_FORMAT_YUV420P2_CSC0; default: return SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR; } @@ -217,7 +235,7 @@ VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags) data = (VITA_GXM_RenderData *) SDL_calloc(1, sizeof(VITA_GXM_RenderData)); if (!data) { - VITA_GXM_DestroyRenderer(renderer); + SDL_free(renderer); SDL_OutOfMemory(); return NULL; } @@ -226,7 +244,10 @@ VITA_GXM_CreateRenderer(SDL_Window *window, Uint32 flags) renderer->SupportsBlendMode = VITA_GXM_SupportsBlendMode; renderer->CreateTexture = VITA_GXM_CreateTexture; renderer->UpdateTexture = VITA_GXM_UpdateTexture; +#if SDL_HAVE_YUV renderer->UpdateTextureYUV = VITA_GXM_UpdateTextureYUV; + renderer->UpdateTextureNV = VITA_GXM_UpdateTextureNV; +#endif renderer->LockTexture = VITA_GXM_LockTexture; renderer->UnlockTexture = VITA_GXM_UnlockTexture; renderer->SetTextureScaleMode = VITA_GXM_SetTextureScaleMode; @@ -293,7 +314,17 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) return SDL_OutOfMemory(); } - vita_texture->tex = create_gxm_texture(data, texture->w, texture->h, PixelFormatToVITAFMT(texture->format), (texture->access == SDL_TEXTUREACCESS_TARGET)); + vita_texture->tex = create_gxm_texture( + data, + texture->w, + texture->h, + PixelFormatToVITAFMT(texture->format), + (texture->access == SDL_TEXTUREACCESS_TARGET), + &(vita_texture->w), + &(vita_texture->h), + &(vita_texture->pitch), + &(vita_texture->wscale) + ); if (!vita_texture->tex) { SDL_free(vita_texture); @@ -304,38 +335,129 @@ VITA_GXM_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) VITA_GXM_SetTextureScaleMode(renderer, texture, texture->scaleMode); - vita_texture->w = gxm_texture_get_width(vita_texture->tex); - vita_texture->h = gxm_texture_get_height(vita_texture->tex); - vita_texture->pitch = gxm_texture_get_stride(vita_texture->tex); +#if SDL_HAVE_YUV + vita_texture->yuv = ((texture->format == SDL_PIXELFORMAT_IYUV) || (texture->format == SDL_PIXELFORMAT_YV12)); + vita_texture->nv12 = ((texture->format == SDL_PIXELFORMAT_NV12) || (texture->format == SDL_PIXELFORMAT_NV21)); +#endif return 0; } +static void VITA_GXM_SetYUVProfile(SDL_Renderer * renderer, SDL_Texture *texture) +{ + VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata; + int ret = 0; + switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { + case SDL_YUV_CONVERSION_BT601: + ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD); + break; + case SDL_YUV_CONVERSION_BT709: + ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD); + break; + case SDL_YUV_CONVERSION_JPEG: + default: + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV profile: %d\n", SDL_GetYUVConversionModeForResolution(texture->w, texture->h)); + break; + } + + if (ret < 0) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Setting YUV profile failed: %x\n", ret); + } +} static int VITA_GXM_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) { - const Uint8 *src; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; Uint8 *dst; - int row, length,dpitch; - src = pixels; + int row, length, dpitch; + +#if SDL_HAVE_YUV + if (vita_texture->yuv || vita_texture->nv12) { + VITA_GXM_SetYUVProfile(renderer, texture); + } +#endif VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); length = rect->w * SDL_BYTESPERPIXEL(texture->format); if (length == pitch && length == dpitch) { - SDL_memcpy(dst, src, length*rect->h); + SDL_memcpy(dst, pixels, length*rect->h); } else { for (row = 0; row < rect->h; ++row) { - SDL_memcpy(dst, src, length); - src += pitch; + SDL_memcpy(dst, pixels, length); + pixels += pitch; dst += dpitch; } } +#if SDL_HAVE_YUV + if (vita_texture->yuv) { + void *Udst; + void *Vdst; + int uv_pitch = (dpitch+1) / 2; + int uv_src_pitch = (pitch+1) / 2; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + // skip Y plane + Uint8 *Dpixels = gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h); + + Udst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x; + Vdst = Dpixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w; + + // U plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(Udst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Udst, pixels, length); + pixels += uv_src_pitch; + Udst += uv_pitch; + } + } + + // V plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(Vdst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Vdst, pixels, length); + pixels += uv_src_pitch; + Vdst += uv_pitch; + } + } + + } else if (vita_texture->nv12) { + void *UVdst; + int uv_pitch = 2 * ((dpitch+1) / 2); + int uv_src_pitch = 2 * ((pitch+1) / 2); + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2 , (rect->h + 1) / 2}; + + // skip Y plane + void *Dpixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + UVdst = Dpixels + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w*2; + + // UV plane + if (length == uv_src_pitch && length == uv_pitch) { + SDL_memcpy(UVdst, pixels, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(UVdst, pixels, length); + pixels += uv_src_pitch; + UVdst += uv_pitch; + } + } + } +#endif + return 0; } +#if SDL_HAVE_YUV static int VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, @@ -343,9 +465,133 @@ VITA_GXM_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, const Uint8 *Uplane, int Upitch, const Uint8 *Vplane, int Vpitch) { + Uint8 *dst; + int row, length, dpitch; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + VITA_GXM_SetYUVProfile(renderer, texture); + + // copy Y plane + // obtain pixels via locking so that texture is flushed + VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); + + length = rect->w; + + if (length == Ypitch && length == dpitch) { + SDL_memcpy(dst, Yplane, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, Yplane, length); + Yplane += Ypitch; + dst += dpitch; + } + } + + // U/V planes + { + void *Udst; + void *Vdst; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; + int uv_pitch = (dpitch+1) / 2; + + // skip Y plane + void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + + if (texture->format == SDL_PIXELFORMAT_YV12) { // YVU + Vdst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + Udst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + } else { // YUV + Udst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + Vdst = pixels + (uv_pitch * ((vita_texture->h + 1) / 2)) + (UVrect.y * uv_pitch) + UVrect.x; + } + + length = UVrect.w; + + // U plane + if (length == Upitch && length == uv_pitch) { + SDL_memcpy(Udst, Uplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Udst, Uplane, length); + Uplane += Upitch; + Udst += uv_pitch; + } + } + + // V plane + if (length == Vpitch && length == uv_pitch) { + SDL_memcpy(Vdst, Vplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(Vdst, Vplane, length); + Vplane += Vpitch; + Vdst += uv_pitch; + } + } + + } + return 0; } +static int +VITA_GXM_UpdateTextureNV(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ + + Uint8 *dst; + int row, length, dpitch; + SDL_Rect UVrect = {rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2}; + + VITA_GXM_SetYUVProfile(renderer, texture); + + // copy Y plane + VITA_GXM_LockTexture(renderer, texture, rect, (void **)&dst, &dpitch); + + length = rect->w * SDL_BYTESPERPIXEL(texture->format); + + if (length == Ypitch && length == dpitch) { + SDL_memcpy(dst, Yplane, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, Yplane, length); + Yplane += Ypitch; + dst += dpitch; + } + } + + // UV plane + { + void *UVdst; + VITA_GXM_TextureData *vita_texture = (VITA_GXM_TextureData *) texture->driverdata; + int uv_pitch = 2 * ((dpitch+1) / 2); + + // skip Y plane + void *pixels = (void *) ((Uint8 *) gxm_texture_get_datap(vita_texture->tex) + (vita_texture->pitch * vita_texture->h)); + + UVdst = pixels + (UVrect.y * uv_pitch) + UVrect.x; + + length = UVrect.w * 2; + + // UV plane + if (length == UVpitch && length == uv_pitch) { + SDL_memcpy(UVdst, UVplane, length*UVrect.h); + } else { + for (row = 0; row < UVrect.h; ++row) { + SDL_memcpy(UVdst, UVplane, length); + UVplane += UVpitch; + UVdst += uv_pitch; + } + } + } + + return 0; +} + +#endif + static int VITA_GXM_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) @@ -517,6 +763,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu size_indices = indices ? size_indices : 0; if (texture) { + VITA_GXM_TextureData* vita_texture = (VITA_GXM_TextureData*) texture->driverdata; texture_vertex *vertices; vertices = (texture_vertex *)pool_malloc( @@ -549,7 +796,7 @@ VITA_GXM_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Textu vertices[i].x = xy_[0] * scale_x; vertices[i].y = xy_[1] * scale_y; - vertices[i].u = uv_[0]; + vertices[i].u = uv_[0] * vita_texture->wscale; vertices[i].v = uv_[1]; vertices[i].color = col_; } @@ -728,14 +975,6 @@ SetDrawState(VITA_GXM_RenderData *data, const SDL_RenderCommand *cmd) return 0; } -static int -SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd) -{ - VITA_GXM_RenderData *data = (VITA_GXM_RenderData *) renderer->driverdata; - - return SetDrawState(data, cmd); -} - static int VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) { @@ -822,11 +1061,7 @@ VITA_GXM_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void * nextcmd = nextcmd->next; } - if (thistexture) { - ret = SetCopyState(renderer, cmd); - } else { - ret = SetDrawState(data, cmd); - } + ret = SetDrawState(data, cmd); if (ret == 0) { int op = SCE_GXM_PRIMITIVE_TRIANGLES; @@ -1011,7 +1246,7 @@ VITA_GXM_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) sceGxmFinish(data->gxm_context); - free_gxm_texture(vita_texture->tex); + free_gxm_texture(data, vita_texture->tex); SDL_free(vita_texture); diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.c b/src/render/vitagxm/SDL_render_vita_gxm_memory.c index d3322730a..85d682ad7 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_memory.c +++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.c @@ -26,7 +26,7 @@ #include "SDL_render_vita_gxm_memory.h" void * -mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) +vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid) { void *mem; @@ -51,7 +51,7 @@ mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignm } void -mem_gpu_free(SceUID uid) +vita_mem_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -61,7 +61,71 @@ mem_gpu_free(SceUID uid) } void * -mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size) +{ + void *mem; + + if (data->texturePool == NULL) { + int poolsize; + int ret; + SceKernelFreeMemorySizeInfo info; + info.size = sizeof(SceKernelFreeMemorySizeInfo); + sceKernelGetFreeMemorySize(&info); + + poolsize = ALIGN(info.size_cdram, 256*1024); + if (poolsize > info.size_cdram) { + poolsize = ALIGN(info.size_cdram - 256*1024, 256*1024); + } + data->texturePoolUID = sceKernelAllocMemBlock("gpu_texture_pool", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, poolsize, NULL); + if (data->texturePoolUID < 0) { + return NULL; + } + + ret = sceKernelGetMemBlockBase(data->texturePoolUID, &mem); + if ( ret < 0) + { + return NULL; + } + data->texturePool = sceClibMspaceCreate(mem, poolsize); + + if (data->texturePool == NULL) { + return NULL; + } + ret = sceGxmMapMemory(mem, poolsize, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE); + if (ret < 0) + { + return NULL; + } + } + return sceClibMspaceMemalign(data->texturePool, SCE_GXM_TEXTURE_ALIGNMENT, size); +} + +void +vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr) +{ + if (data->texturePool != NULL) + { + sceClibMspaceFree(data->texturePool, ptr); + } +} + +void +vita_gpu_mem_destroy(VITA_GXM_RenderData *data) +{ + void *mem = NULL; + if (data->texturePool != NULL) + { + sceClibMspaceDestroy(data->texturePool); + data->texturePool = NULL; + if (sceKernelGetMemBlockBase(data->texturePoolUID, &mem) < 0) + return; + sceGxmUnmapMemory(mem); + sceKernelFreeMemBlock(data->texturePoolUID); + } +} + +void * +vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -77,7 +141,7 @@ mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) } void -mem_vertex_usse_free(SceUID uid) +vita_mem_vertex_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) @@ -87,7 +151,7 @@ mem_vertex_usse_free(SceUID uid) } void * -mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) +vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset) { void *mem = NULL; @@ -103,7 +167,7 @@ mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offse } void -mem_fragment_usse_free(SceUID uid) +vita_mem_fragment_usse_free(SceUID uid) { void *mem = NULL; if (sceKernelGetMemBlockBase(uid, &mem) < 0) diff --git a/src/render/vitagxm/SDL_render_vita_gxm_memory.h b/src/render/vitagxm/SDL_render_vita_gxm_memory.h index 51bc8a80a..93b9f3498 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_memory.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_memory.h @@ -25,15 +25,19 @@ #include #include #include +#include "SDL_render_vita_gxm_types.h" #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) -void *mem_gpu_alloc(SceKernelMemBlockType type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); -void mem_gpu_free(SceUID uid); -void *mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_vertex_usse_free(SceUID uid); -void *mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); -void mem_fragment_usse_free(SceUID uid); +void *vita_mem_alloc(unsigned int type, unsigned int size, unsigned int alignment, unsigned int attribs, SceUID *uid); +void vita_mem_free(SceUID uid); +void *vita_gpu_mem_alloc(VITA_GXM_RenderData *data, unsigned int size); +void vita_gpu_mem_free(VITA_GXM_RenderData *data, void* ptr); +void vita_gpu_mem_destroy(VITA_GXM_RenderData *data); +void *vita_mem_vertex_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_vertex_usse_free(SceUID uid); +void *vita_mem_fragment_usse_alloc(unsigned int size, SceUID *uid, unsigned int *usse_offset); +void vita_mem_fragment_usse_free(SceUID uid); #endif /* SDL_RENDER_VITA_GXM_MEMORY_H */ diff --git a/src/render/vitagxm/SDL_render_vita_gxm_tools.c b/src/render/vitagxm/SDL_render_vita_gxm_tools.c index e043b55ab..035e8a63c 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_tools.c +++ b/src/render/vitagxm/SDL_render_vita_gxm_tools.c @@ -117,6 +117,8 @@ tex_format_to_bytespp(SceGxmTextureFormat format) case SCE_GXM_TEXTURE_BASE_FORMAT_U8: case SCE_GXM_TEXTURE_BASE_FORMAT_S8: case SCE_GXM_TEXTURE_BASE_FORMAT_P8: + case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2: // YUV actually uses 12 bits per pixel. UV planes bits/mem are handled elsewhere + case SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3: return 1; case SCE_GXM_TEXTURE_BASE_FORMAT_U4U4U4U4: case SCE_GXM_TEXTURE_BASE_FORMAT_U8U3U3U2: @@ -414,28 +416,28 @@ gxm_init(SDL_Renderer *renderer) } // allocate ring buffer memory using default sizes - vdmRingBuffer = mem_gpu_alloc( + vdmRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VDM_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vdmRingBufferUid); - vertexRingBuffer = mem_gpu_alloc( + vertexRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_VERTEX_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->vertexRingBufferUid); - fragmentRingBuffer = mem_gpu_alloc( + fragmentRingBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, SCE_GXM_DEFAULT_FRAGMENT_RING_BUFFER_SIZE, 4, SCE_GXM_MEMORY_ATTRIB_READ, &data->fragmentRingBufferUid); - fragmentUsseRingBuffer = mem_fragment_usse_alloc( + fragmentUsseRingBuffer = vita_mem_fragment_usse_alloc( SCE_GXM_DEFAULT_FRAGMENT_USSE_RING_BUFFER_SIZE, &data->fragmentUsseRingBufferUid, &fragmentUsseRingBufferOffset); @@ -480,7 +482,7 @@ gxm_init(SDL_Renderer *renderer) for (i = 0; i < VITA_GXM_BUFFERS; i++) { // allocate memory for display - data->displayBufferData[i] = mem_gpu_alloc( + data->displayBufferData[i] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -525,7 +527,7 @@ gxm_init(SDL_Renderer *renderer) // allocate the depth buffer - data->depthBufferData = mem_gpu_alloc( + data->depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -533,7 +535,7 @@ gxm_init(SDL_Renderer *renderer) &data->depthBufferUid); // allocate the stencil buffer - data->stencilBufferData = mem_gpu_alloc( + data->stencilBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4 * sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -565,19 +567,19 @@ gxm_init(SDL_Renderer *renderer) // allocate memory for buffers and USSE code - patcherBuffer = mem_gpu_alloc( + patcherBuffer = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, patcherBufferSize, 4, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &data->patcherBufferUid); - patcherVertexUsse = mem_vertex_usse_alloc( + patcherVertexUsse = vita_mem_vertex_usse_alloc( patcherVertexUsseSize, &data->patcherVertexUsseUid, &patcherVertexUsseOffset); - patcherFragmentUsse = mem_fragment_usse_alloc( + patcherFragmentUsse = vita_mem_fragment_usse_alloc( patcherFragmentUsseSize, &data->patcherFragmentUsseUid, &patcherFragmentUsseOffset); @@ -728,7 +730,7 @@ gxm_init(SDL_Renderer *renderer) } // create the clear triangle vertex/index data - data->clearVertices = (clear_vertex *)mem_gpu_alloc( + data->clearVertices = (clear_vertex *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 3*sizeof(clear_vertex), 4, @@ -740,7 +742,7 @@ gxm_init(SDL_Renderer *renderer) // Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible // 16-bit indices in linear ascending order, so we can use this for // all drawing operations where we don't want to use indexing. - data->linearIndices = (uint16_t *)mem_gpu_alloc( + data->linearIndices = (uint16_t *)vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, UINT16_MAX*sizeof(uint16_t), sizeof(uint16_t), @@ -871,7 +873,7 @@ gxm_init(SDL_Renderer *renderer) data->textureWvpParam = (SceGxmProgramParameter *)sceGxmProgramFindParameterByName(textureVertexProgramGxp, "wvp"); // Allocate memory for the memory pool - data->pool_addr[0] = mem_gpu_alloc( + data->pool_addr[0] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -879,7 +881,7 @@ gxm_init(SDL_Renderer *renderer) &data->poolUid[0] ); - data->pool_addr[1] = mem_gpu_alloc( + data->pool_addr[1] = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW, VITA_GXM_POOL_SIZE, sizeof(void *), @@ -918,28 +920,28 @@ void gxm_finish(SDL_Renderer *renderer) free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mod); free_fragment_programs(data, &data->blendFragmentPrograms.blend_mode_mul); - mem_gpu_free(data->linearIndicesUid); - mem_gpu_free(data->clearVerticesUid); + vita_mem_free(data->linearIndicesUid); + vita_mem_free(data->clearVerticesUid); // wait until display queue is finished before deallocating display buffers sceGxmDisplayQueueFinish(); // clean up display queue - mem_gpu_free(data->depthBufferUid); + vita_mem_free(data->depthBufferUid); for (size_t i = 0; i < VITA_GXM_BUFFERS; i++) { // clear the buffer then deallocate SDL_memset(data->displayBufferData[i], 0, VITA_GXM_SCREEN_HEIGHT * VITA_GXM_SCREEN_STRIDE * 4); - mem_gpu_free(data->displayBufferUid[i]); + vita_mem_free(data->displayBufferUid[i]); // destroy the sync object sceGxmSyncObjectDestroy(data->displayBufferSync[i]); } // Free the depth and stencil buffer - mem_gpu_free(data->depthBufferUid); - mem_gpu_free(data->stencilBufferUid); + vita_mem_free(data->depthBufferUid); + vita_mem_free(data->stencilBufferUid); // unregister programs and destroy shader patcher sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->clearFragmentProgramId); @@ -950,23 +952,24 @@ void gxm_finish(SDL_Renderer *renderer) sceGxmShaderPatcherUnregisterProgram(data->shaderPatcher, data->textureVertexProgramId); sceGxmShaderPatcherDestroy(data->shaderPatcher); - mem_fragment_usse_free(data->patcherFragmentUsseUid); - mem_vertex_usse_free(data->patcherVertexUsseUid); - mem_gpu_free(data->patcherBufferUid); + vita_mem_fragment_usse_free(data->patcherFragmentUsseUid); + vita_mem_vertex_usse_free(data->patcherVertexUsseUid); + vita_mem_free(data->patcherBufferUid); // destroy the render target sceGxmDestroyRenderTarget(data->renderTarget); // destroy the gxm context sceGxmDestroyContext(data->gxm_context); - mem_fragment_usse_free(data->fragmentUsseRingBufferUid); - mem_gpu_free(data->fragmentRingBufferUid); - mem_gpu_free(data->vertexRingBufferUid); - mem_gpu_free(data->vdmRingBufferUid); + vita_mem_fragment_usse_free(data->fragmentUsseRingBufferUid); + vita_mem_free(data->fragmentRingBufferUid); + vita_mem_free(data->vertexRingBufferUid); + vita_mem_free(data->vdmRingBufferUid); SDL_free(data->contextParams.hostMem); - mem_gpu_free(data->poolUid[0]); - mem_gpu_free(data->poolUid[1]); + vita_mem_free(data->poolUid[0]); + vita_mem_free(data->poolUid[1]); + vita_gpu_mem_destroy(data); // terminate libgxm sceGxmTerminate(); @@ -975,16 +978,20 @@ void gxm_finish(SDL_Renderer *renderer) // textures void -free_gxm_texture(gxm_texture *texture) +free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture) { if (texture) { if (texture->gxm_rendertarget) { sceGxmDestroyRenderTarget(texture->gxm_rendertarget); } if (texture->depth_UID) { - mem_gpu_free(texture->depth_UID); + vita_mem_free(texture->depth_UID); + } + if (texture->cdram) { + vita_gpu_mem_free(data, sceGxmTextureGetData(&texture->gxm_tex)); + } else { + vita_mem_free(texture->data_UID); } - mem_gpu_free(texture->data_UID); SDL_free(texture); } } @@ -995,25 +1002,6 @@ gxm_texture_get_format(const gxm_texture *texture) return sceGxmTextureGetFormat(&texture->gxm_tex); } -unsigned int -gxm_texture_get_width(const gxm_texture *texture) -{ - return sceGxmTextureGetWidth(&texture->gxm_tex); -} - -unsigned int -gxm_texture_get_height(const gxm_texture *texture) -{ - return sceGxmTextureGetHeight(&texture->gxm_tex); -} - -unsigned int -gxm_texture_get_stride(const gxm_texture *texture) -{ - return ((gxm_texture_get_width(texture) + 7) & ~7) - * tex_format_to_bytespp(gxm_texture_get_format(texture)); -} - void * gxm_texture_get_datap(const gxm_texture *texture) { @@ -1021,34 +1009,53 @@ gxm_texture_get_datap(const gxm_texture *texture) } gxm_texture * -create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget) +create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale) { gxm_texture *texture = SDL_calloc(1, sizeof(gxm_texture)); - const int tex_size = ((w + 7) & ~ 7) * h * tex_format_to_bytespp(format); + int aligned_w = ALIGN(w, 8); + int texture_w = w; + int tex_size = aligned_w * h * tex_format_to_bytespp(format); void *texture_data; + int ret; + + *return_wscale = 1.0f; + + // SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3/P2 based formats require width aligned to 16 + if ( (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P3 || (format & 0x9f000000U) == SCE_GXM_TEXTURE_BASE_FORMAT_YUV420P2) { + aligned_w = ALIGN(w, 16); + texture_w = aligned_w; + tex_size = aligned_w * h * tex_format_to_bytespp(format); + *return_wscale = (float) (w) / texture_w; + // add storage for UV planes + tex_size += (((aligned_w + 1) / 2) * ((h + 1) / 2)) * 2; + } if (!texture) return NULL; + *return_w = w; + *return_h = h; + *return_pitch = aligned_w * tex_format_to_bytespp(format); + /* Allocate a GPU buffer for the texture */ - texture_data = mem_gpu_alloc( - SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, - tex_size, - SCE_GXM_TEXTURE_ALIGNMENT, - SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, - &texture->data_UID + texture_data = vita_gpu_mem_alloc( + data, + tex_size ); /* Try SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE in case we're out of VRAM */ if (!texture_data) { SDL_LogWarn(SDL_LOG_CATEGORY_RENDER, "CDRAM texture allocation failed\n"); - texture_data = mem_gpu_alloc( + texture_data = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, tex_size, SCE_GXM_TEXTURE_ALIGNMENT, SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &texture->data_UID ); + texture->cdram = 0; + } else { + texture->cdram = 1; } if (!texture_data) { @@ -1060,7 +1067,12 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc SDL_memset(texture_data, 0, tex_size); /* Create the gxm texture */ - sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, w, h, 0); + ret = sceGxmTextureInitLinear( &texture->gxm_tex, texture_data, format, texture_w, h, 0); + if (ret < 0) { + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "texture init failed: %x\n", ret); + return NULL; + } if (isRenderTarget) { void *depthBufferData; @@ -1083,13 +1095,13 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc ); if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "color surface init failed: %x\n", err); return NULL; } // allocate it - depthBufferData = mem_gpu_alloc( + depthBufferData = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, 4*sampleCount, SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, @@ -1106,8 +1118,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc NULL); if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "depth stencil init failed: %x\n", err); return NULL; } @@ -1131,8 +1143,8 @@ create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, Sc texture->gxm_rendertarget = tgt; if (err < 0) { - free_gxm_texture(texture); - SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %d\n", err); + free_gxm_texture(data, texture); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "create render target failed: %x\n", err); return NULL; } } @@ -1181,7 +1193,7 @@ void gxm_init_for_common_dialog(void) for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { buffer_for_common_dialog[i].displayData.wait_vblank = SDL_TRUE; - buffer_for_common_dialog[i].displayData.address = mem_gpu_alloc( + buffer_for_common_dialog[i].displayData.address = vita_mem_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, 4 * VITA_GXM_SCREEN_STRIDE * VITA_GXM_SCREEN_HEIGHT, SCE_GXM_COLOR_SURFACE_ALIGNMENT, @@ -1229,7 +1241,7 @@ void gxm_term_for_common_dialog(void) sceGxmDisplayQueueFinish(); for (int i = 0; i < VITA_GXM_BUFFERS; i += 1) { - mem_gpu_free(buffer_for_common_dialog[i].uid); + vita_mem_free(buffer_for_common_dialog[i].uid); sceGxmSyncObjectDestroy(buffer_for_common_dialog[i].sync); } } diff --git a/src/render/vitagxm/SDL_render_vita_gxm_tools.h b/src/render/vitagxm/SDL_render_vita_gxm_tools.h index 351bdc2e6..67659889d 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_tools.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_tools.h @@ -48,15 +48,12 @@ void unset_clip_rectangle(VITA_GXM_RenderData *data); int gxm_init(SDL_Renderer *renderer); void gxm_finish(SDL_Renderer *renderer); -gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget); -void free_gxm_texture(gxm_texture *texture); +gxm_texture *create_gxm_texture(VITA_GXM_RenderData *data, unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget, unsigned int *return_w, unsigned int *return_h, unsigned int *return_pitch, float *return_wscale); +void free_gxm_texture(VITA_GXM_RenderData *data, gxm_texture *texture); void gxm_texture_set_filters(gxm_texture *texture, SceGxmTextureFilter min_filter, SceGxmTextureFilter mag_filter); SceGxmTextureFormat gxm_texture_get_format(const gxm_texture *texture); -unsigned int gxm_texture_get_width(const gxm_texture *texture); -unsigned int gxm_texture_get_height(const gxm_texture *texture); -unsigned int gxm_texture_get_stride(const gxm_texture *texture); void *gxm_texture_get_datap(const gxm_texture *texture); void gxm_minimal_init_for_common_dialog(void); diff --git a/src/render/vitagxm/SDL_render_vita_gxm_types.h b/src/render/vitagxm/SDL_render_vita_gxm_types.h index 898a92d9c..c5cbf5898 100644 --- a/src/render/vitagxm/SDL_render_vita_gxm_types.h +++ b/src/render/vitagxm/SDL_render_vita_gxm_types.h @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -79,6 +80,7 @@ typedef struct gxm_texture { SceGxmColorSurface gxm_colorsurface; SceGxmDepthStencilSurface gxm_depthstencil; SceUID depth_UID; + SDL_bool cdram; } gxm_texture; typedef struct fragment_programs { @@ -186,14 +188,19 @@ typedef struct blend_fragment_programs blendFragmentPrograms; gxm_drawstate_cache drawstate; + SceClibMspace texturePool; + SceUID texturePoolUID; } VITA_GXM_RenderData; typedef struct { gxm_texture *tex; - unsigned int pitch; - unsigned int w; - unsigned int h; + unsigned int pitch; + unsigned int w; + unsigned int h; + float wscale; + SDL_bool yuv; + SDL_bool nv12; } VITA_GXM_TextureData; #endif /* SDL_RENDER_VITA_GXM_TYPES_H */ diff --git a/src/sensor/windows/SDL_windowssensor.c b/src/sensor/windows/SDL_windowssensor.c index bb8d39ed2..21b119d22 100644 --- a/src/sensor/windows/SDL_windowssensor.c +++ b/src/sensor/windows/SDL_windowssensor.c @@ -325,7 +325,10 @@ static int DisconnectSensor(ISensor *sensor) for (i = 0; i < SDL_num_sensors; ++i) { old_sensor = &SDL_sensors[i]; if (sensor == old_sensor->sensor) { - ISensor_SetEventSink(sensor, NULL); + /* This call hangs for some reason: + * https://github.com/libsdl-org/SDL/issues/5288 + */ + /*ISensor_SetEventSink(sensor, NULL);*/ ISensor_Release(sensor); SDL_free(old_sensor->name); --SDL_num_sensors; diff --git a/src/stdlib/SDL_getenv.c b/src/stdlib/SDL_getenv.c index d54cfe9ee..add833284 100644 --- a/src/stdlib/SDL_getenv.c +++ b/src/stdlib/SDL_getenv.c @@ -48,7 +48,7 @@ int SDL_setenv(const char *name, const char *value, int overwrite) { /* Input validation */ - if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { return (-1); } @@ -59,7 +59,7 @@ int SDL_setenv(const char *name, const char *value, int overwrite) { /* Input validation */ - if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { return (-1); } @@ -82,7 +82,7 @@ SDL_setenv(const char *name, const char *value, int overwrite) char *new_variable; /* Input validation */ - if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { return (-1); } @@ -115,7 +115,7 @@ SDL_setenv(const char *name, const char *value, int overwrite) char *new_variable; /* Input validation */ - if (!name || SDL_strlen(name) == 0 || SDL_strchr(name, '=') != NULL || !value) { + if (!name || *name == '\0' || SDL_strchr(name, '=') != NULL || !value) { return (-1); } @@ -181,7 +181,7 @@ SDL_getenv(const char *name) #endif /* Input validation */ - if (!name || !*name) { + if (!name || *name == '\0') { return NULL; } @@ -194,7 +194,7 @@ SDL_getenv(const char *name) size_t bufferlen; /* Input validation */ - if (!name || SDL_strlen(name)==0) { + if (!name || *name == '\0') { return NULL; } @@ -222,7 +222,7 @@ SDL_getenv(const char *name) char *value; /* Input validation */ - if (!name || SDL_strlen(name)==0) { + if (!name || *name == '\0') { return NULL; } diff --git a/src/stdlib/SDL_iconv.c b/src/stdlib/SDL_iconv.c index c88731b8d..3f5c82745 100644 --- a/src/stdlib/SDL_iconv.c +++ b/src/stdlib/SDL_iconv.c @@ -36,18 +36,6 @@ #define LIBICONV_PLUG 1 #endif #include - -/* Depending on which standard the iconv() was implemented with, - iconv() may or may not use const char ** for the inbuf param. - If we get this wrong, it's just a warning, so no big deal. -*/ -#if defined(_XGP6) || defined(__APPLE__) || defined(__RISCOS__) || defined(__FREEBSD__) || \ - defined(__EMSCRIPTEN__) || \ - (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) || \ - (defined(_NEWLIB_VERSION))) -#define ICONV_INBUF_NONCONST -#endif - #include SDL_COMPILE_TIME_ASSERT(iconv_t, sizeof (iconv_t) <= sizeof (SDL_iconv_t)); @@ -69,12 +57,9 @@ SDL_iconv(SDL_iconv_t cd, const char **inbuf, size_t * inbytesleft, char **outbuf, size_t * outbytesleft) { - size_t retCode; -#ifdef ICONV_INBUF_NONCONST - retCode = iconv((iconv_t) ((uintptr_t) cd), (char **) inbuf, inbytesleft, outbuf, outbytesleft); -#else - retCode = iconv((iconv_t) ((uintptr_t) cd), inbuf, inbytesleft, outbuf, outbytesleft); -#endif + /* iconv's second parameter may or may not be `const char const *` depending on the + C runtime's whims. Casting to void * seems to make everyone happy, though. */ + const size_t retCode = iconv((iconv_t) ((uintptr_t) cd), (void *) inbuf, inbytesleft, outbuf, outbytesleft); if (retCode == (size_t) - 1) { switch (errno) { case E2BIG: diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c index 12cc2da8f..133193072 100644 --- a/src/stdlib/SDL_string.c +++ b/src/stdlib/SDL_string.c @@ -32,6 +32,8 @@ /* Visual Studio 2013 tries to link with _vacopy in the C runtime. Newer versions do an inline assignment */ #undef va_copy #define va_copy(dst, src) dst = src +#elif defined(__GNUC__) && (__GNUC__ < 3) +#define va_copy(to, from) __va_copy(to, from) #endif #if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) || !defined(HAVE_STRTOUL) || !defined(HAVE_STRTOD) || !defined(HAVE_STRTOLL) || !defined(HAVE_STRTOULL) @@ -639,19 +641,16 @@ SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_ size_t bytes = SDL_min(src_bytes, dst_bytes - 1); size_t i = 0; unsigned char trailing_bytes = 0; - if (bytes) - { + + if (bytes) { unsigned char c = (unsigned char)src[bytes - 1]; - if (UTF8_IsLeadByte(c)) + if (UTF8_IsLeadByte(c)) { --bytes; - else if (UTF8_IsTrailingByte(c)) - { - for (i = bytes - 1; i != 0; --i) - { + } else if (UTF8_IsTrailingByte(c)) { + for (i = bytes - 1; i != 0; --i) { c = (unsigned char)src[i]; trailing_bytes = UTF8_TrailingBytes(c); - if (trailing_bytes) - { + if (trailing_bytes) { if (bytes - i != trailing_bytes + 1) bytes = i; @@ -662,6 +661,7 @@ SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_ SDL_memcpy(dst, src, bytes); } dst[bytes] = '\0'; + return bytes; } @@ -1070,13 +1070,16 @@ SDL_strcmp(const char *str1, const char *str2) #if defined(HAVE_STRCMP) return strcmp(str1, str2); #else - while (*str1 && *str2) { - if (*str1 != *str2) + int result; + + while(1) { + result = (int)((unsigned char) *str1 - (unsigned char) *str2); + if (result != 0 || (*str1 == '\0'/* && *str2 == '\0'*/)) break; ++str1; ++str2; } - return (int)((unsigned char) *str1 - (unsigned char) *str2); + return result; #endif /* HAVE_STRCMP */ } @@ -1086,17 +1089,20 @@ SDL_strncmp(const char *str1, const char *str2, size_t maxlen) #if defined(HAVE_STRNCMP) return strncmp(str1, str2, maxlen); #else - while (*str1 && *str2 && maxlen) { - if (*str1 != *str2) + int result; + + while (maxlen) { + result = (int) (unsigned char) *str1 - (unsigned char) *str2; + if (result != 0 || *str1 == '\0'/* && *str2 == '\0'*/) break; ++str1; ++str2; --maxlen; } if (!maxlen) { - return 0; + result = 0; } - return (int) ((unsigned char) *str1 - (unsigned char) *str2); + return result; #endif /* HAVE_STRNCMP */ } @@ -1108,19 +1114,18 @@ SDL_strcasecmp(const char *str1, const char *str2) #elif defined(HAVE__STRICMP) return _stricmp(str1, str2); #else - char a = 0; - char b = 0; - while (*str1 && *str2) { + int a, b, result; + + while (1) { a = SDL_toupper((unsigned char) *str1); b = SDL_toupper((unsigned char) *str2); - if (a != b) + result = a - b; + if (result != 0 || a == 0 /*&& b == 0*/) break; ++str1; ++str2; } - a = SDL_toupper(*str1); - b = SDL_toupper(*str2); - return (int) ((unsigned char) a - (unsigned char) b); + return result; #endif /* HAVE_STRCASECMP */ } @@ -1132,24 +1137,21 @@ SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen) #elif defined(HAVE__STRNICMP) return _strnicmp(str1, str2, maxlen); #else - char a = 0; - char b = 0; - while (*str1 && *str2 && maxlen) { + int a, b, result; + + while (maxlen) { a = SDL_tolower((unsigned char) *str1); b = SDL_tolower((unsigned char) *str2); - if (a != b) + result = a - b; + if (result != 0 || a == 0 /*&& b == 0*/) break; ++str1; ++str2; --maxlen; } - if (maxlen == 0) { - return 0; - } else { - a = SDL_tolower((unsigned char) *str1); - b = SDL_tolower((unsigned char) *str2); - return (int) ((unsigned char) a - (unsigned char) b); - } + if (maxlen == 0) + result = 0; + return result; #endif /* HAVE_STRNCASECMP */ } diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c index 48c6c72f0..93a0e7c74 100644 --- a/src/test/SDL_test_common.c +++ b/src/test/SDL_test_common.c @@ -1464,10 +1464,12 @@ default: return "???"; static void SDLTest_PrintEvent(SDL_Event * event) { +#ifndef VERBOSE_MOTION_EVENTS if ((event->type == SDL_MOUSEMOTION) || (event->type == SDL_FINGERMOTION)) { /* Mouse and finger motion are really spammy */ return; } +#endif switch (event->type) { case SDL_DISPLAYEVENT: diff --git a/src/thread/generic/SDL_syscond.c b/src/thread/generic/SDL_syscond.c index 328e37c90..59e8ce076 100644 --- a/src/thread/generic/SDL_syscond.c +++ b/src/thread/generic/SDL_syscond.c @@ -99,7 +99,7 @@ SDL_CondSignal_generic(SDL_cond * _cond) { SDL_cond_generic *cond = (SDL_cond_generic *)_cond; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -124,7 +124,7 @@ SDL_CondBroadcast_generic(SDL_cond * _cond) { SDL_cond_generic *cond = (SDL_cond_generic *)_cond; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -181,7 +181,7 @@ SDL_CondWaitTimeout_generic(SDL_cond * _cond, SDL_mutex * mutex, Uint32 ms) int retval; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* Obtain the protection mutex, and increment the number of waiters. diff --git a/src/thread/generic/SDL_sysmutex.c b/src/thread/generic/SDL_sysmutex.c index 9028c7268..42965aa8b 100644 --- a/src/thread/generic/SDL_sysmutex.c +++ b/src/thread/generic/SDL_sysmutex.c @@ -78,7 +78,7 @@ SDL_LockMutex(SDL_mutex * mutex) SDL_threadID this_thread; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } this_thread = SDL_ThreadID(); @@ -109,7 +109,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) SDL_threadID this_thread; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } this_thread = SDL_ThreadID(); @@ -139,7 +139,7 @@ SDL_mutexV(SDL_mutex * mutex) return 0; #else if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } /* If we don't own the mutex, we can't unlock it */ diff --git a/src/thread/generic/SDL_syssem.c b/src/thread/generic/SDL_syssem.c index 93ce2952d..c21ff196a 100644 --- a/src/thread/generic/SDL_syssem.c +++ b/src/thread/generic/SDL_syssem.c @@ -132,7 +132,7 @@ SDL_SemTryWait(SDL_sem * sem) int retval; if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } retval = SDL_MUTEX_TIMEDOUT; @@ -152,7 +152,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) int retval; if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } /* A timeout of 0 is an easy case */ @@ -200,7 +200,7 @@ int SDL_SemPost(SDL_sem * sem) { if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } SDL_LockMutex(sem->count_lock); diff --git a/src/thread/os2/SDL_sysmutex.c b/src/thread/os2/SDL_sysmutex.c index 28986f632..d3fc7a3bd 100644 --- a/src/thread/os2/SDL_sysmutex.c +++ b/src/thread/os2/SDL_sysmutex.c @@ -56,12 +56,12 @@ SDL_CreateMutex(void) void SDL_DestroyMutex(SDL_mutex * mutex) { - ULONG ulRC; HMTX hMtx = (HMTX)mutex; - - ulRC = DosCloseMutexSem(hMtx); - if (ulRC != NO_ERROR) { - debug_os2("DosCloseMutexSem(), rc = %u", ulRC); + if (hMtx != NULLHANDLE) { + const ULONG ulRC = DosCloseMutexSem(hMtx); + if (ulRC != NO_ERROR) { + debug_os2("DosCloseMutexSem(), rc = %u", ulRC); + } } } @@ -73,7 +73,7 @@ SDL_LockMutex(SDL_mutex * mutex) HMTX hMtx = (HMTX)mutex; if (hMtx == NULLHANDLE) - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); ulRC = DosRequestMutexSem(hMtx, SEM_INDEFINITE_WAIT); if (ulRC != NO_ERROR) { @@ -92,7 +92,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) HMTX hMtx = (HMTX)mutex; if (hMtx == NULLHANDLE) - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); ulRC = DosRequestMutexSem(hMtx, SEM_IMMEDIATE_RETURN); @@ -115,7 +115,7 @@ SDL_UnlockMutex(SDL_mutex * mutex) HMTX hMtx = (HMTX)mutex; if (hMtx == NULLHANDLE) - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); ulRC = DosReleaseMutexSem(hMtx); if (ulRC != NO_ERROR) diff --git a/src/thread/os2/SDL_syssem.c b/src/thread/os2/SDL_syssem.c index d2ede6991..79bf0673f 100644 --- a/src/thread/os2/SDL_syssem.c +++ b/src/thread/os2/SDL_syssem.c @@ -89,7 +89,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) ULONG cPost; if (sem == NULL) - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); if (timeout != SEM_INDEFINITE_WAIT) DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &ulStartTime, sizeof(ULONG)); @@ -147,7 +147,7 @@ SDL_SemValue(SDL_sem * sem) ULONG ulRC; if (sem == NULL) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -167,7 +167,7 @@ SDL_SemPost(SDL_sem * sem) ULONG ulRC; if (sem == NULL) - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); ulRC = DosRequestMutexSem(sem->hMtx, SEM_INDEFINITE_WAIT); if (ulRC != NO_ERROR) diff --git a/src/thread/psp/SDL_syscond.c b/src/thread/psp/SDL_syscond.c index 5c98610af..02307ed9c 100644 --- a/src/thread/psp/SDL_syscond.c +++ b/src/thread/psp/SDL_syscond.c @@ -84,7 +84,7 @@ int SDL_CondSignal(SDL_cond * cond) { if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -108,7 +108,7 @@ int SDL_CondBroadcast(SDL_cond * cond) { if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -164,7 +164,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) int retval; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* Obtain the protection mutex, and increment the number of waiters. diff --git a/src/thread/psp/SDL_sysmutex.c b/src/thread/psp/SDL_sysmutex.c index 0adc16c01..9e391629a 100644 --- a/src/thread/psp/SDL_sysmutex.c +++ b/src/thread/psp/SDL_sysmutex.c @@ -84,7 +84,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) #else SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelTryLockLwMutex(&mutex->lock, 1); @@ -114,7 +114,7 @@ SDL_mutexP(SDL_mutex * mutex) #else SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelLockLwMutex(&mutex->lock, 1, NULL); @@ -136,7 +136,7 @@ SDL_mutexV(SDL_mutex * mutex) SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelUnlockLwMutex(&mutex->lock, 1); diff --git a/src/thread/psp/SDL_syssem.c b/src/thread/psp/SDL_syssem.c index aaac5b68e..640619cd9 100644 --- a/src/thread/psp/SDL_syssem.c +++ b/src/thread/psp/SDL_syssem.c @@ -82,7 +82,7 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) int res; if (sem == NULL) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -128,7 +128,7 @@ Uint32 SDL_SemValue(SDL_sem *sem) SceKernelSemaInfo info; if (sem == NULL) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -144,7 +144,7 @@ int SDL_SemPost(SDL_sem *sem) int res; if (sem == NULL) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } res = sceKernelSignalSema(sem->semid, 1); diff --git a/src/thread/pthread/SDL_syscond.c b/src/thread/pthread/SDL_syscond.c index 5ebd415cc..c84ec7ada 100644 --- a/src/thread/pthread/SDL_syscond.c +++ b/src/thread/pthread/SDL_syscond.c @@ -68,7 +68,7 @@ SDL_CondSignal(SDL_cond * cond) int retval; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } retval = 0; @@ -85,7 +85,7 @@ SDL_CondBroadcast(SDL_cond * cond) int retval; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } retval = 0; @@ -105,7 +105,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) struct timespec abstime; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } #ifdef HAVE_CLOCK_GETTIME @@ -148,7 +148,7 @@ int SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex) { if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } else if (pthread_cond_wait(&cond->cond, &mutex->id) != 0) { return SDL_SetError("pthread_cond_wait() failed"); } diff --git a/src/thread/pthread/SDL_sysmutex.c b/src/thread/pthread/SDL_sysmutex.c index 027a6cb41..c26982aed 100644 --- a/src/thread/pthread/SDL_sysmutex.c +++ b/src/thread/pthread/SDL_sysmutex.c @@ -85,7 +85,7 @@ SDL_LockMutex(SDL_mutex * mutex) #endif if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } #if FAKE_RECURSIVE_MUTEX @@ -122,7 +122,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) #endif if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } retval = 0; @@ -162,7 +162,7 @@ int SDL_UnlockMutex(SDL_mutex * mutex) { if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } #if FAKE_RECURSIVE_MUTEX diff --git a/src/thread/pthread/SDL_syssem.c b/src/thread/pthread/SDL_syssem.c index 2c97ef4e5..9a0c88822 100644 --- a/src/thread/pthread/SDL_syssem.c +++ b/src/thread/pthread/SDL_syssem.c @@ -73,7 +73,7 @@ SDL_SemTryWait(SDL_sem * sem) int retval; if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } retval = SDL_MUTEX_TIMEDOUT; if (sem_trywait(&sem->sem) == 0) { @@ -88,7 +88,7 @@ SDL_SemWait(SDL_sem * sem) int retval; if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } do { @@ -115,7 +115,7 @@ SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) #endif if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } /* Try the easy cases first */ @@ -195,7 +195,7 @@ SDL_SemPost(SDL_sem * sem) int retval; if (!sem) { - return SDL_SetError("Passed a NULL semaphore"); + return SDL_InvalidParamError("sem"); } retval = sem_post(&sem->sem); diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index b5ab82dbf..3b3f40fa1 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -30,13 +30,13 @@ #endif #include +#include #ifdef __LINUX__ #include #include #include #include -#include #include "../../core/linux/SDL_dbus.h" #endif /* __LINUX__ */ @@ -137,22 +137,29 @@ SDL_SYS_SetupThread(const char *name) #if defined(__MACOSX__) || defined(__IPHONEOS__) ppthread_setname_np(name); #elif defined(__LINUX__) - ppthread_setname_np(pthread_self(), name); + if (ppthread_setname_np(pthread_self(), name) == ERANGE) { + char namebuf[16]; /* Limited to 16 char */ + SDL_strlcpy(namebuf, name, sizeof (namebuf)); + ppthread_setname_np(pthread_self(), namebuf); + } #endif } #elif HAVE_PTHREAD_SETNAME_NP #if defined(__NETBSD__) pthread_setname_np(pthread_self(), "%s", name); #else - pthread_setname_np(pthread_self(), name); + if (pthread_setname_np(pthread_self(), name) == ERANGE) { + char namebuf[16]; /* Limited to 16 char */ + SDL_strlcpy(namebuf, name, sizeof (namebuf)); + pthread_setname_np(pthread_self(), namebuf); + } #endif #elif HAVE_PTHREAD_SET_NAME_NP pthread_set_name_np(pthread_self(), name); #elif defined(__HAIKU__) /* The docs say the thread name can't be longer than B_OS_NAME_LENGTH. */ char namebuf[B_OS_NAME_LENGTH]; - SDL_snprintf(namebuf, sizeof (namebuf), "%s", name); - namebuf[sizeof (namebuf) - 1] = '\0'; + SDL_strlcpy(namebuf, name, sizeof (namebuf)); rename_thread(find_thread(NULL), namebuf); #endif } @@ -186,7 +193,7 @@ SDL_ThreadID(void) int SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) { -#if __NACL__ || __RISCOS__ +#if __NACL__ || __RISCOS__ || __OS2__ /* FIXME: Setting thread priority does not seem to be supported in NACL */ return 0; #else diff --git a/src/thread/stdcpp/SDL_syscond.cpp b/src/thread/stdcpp/SDL_syscond.cpp index 8aa26d73d..90c38adba 100644 --- a/src/thread/stdcpp/SDL_syscond.cpp +++ b/src/thread/stdcpp/SDL_syscond.cpp @@ -70,8 +70,7 @@ int SDL_CondSignal(SDL_cond * cond) { if (!cond) { - SDL_SetError("Passed a NULL condition variable"); - return -1; + return SDL_InvalidParamError("cond"); } cond->cpp_cond.notify_one(); @@ -84,8 +83,7 @@ int SDL_CondBroadcast(SDL_cond * cond) { if (!cond) { - SDL_SetError("Passed a NULL condition variable"); - return -1; + return SDL_InvalidParamError("cond"); } cond->cpp_cond.notify_all(); @@ -118,13 +116,11 @@ int SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) { if (!cond) { - SDL_SetError("Passed a NULL condition variable"); - return -1; + return SDL_InvalidParamError("cond"); } if (!mutex) { - SDL_SetError("Passed a NULL mutex variable"); - return -1; + return SDL_InvalidParamError("mutex"); } try { @@ -148,8 +144,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) } } } catch (std::system_error & ex) { - SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what()); - return -1; + return SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what()); } } diff --git a/src/thread/stdcpp/SDL_sysmutex.cpp b/src/thread/stdcpp/SDL_sysmutex.cpp index 4146bc98d..828801046 100644 --- a/src/thread/stdcpp/SDL_sysmutex.cpp +++ b/src/thread/stdcpp/SDL_sysmutex.cpp @@ -65,16 +65,14 @@ int SDL_mutexP(SDL_mutex * mutex) { if (mutex == NULL) { - SDL_SetError("Passed a NULL mutex"); - return -1; + return SDL_InvalidParamError("mutex"); } try { mutex->cpp_mutex.lock(); return 0; } catch (std::system_error & ex) { - SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what()); - return -1; + return SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what()); } } @@ -84,7 +82,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) { int retval = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } if (mutex->cpp_mutex.try_lock() == false) { @@ -99,8 +97,7 @@ int SDL_mutexV(SDL_mutex * mutex) { if (mutex == NULL) { - SDL_SetError("Passed a NULL mutex"); - return -1; + return SDL_InvalidParamError("mutex"); } mutex->cpp_mutex.unlock(); diff --git a/src/thread/stdcpp/SDL_systhread.cpp b/src/thread/stdcpp/SDL_systhread.cpp index 086a1fde2..3d818ac56 100644 --- a/src/thread/stdcpp/SDL_systhread.cpp +++ b/src/thread/stdcpp/SDL_systhread.cpp @@ -52,11 +52,9 @@ SDL_SYS_CreateThread(SDL_Thread * thread) thread->handle = (void *) new std::thread(std::move(cpp_thread)); return 0; } catch (std::system_error & ex) { - SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what()); - return -1; + return SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what()); } catch (std::bad_alloc &) { - SDL_OutOfMemory(); - return -1; + return SDL_OutOfMemory(); } } diff --git a/src/thread/vita/SDL_syscond.c b/src/thread/vita/SDL_syscond.c index 799bc0ae1..c6e46c475 100644 --- a/src/thread/vita/SDL_syscond.c +++ b/src/thread/vita/SDL_syscond.c @@ -84,7 +84,7 @@ int SDL_CondSignal(SDL_cond * cond) { if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -108,7 +108,7 @@ int SDL_CondBroadcast(SDL_cond * cond) { if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* If there are waiting threads not already signalled, then @@ -164,7 +164,7 @@ SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms) int retval; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } /* Obtain the protection mutex, and increment the number of waiters. diff --git a/src/thread/vita/SDL_sysmutex.c b/src/thread/vita/SDL_sysmutex.c index a18705a61..6327182cc 100644 --- a/src/thread/vita/SDL_sysmutex.c +++ b/src/thread/vita/SDL_sysmutex.c @@ -80,7 +80,7 @@ SDL_TryLockMutex(SDL_mutex * mutex) #else SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelTryLockLwMutex(&mutex->lock, 1); @@ -110,7 +110,7 @@ SDL_mutexP(SDL_mutex * mutex) #else SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelLockLwMutex(&mutex->lock, 1, NULL); @@ -132,7 +132,7 @@ SDL_mutexV(SDL_mutex * mutex) SceInt32 res = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } res = sceKernelUnlockLwMutex(&mutex->lock, 1); diff --git a/src/thread/vita/SDL_syssem.c b/src/thread/vita/SDL_syssem.c index 34e4d9ca8..7fecd6ca2 100644 --- a/src/thread/vita/SDL_syssem.c +++ b/src/thread/vita/SDL_syssem.c @@ -83,7 +83,7 @@ int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout) unsigned int res; if (sem == NULL) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -130,7 +130,7 @@ Uint32 SDL_SemValue(SDL_sem *sem) info.size = sizeof(info); if (sem == NULL) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -146,7 +146,7 @@ int SDL_SemPost(SDL_sem *sem) int res; if (sem == NULL) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } res = sceKernelSignalSema(sem->semid, 1); diff --git a/src/thread/windows/SDL_syscond_cv.c b/src/thread/windows/SDL_syscond_cv.c index 89c1a17f4..54d34084f 100644 --- a/src/thread/windows/SDL_syscond_cv.c +++ b/src/thread/windows/SDL_syscond_cv.c @@ -109,7 +109,7 @@ SDL_CondSignal_cv(SDL_cond * _cond) { SDL_cond_cv *cond = (SDL_cond_cv *)_cond; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } pWakeConditionVariable(&cond->cond); @@ -122,7 +122,7 @@ SDL_CondBroadcast_cv(SDL_cond * _cond) { SDL_cond_cv *cond = (SDL_cond_cv *)_cond; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } pWakeAllConditionVariable(&cond->cond); @@ -138,10 +138,10 @@ SDL_CondWaitTimeout_cv(SDL_cond * _cond, SDL_mutex * _mutex, Uint32 ms) int ret; if (!cond) { - return SDL_SetError("Passed a NULL condition variable"); + return SDL_InvalidParamError("cond"); } if (!_mutex) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } if (ms == SDL_MUTEX_MAXWAIT) { diff --git a/src/thread/windows/SDL_sysmutex.c b/src/thread/windows/SDL_sysmutex.c index 327f31db5..b0b4abcb0 100644 --- a/src/thread/windows/SDL_sysmutex.c +++ b/src/thread/windows/SDL_sysmutex.c @@ -88,7 +88,7 @@ SDL_LockMutex_srw(SDL_mutex * _mutex) DWORD this_thread; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } this_thread = GetCurrentThreadId(); @@ -115,7 +115,7 @@ SDL_TryLockMutex_srw(SDL_mutex * _mutex) int retval = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } this_thread = GetCurrentThreadId(); @@ -139,7 +139,7 @@ SDL_UnlockMutex_srw(SDL_mutex * _mutex) SDL_mutex_srw *mutex = (SDL_mutex_srw *)_mutex; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } if (mutex->owner == GetCurrentThreadId()) { @@ -208,7 +208,7 @@ SDL_LockMutex_cs(SDL_mutex * mutex_) { SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } EnterCriticalSection(&mutex->cs); @@ -222,7 +222,7 @@ SDL_TryLockMutex_cs(SDL_mutex * mutex_) SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_; int retval = 0; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } if (TryEnterCriticalSection(&mutex->cs) == 0) { @@ -237,7 +237,7 @@ SDL_UnlockMutex_cs(SDL_mutex * mutex_) { SDL_mutex_cs *mutex = (SDL_mutex_cs *)mutex_; if (mutex == NULL) { - return SDL_SetError("Passed a NULL mutex"); + return SDL_InvalidParamError("mutex"); } LeaveCriticalSection(&mutex->cs); diff --git a/src/thread/windows/SDL_syssem.c b/src/thread/windows/SDL_syssem.c index 3c2e69cf0..794a713a8 100644 --- a/src/thread/windows/SDL_syssem.c +++ b/src/thread/windows/SDL_syssem.c @@ -122,7 +122,7 @@ SDL_SemTryWait_atom(SDL_sem * _sem) LONG count; if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } count = sem->count; @@ -144,7 +144,7 @@ SDL_SemWait_atom(SDL_sem * _sem) LONG count; if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } for (;;) { @@ -176,7 +176,7 @@ SDL_SemWaitTimeout_atom(SDL_sem * _sem, Uint32 timeout) } if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } /** @@ -219,7 +219,7 @@ SDL_SemValue_atom(SDL_sem * _sem) SDL_sem_atom *sem = (SDL_sem_atom *)_sem; if (!sem) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } @@ -232,7 +232,7 @@ SDL_SemPost_atom(SDL_sem * _sem) SDL_sem_atom *sem = (SDL_sem_atom *)_sem; if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } InterlockedIncrement(&sem->count); @@ -313,7 +313,7 @@ SDL_SemWaitTimeout_kern(SDL_sem * _sem, Uint32 timeout) DWORD dwMilliseconds; if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } if (timeout == SDL_MUTEX_MAXWAIT) { @@ -354,7 +354,7 @@ SDL_SemValue_kern(SDL_sem * _sem) { SDL_sem_kern *sem = (SDL_sem_kern *)_sem; if (!sem) { - SDL_SetError("Passed a NULL sem"); + SDL_InvalidParamError("sem"); return 0; } return (Uint32)sem->count; @@ -365,7 +365,7 @@ SDL_SemPost_kern(SDL_sem * _sem) { SDL_sem_kern *sem = (SDL_sem_kern *)_sem; if (!sem) { - return SDL_SetError("Passed a NULL sem"); + return SDL_InvalidParamError("sem"); } /* Increase the counter in the first place, because * after a successful release the semaphore may diff --git a/src/timer/os2/SDL_systimer.c b/src/timer/os2/SDL_systimer.c index c5bcf64b7..8a8425d29 100644 --- a/src/timer/os2/SDL_systimer.c +++ b/src/timer/os2/SDL_systimer.c @@ -39,6 +39,7 @@ typedef unsigned long long ULLONG; +static SDL_bool ticks_started = SDL_FALSE; static ULONG ulTmrFreq = 0; static ULLONG ullTmrStart = 0; @@ -46,7 +47,14 @@ void SDL_TicksInit(void) { ULONG ulTmrStart; /* for 32-bit fallback. */ - ULONG ulRC = DosTmrQueryFreq(&ulTmrFreq); + ULONG ulRC; + + if (ticks_started) { + return; + } + ticks_started = SDL_TRUE; + + ulRC = DosTmrQueryFreq(&ulTmrFreq); if (ulRC != NO_ERROR) { debug_os2("DosTmrQueryFreq() failed, rc = %u", ulRC); } else { @@ -65,6 +73,7 @@ SDL_TicksInit(void) void SDL_TicksQuit(void) { + ticks_started = SDL_FALSE; } Uint64 @@ -73,7 +82,7 @@ SDL_GetTicks64(void) Uint64 ui64Result; ULLONG ullTmrNow; - if (ulTmrFreq == 0) { /* Was not initialized. */ + if (!ticks_started) { SDL_TicksInit(); } diff --git a/src/timer/unix/SDL_systimer.c b/src/timer/unix/SDL_systimer.c index 57fdab09c..2cf26764c 100644 --- a/src/timer/unix/SDL_systimer.c +++ b/src/timer/unix/SDL_systimer.c @@ -187,13 +187,6 @@ SDL_GetPerformanceFrequency(void) void SDL_Delay(Uint32 ms) { -#ifdef __EMSCRIPTEN__ - if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) { - /* pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent */ - emscripten_sleep(ms); - return; - } -#endif int was_error; #if HAVE_NANOSLEEP @@ -203,6 +196,14 @@ SDL_Delay(Uint32 ms) Uint64 then, now, elapsed; #endif +#ifdef __EMSCRIPTEN__ + if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) { + /* pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent */ + emscripten_sleep(ms); + return; + } +#endif + /* Set the timeout interval */ #if HAVE_NANOSLEEP elapsed.tv_sec = ms / 1000; diff --git a/src/video/SDL_blit.c b/src/video/SDL_blit.c index dc4d7e9c3..fa6492f51 100644 --- a/src/video/SDL_blit.c +++ b/src/video/SDL_blit.c @@ -231,9 +231,7 @@ SDL_CalculateBlit(SDL_Surface * surface) if (map->identity && !(map->info.flags & ~SDL_COPY_RLE_DESIRED)) { blit = SDL_BlitCopy; } else if (surface->format->Rloss > 8 || dst->format->Rloss > 8) { - /* Greater than 8 bits per channel not supported yet */ - SDL_InvalidateMap(map); - return SDL_SetError("Blit combination not supported"); + blit = SDL_Blit_Slow; } #if SDL_HAVE_BLIT_0 else if (surface->format->BitsPerPixel < 8 && diff --git a/src/video/SDL_blit.h b/src/video/SDL_blit.h index 53222e441..e00ba68e2 100644 --- a/src/video/SDL_blit.h +++ b/src/video/SDL_blit.h @@ -269,18 +269,18 @@ do { \ { \ switch (bpp) { \ case 1: { \ - Uint8 _Pixel; \ + Uint8 _pixel; \ \ - PIXEL_FROM_RGB(_Pixel, fmt, r, g, b); \ - *((Uint8 *)(buf)) = _Pixel; \ + PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \ + *((Uint8 *)(buf)) = _pixel; \ } \ break; \ \ case 2: { \ - Uint16 _Pixel; \ + Uint16 _pixel; \ \ - PIXEL_FROM_RGB(_Pixel, fmt, r, g, b); \ - *((Uint16 *)(buf)) = _Pixel; \ + PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \ + *((Uint16 *)(buf)) = _pixel; \ } \ break; \ \ @@ -298,10 +298,10 @@ do { \ break; \ \ case 4: { \ - Uint32 _Pixel; \ + Uint32 _pixel; \ \ - PIXEL_FROM_RGB(_Pixel, fmt, r, g, b); \ - *((Uint32 *)(buf)) = _Pixel; \ + PIXEL_FROM_RGB(_pixel, fmt, r, g, b); \ + *((Uint32 *)(buf)) = _pixel; \ } \ break; \ } \ diff --git a/src/video/SDL_blit_0.c b/src/video/SDL_blit_0.c index e2eecba7d..54882f8b1 100644 --- a/src/video/SDL_blit_0.c +++ b/src/video/SDL_blit_0.c @@ -452,11 +452,94 @@ static const SDL_BlitFunc colorkey_blit[] = { (SDL_BlitFunc) NULL, BlitBto1Key, BlitBto2Key, BlitBto3Key, BlitBto4Key }; + +static void +Blit4bto4(SDL_BlitInfo * info) +{ + int width = info->dst_w; + int height = info->dst_h; + Uint8 *src = info->src; + Uint32 *dst = (Uint32 *) info->dst; + int srcskip = info->src_skip; + int dstskip = info->dst_skip; + Uint32 *map = (Uint32 *) info->table; + int c; + + /* Set up some basic variables */ + srcskip += width - (width + 1) / 2; + + while (height--) { + Uint8 byte = 0, bit; + for (c = 0; c < width; ++c) { + if ((c & 0x1) == 0) { + byte = *src++; + } + bit = (byte & 0xF0) >> 4; + if (1) { + *dst = map[bit]; + } + byte <<= 4; + dst++; + } + src += srcskip; + dst = (Uint32 *) ((Uint8 *) dst + dstskip); + } +} + +static void +Blit4bto4Key(SDL_BlitInfo * info) +{ + int width = info->dst_w; + int height = info->dst_h; + Uint8 *src = info->src; + Uint32 *dst = (Uint32 *) info->dst; + int srcskip = info->src_skip; + int dstskip = info->dst_skip; + Uint32 ckey = info->colorkey; + Uint32 *map = (Uint32 *) info->table; + int c; + + /* Set up some basic variables */ + srcskip += width - (width + 1) / 2; + + while (height--) { + Uint8 byte = 0, bit; + for (c = 0; c < width; ++c) { + if ((c & 0x1) == 0) { + byte = *src++; + } + bit = (byte & 0xF0) >> 4; + if (bit != ckey) { + *dst = map[bit]; + } + byte <<= 4; + dst++; + } + src += srcskip; + dst = (Uint32 *) ((Uint8 *) dst + dstskip); + } +} + SDL_BlitFunc SDL_CalculateBlit0(SDL_Surface * surface) { int which; + /* 4bits to 32bits */ + if (surface->format->BitsPerPixel == 4) { + if (surface->map->dst->format->BytesPerPixel == 4) { + switch (surface->map->info.flags & ~SDL_COPY_RLE_MASK) { + case 0: + return Blit4bto4; + + case SDL_COPY_COLORKEY: + return Blit4bto4Key; + } + } + /* We don't fully support 4-bit packed pixel modes */ + return NULL; + } + if (surface->format->BitsPerPixel != 1) { /* We don't support sub 8-bit packed pixel modes */ return (SDL_BlitFunc) NULL; diff --git a/src/video/SDL_blit_N.c b/src/video/SDL_blit_N.c index 5736b86e3..e3b6c96a3 100644 --- a/src/video/SDL_blit_N.c +++ b/src/video/SDL_blit_N.c @@ -128,7 +128,7 @@ calc_swizzle32(const SDL_PixelFormat * srcfmt, const SDL_PixelFormat * dstfmt) * leave alpha with a zero mask, but we should still swizzle the bits. */ /* ARGB */ - const static const struct SDL_PixelFormat default_pixel_format = { + static const struct SDL_PixelFormat default_pixel_format = { 0, NULL, 0, 0, {0, 0}, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, diff --git a/src/video/SDL_blit_auto.c b/src/video/SDL_blit_auto.c index 359c1bdf5..f64511fcc 100644 --- a/src/video/SDL_blit_auto.c +++ b/src/video/SDL_blit_auto.c @@ -756,7 +756,6 @@ static void SDL_Blit_RGB888_ARGB8888_Scale(SDL_BlitInfo *info) { Uint32 pixel; const Uint32 A = 0xFF; - Uint32 R, G, B; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -776,8 +775,7 @@ static void SDL_Blit_RGB888_ARGB8888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel; - pixel = (A << 24) | (R << 16) | (G << 8) | B; + pixel |= (A << 24); *dst = pixel; posx += incx; ++dst; @@ -2232,7 +2230,6 @@ static void SDL_Blit_BGR888_ARGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info) static void SDL_Blit_ARGB8888_RGB888_Scale(SDL_BlitInfo *info) { Uint32 pixel; - Uint32 R, G, B; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -2252,8 +2249,7 @@ static void SDL_Blit_ARGB8888_RGB888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - R = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); B = (Uint8)pixel; - pixel = (R << 16) | (G << 8) | B; + pixel &= 0xFFFFFF; *dst = pixel; posx += incx; ++dst; @@ -3395,7 +3391,6 @@ static void SDL_Blit_ARGB8888_ARGB8888_Modulate_Blend_Scale(SDL_BlitInfo *info) static void SDL_Blit_RGBA8888_RGB888_Scale(SDL_BlitInfo *info) { Uint32 pixel; - Uint32 R, G, B; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -3415,8 +3410,7 @@ static void SDL_Blit_RGBA8888_RGB888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - R = (Uint8)(pixel >> 24); G = (Uint8)(pixel >> 16); B = (Uint8)(pixel >> 8); - pixel = (R << 16) | (G << 8) | B; + pixel >>= 8; *dst = pixel; posx += incx; ++dst; @@ -4163,7 +4157,6 @@ static void SDL_Blit_RGBA8888_BGR888_Modulate_Blend_Scale(SDL_BlitInfo *info) static void SDL_Blit_RGBA8888_ARGB8888_Scale(SDL_BlitInfo *info) { Uint32 pixel; - Uint32 R, G, B, A; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -4183,8 +4176,7 @@ static void SDL_Blit_RGBA8888_ARGB8888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - R = (Uint8)(pixel >> 24); G = (Uint8)(pixel >> 16); B = (Uint8)(pixel >> 8); A = (Uint8)pixel; - pixel = (A << 24) | (R << 16) | (G << 8) | B; + pixel = (pixel >> 8) | (pixel << 24); *dst = pixel; posx += incx; ++dst; @@ -4947,7 +4939,6 @@ static void SDL_Blit_ABGR8888_RGB888_Modulate_Blend_Scale(SDL_BlitInfo *info) static void SDL_Blit_ABGR8888_BGR888_Scale(SDL_BlitInfo *info) { Uint32 pixel; - Uint32 R, G, B; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -4967,8 +4958,7 @@ static void SDL_Blit_ABGR8888_BGR888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - B = (Uint8)(pixel >> 16); G = (Uint8)(pixel >> 8); R = (Uint8)pixel; - pixel = (B << 16) | (G << 8) | R; + pixel &= 0xFFFFFF; *dst = pixel; posx += incx; ++dst; @@ -6115,7 +6105,6 @@ static void SDL_Blit_BGRA8888_RGB888_Modulate_Blend_Scale(SDL_BlitInfo *info) static void SDL_Blit_BGRA8888_BGR888_Scale(SDL_BlitInfo *info) { Uint32 pixel; - Uint32 R, G, B; int srcy, srcx; Uint32 posy, posx; int incy, incx; @@ -6135,8 +6124,7 @@ static void SDL_Blit_BGRA8888_BGR888_Scale(SDL_BlitInfo *info) srcx = posx >> 16; src = (Uint32 *)(info->src + (srcy * info->src_pitch) + (srcx * 4)); pixel = *src; - B = (Uint8)(pixel >> 24); G = (Uint8)(pixel >> 16); R = (Uint8)(pixel >> 8); - pixel = (B << 16) | (G << 8) | R; + pixel >>= 8; *dst = pixel; posx += incx; ++dst; diff --git a/src/video/SDL_blit_slow.c b/src/video/SDL_blit_slow.c index a104517e8..ed9c692b1 100644 --- a/src/video/SDL_blit_slow.c +++ b/src/video/SDL_blit_slow.c @@ -24,6 +24,21 @@ #include "SDL_blit.h" #include "SDL_blit_slow.h" +#define FORMAT_ALPHA 0 +#define FORMAT_NO_ALPHA -1 +#define FORMAT_2101010 1 +#define FORMAT_HAS_ALPHA(format) format == 0 +#define FORMAT_HAS_NO_ALPHA(format) format < 0 +static int SDL_INLINE detect_format(SDL_PixelFormat *pf) { + if (pf->format == SDL_PIXELFORMAT_ARGB2101010) { + return FORMAT_2101010; + } else if (pf->Amask) { + return FORMAT_ALPHA; + } else { + return FORMAT_NO_ALPHA; + } +} + /* The ONE TRUE BLITTER * This puppy has to handle all the unoptimized cases - yes, it's slow. */ @@ -46,9 +61,14 @@ SDL_Blit_Slow(SDL_BlitInfo * info) SDL_PixelFormat *dst_fmt = info->dst_fmt; int srcbpp = src_fmt->BytesPerPixel; int dstbpp = dst_fmt->BytesPerPixel; + int srcfmt_val; + int dstfmt_val; Uint32 rgbmask = ~src_fmt->Amask; Uint32 ckey = info->colorkey & rgbmask; + srcfmt_val = detect_format(src_fmt); + dstfmt_val = detect_format(dst_fmt); + incy = (info->src_h << 16) / info->dst_h; incx = (info->src_w << 16) / info->dst_w; posy = incy / 2; /* start at the middle of pixel */ @@ -62,14 +82,18 @@ SDL_Blit_Slow(SDL_BlitInfo * info) while (n--) { srcx = posx >> 16; src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp)); - if (src_fmt->Amask) { - DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, - srcB, srcA); - } else { - DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, - srcB); + + if (FORMAT_HAS_ALPHA(srcfmt_val)) { + DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA); + } else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) { + DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB); srcA = 0xFF; + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + srcpixel = *((Uint32 *)(src)); + RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA); } + if (flags & SDL_COPY_COLORKEY) { /* srcpixel isn't set for 24 bpp */ if (srcbpp == 3) { @@ -82,13 +106,15 @@ SDL_Blit_Slow(SDL_BlitInfo * info) continue; } } - if (dst_fmt->Amask) { - DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, - dstB, dstA); - } else { - DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, - dstB); + if (FORMAT_HAS_ALPHA(dstfmt_val)) { + DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA); + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { + DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB); dstA = 0xFF; + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + dstpixel = *((Uint32 *)(dst)); + RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA); } if (flags & SDL_COPY_MODULATE_COLOR) { @@ -151,10 +177,15 @@ SDL_Blit_Slow(SDL_BlitInfo * info) dstA = 255; break; } - if (dst_fmt->Amask) { + if (FORMAT_HAS_ALPHA(dstfmt_val)) { ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA); - } else { + } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB); + } else { + /* SDL_PIXELFORMAT_ARGB2101010 */ + Uint32 pixel; + ARGB2101010_FROM_RGBA(pixel, dstR, dstG, dstB, dstA); + *(Uint32 *)dst = pixel; } posx += incx; dst += dstbpp; diff --git a/src/video/SDL_bmp.c b/src/video/SDL_bmp.c index 5bddd7354..cb220440a 100644 --- a/src/video/SDL_bmp.c +++ b/src/video/SDL_bmp.c @@ -53,7 +53,7 @@ #define LCS_WINDOWS_COLOR_SPACE 0x57696E20 #endif -static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) +static SDL_bool readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) { /* | Sets the surface pixels from src. A bmp image is upside down. @@ -70,14 +70,14 @@ static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) #define COPY_PIXEL(x) spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x) for (;;) { - if (!SDL_RWread(src, &ch, 1, 1)) return 1; + if (!SDL_RWread(src, &ch, 1, 1)) return SDL_TRUE; /* | encoded mode starts with a run length, and then a byte | with two colour indexes to alternate between for the run */ if (ch) { Uint8 pixel; - if (!SDL_RWread(src, &pixel, 1, 1)) return 1; + if (!SDL_RWread(src, &pixel, 1, 1)) return SDL_TRUE; if (isRle8) { /* 256-color bitmap, compressed */ do { COPY_PIXEL(pixel); @@ -98,18 +98,18 @@ static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) | a cursor move, or some absolute data. | zero tag may be absolute mode or an escape */ - if (!SDL_RWread(src, &ch, 1, 1)) return 1; + if (!SDL_RWread(src, &ch, 1, 1)) return SDL_TRUE; switch (ch) { case 0: /* end of line */ ofs = 0; bits -= pitch; /* go to previous */ break; case 1: /* end of bitmap */ - return 0; /* success! */ + return SDL_FALSE; /* success! */ case 2: /* delta */ - if (!SDL_RWread(src, &ch, 1, 1)) return 1; + if (!SDL_RWread(src, &ch, 1, 1)) return SDL_TRUE; ofs += ch; - if (!SDL_RWread(src, &ch, 1, 1)) return 1; + if (!SDL_RWread(src, &ch, 1, 1)) return SDL_TRUE; bits -= (ch * pitch); break; default: /* no compression */ @@ -117,14 +117,14 @@ static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) needsPad = (ch & 1); do { Uint8 pixel; - if (!SDL_RWread(src, &pixel, 1, 1)) return 1; + if (!SDL_RWread(src, &pixel, 1, 1)) return SDL_TRUE; COPY_PIXEL(pixel); } while (--ch); } else { needsPad = (((ch+1)>>1) & 1); /* (ch+1)>>1: bytes size */ for (;;) { Uint8 pixel; - if (!SDL_RWread(src, &pixel, 1, 1)) return 1; + if (!SDL_RWread(src, &pixel, 1, 1)) return SDL_TRUE; COPY_PIXEL(pixel >> 4); if (!--ch) break; COPY_PIXEL(pixel & 0x0F); @@ -132,7 +132,7 @@ static int readRlePixels(SDL_Surface * surface, SDL_RWops * src, int isRle8) } } /* pad at even boundary */ - if (needsPad && !SDL_RWread(src, &ch, 1, 1)) return 1; + if (needsPad && !SDL_RWread(src, &ch, 1, 1)) return SDL_TRUE; break; } } @@ -213,12 +213,17 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) surface = NULL; was_error = SDL_FALSE; if (src == NULL) { + SDL_InvalidParamError("src"); was_error = SDL_TRUE; goto done; } /* Read in the BMP file header */ fp_offset = SDL_RWtell(src); + if (fp_offset < 0) { + was_error = SDL_TRUE; + goto done; + } SDL_ClearError(); if (SDL_RWread(src, magic, 1, 2) != 2) { SDL_Error(SDL_EFREAD); @@ -407,6 +412,12 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) goto done; } + if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */ + SDL_SetError("Unsupported or incorrect biBitCount field"); + was_error = SDL_TRUE; + goto done; + } + if (biClrUsed == 0) { biClrUsed = 1 << biBitCount; } @@ -451,8 +462,8 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) goto done; } if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) { - was_error = (SDL_bool)readRlePixels(surface, src, biCompression == BI_RLE8); - if (was_error) SDL_SetError("Error reading from BMP"); + was_error = readRlePixels(surface, src, biCompression == BI_RLE8); + if (was_error) SDL_Error(SDL_EFREAD); goto done; } top = (Uint8 *)surface->pixels; @@ -484,7 +495,7 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) for (i = 0; i < surface->w; ++i) { if (i % (8 / ExpandBMP) == 0) { if (!SDL_RWread(src, &pixel, 1, 1)) { - SDL_SetError("Error reading from BMP"); + SDL_Error(SDL_EFREAD); was_error = SDL_TRUE; goto done; } diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index e10cf7c70..e62fe9931 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -27,7 +27,6 @@ #endif #if SDL_VIDEO_DRIVER_ANDROID #include -#include "../core/android/SDL_android.h" #include "../video/android/SDL_androidvideo.h" #endif #if SDL_VIDEO_DRIVER_RPI @@ -99,7 +98,7 @@ #define DEFAULT_OGL_ES "libGLESv1_CM.so.1" #endif /* SDL_VIDEO_DRIVER_RPI */ -#if SDL_VIDEO_OPENGL +#if SDL_VIDEO_OPENGL && !SDL_VIDEO_VITA_PVR_OGL #include "SDL_opengl.h" #endif @@ -530,7 +529,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa } #endif /* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */ - if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { + if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) && (_this->egl_data->eglGetDisplay != NULL)) { _this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display); } if (_this->egl_data->egl_display == EGL_NO_DISPLAY) { @@ -909,8 +908,7 @@ SDL_EGL_ChooseConfig(_THIS) int ret; if (!_this->egl_data) { - /* The EGL library wasn't loaded, SDL_GetError() should have info */ - return -1; + return SDL_SetError("EGL not initialized"); } /* Try with EGL_CONFIG_CAVEAT set to EGL_NONE, to avoid any EGL_SLOW_CONFIG or EGL_NON_CONFORMANT_CONFIG */ @@ -943,7 +941,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) SDL_bool profile_es = (profile_mask == SDL_GL_CONTEXT_PROFILE_ES); if (!_this->egl_data) { - /* The EGL library wasn't loaded, SDL_GetError() should have info */ + SDL_SetError("EGL not initialized"); return NULL; } @@ -1044,16 +1042,8 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) _this->egl_data->egl_swapinterval = 0; if (SDL_EGL_MakeCurrent(_this, egl_surface, egl_context) < 0) { - /* Save the SDL error set by SDL_EGL_MakeCurrent */ - char errorText[1024]; - SDL_strlcpy(errorText, SDL_GetError(), SDL_arraysize(errorText)); - - /* Delete the context, which may alter the value returned by SDL_GetError() */ + /* Delete the context */ SDL_EGL_DeleteContext(_this, egl_context); - - /* Restore the SDL error */ - SDL_SetError("%s", errorText); - return NULL; } @@ -1071,7 +1061,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface) if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) { _this->gl_allow_no_surface = SDL_TRUE; } -#if SDL_VIDEO_OPENGL +#if SDL_VIDEO_OPENGL && !defined(SDL_VIDEO_DRIVER_VITA) } else { /* Desktop OpenGL supports it by default from version 3.0 on. */ void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params); @@ -1096,7 +1086,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context) EGLContext egl_context = (EGLContext) context; if (!_this->egl_data) { - return SDL_SetError("OpenGL not initialized"); + return SDL_SetError("EGL not initialized"); } if (!_this->egl_data->eglMakeCurrent) { @@ -1104,7 +1094,7 @@ SDL_EGL_MakeCurrent(_THIS, EGLSurface egl_surface, SDL_GLContext context) /* Can't do the nothing there is to do? Probably trying to cleanup a failed startup, just return. */ return 0; } else { - return SDL_SetError("OpenGL not initialized"); /* something clearly went wrong somewhere. */ + return SDL_SetError("EGL not initialized"); /* something clearly went wrong somewhere. */ } } diff --git a/src/video/SDL_fillrect.c b/src/video/SDL_fillrect.c index 55702191a..13872d271 100644 --- a/src/video/SDL_fillrect.c +++ b/src/video/SDL_fillrect.c @@ -238,7 +238,7 @@ int SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color) { if (!dst) { - return SDL_SetError("Passed NULL destination surface"); + return SDL_InvalidParamError("SDL_FillRect(): dst"); } /* If 'rect' == NULL, then fill the whole surface */ @@ -306,12 +306,7 @@ SDL_FillRects(SDL_Surface * dst, const SDL_Rect * rects, int count, int i; if (!dst) { - return SDL_SetError("Passed NULL destination surface"); - } - - /* This function doesn't work on surfaces < 8 bpp */ - if (dst->format->BitsPerPixel < 8) { - return SDL_SetError("SDL_FillRect(): Unsupported surface format"); + return SDL_InvalidParamError("SDL_FillRects(): dst"); } /* Nothing to do */ @@ -321,11 +316,28 @@ SDL_FillRects(SDL_Surface * dst, const SDL_Rect * rects, int count, /* Perform software fill */ if (!dst->pixels) { - return SDL_SetError("SDL_FillRect(): You must lock the surface"); + return SDL_SetError("SDL_FillRects(): You must lock the surface"); } if (!rects) { - return SDL_SetError("SDL_FillRects() passed NULL rects"); + return SDL_InvalidParamError("SDL_FillRects(): rects"); + } + + /* This function doesn't usually work on surfaces < 8 bpp + * Except: support for 4bits, when filling full size. + */ + if (dst->format->BitsPerPixel < 8) { + if (count == 1) { + const SDL_Rect *r = &rects[0]; + if (r->x == 0 && r->y == 0 && r->w == dst->w && r->w == dst->h) { + if (dst->format->BitsPerPixel == 4) { + Uint8 b = (((Uint8) color << 4) | (Uint8) color); + SDL_memset(dst->pixels, b, dst->h * dst->pitch); + return 1; + } + } + } + return SDL_SetError("SDL_FillRects(): Unsupported surface format"); } #if SDL_ARM_NEON_BLITTERS diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c index 26da00cf4..858ccba7b 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -28,6 +28,7 @@ #include "SDL_blit.h" #include "SDL_pixels_c.h" #include "SDL_RLEaccel_c.h" +#include "../SDL_list.h" /* Lookup tables to expand partial bytes to the full 0..255 range */ @@ -677,7 +678,7 @@ int SDL_SetPixelFormatPalette(SDL_PixelFormat * format, SDL_Palette *palette) { if (!format) { - return SDL_SetError("SDL_SetPixelFormatPalette() passed NULL format"); + return SDL_InvalidParamError("SDL_SetPixelFormatPalette(): format"); } if (palette && palette->ncolors > (1 << format->BitsPerPixel)) { @@ -1024,12 +1025,6 @@ SDL_AllocBlitMap(void) } -typedef struct SDL_ListNode -{ - void *entry; - struct SDL_ListNode *next; -} SDL_ListNode; - void SDL_InvalidateAllBlitMap(SDL_Surface *surface) { @@ -1045,40 +1040,6 @@ SDL_InvalidateAllBlitMap(SDL_Surface *surface) } } -static void SDL_ListAdd(SDL_ListNode **head, void *ent); -static void SDL_ListRemove(SDL_ListNode **head, void *ent); - -void -SDL_ListAdd(SDL_ListNode **head, void *ent) -{ - SDL_ListNode *node = SDL_malloc(sizeof (*node)); - - if (node == NULL) { - SDL_OutOfMemory(); - return; - } - - node->entry = ent; - node->next = *head; - *head = node; -} - -void -SDL_ListRemove(SDL_ListNode **head, void *ent) -{ - SDL_ListNode **ptr = head; - - while (*ptr) { - if ((*ptr)->entry == ent) { - SDL_ListNode *tmp = *ptr; - *ptr = (*ptr)->next; - SDL_free(tmp); - return; - } - ptr = &(*ptr)->next; - } -} - void SDL_InvalidateMap(SDL_BlitMap * map) { diff --git a/src/video/SDL_rect.c b/src/video/SDL_rect.c index 0c929517c..dfa939032 100644 --- a/src/video/SDL_rect.c +++ b/src/video/SDL_rect.c @@ -23,447 +23,8 @@ #include "SDL_rect.h" #include "SDL_rect_c.h" -SDL_bool -SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B) -{ - int Amin, Amax, Bmin, Bmax; - - if (!A) { - SDL_InvalidParamError("A"); - return SDL_FALSE; - } - - if (!B) { - SDL_InvalidParamError("B"); - return SDL_FALSE; - } - - /* Special cases for empty rects */ - if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) { - return SDL_FALSE; - } - - /* Horizontal intersection */ - Amin = A->x; - Amax = Amin + A->w; - Bmin = B->x; - Bmax = Bmin + B->w; - if (Bmin > Amin) - Amin = Bmin; - if (Bmax < Amax) - Amax = Bmax; - if (Amax <= Amin) - return SDL_FALSE; - - /* Vertical intersection */ - Amin = A->y; - Amax = Amin + A->h; - Bmin = B->y; - Bmax = Bmin + B->h; - if (Bmin > Amin) - Amin = Bmin; - if (Bmax < Amax) - Amax = Bmax; - if (Amax <= Amin) - return SDL_FALSE; - - return SDL_TRUE; -} - -SDL_bool -SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result) -{ - int Amin, Amax, Bmin, Bmax; - - if (!A) { - SDL_InvalidParamError("A"); - return SDL_FALSE; - } - - if (!B) { - SDL_InvalidParamError("B"); - return SDL_FALSE; - } - - if (!result) { - SDL_InvalidParamError("result"); - return SDL_FALSE; - } - - /* Special cases for empty rects */ - if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) { - result->w = 0; - result->h = 0; - return SDL_FALSE; - } - - /* Horizontal intersection */ - Amin = A->x; - Amax = Amin + A->w; - Bmin = B->x; - Bmax = Bmin + B->w; - if (Bmin > Amin) - Amin = Bmin; - result->x = Amin; - if (Bmax < Amax) - Amax = Bmax; - result->w = Amax - Amin; - - /* Vertical intersection */ - Amin = A->y; - Amax = Amin + A->h; - Bmin = B->y; - Bmax = Bmin + B->h; - if (Bmin > Amin) - Amin = Bmin; - result->y = Amin; - if (Bmax < Amax) - Amax = Bmax; - result->h = Amax - Amin; - - return !SDL_RectEmpty(result); -} - -void -SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result) -{ - int Amin, Amax, Bmin, Bmax; - - if (!A) { - SDL_InvalidParamError("A"); - return; - } - - if (!B) { - SDL_InvalidParamError("B"); - return; - } - - if (!result) { - SDL_InvalidParamError("result"); - return; - } - - /* Special cases for empty Rects */ - if (SDL_RectEmpty(A)) { - if (SDL_RectEmpty(B)) { - /* A and B empty */ - return; - } else { - /* A empty, B not empty */ - *result = *B; - return; - } - } else { - if (SDL_RectEmpty(B)) { - /* A not empty, B empty */ - *result = *A; - return; - } - } - - /* Horizontal union */ - Amin = A->x; - Amax = Amin + A->w; - Bmin = B->x; - Bmax = Bmin + B->w; - if (Bmin < Amin) - Amin = Bmin; - result->x = Amin; - if (Bmax > Amax) - Amax = Bmax; - result->w = Amax - Amin; - - /* Vertical union */ - Amin = A->y; - Amax = Amin + A->h; - Bmin = B->y; - Bmax = Bmin + B->h; - if (Bmin < Amin) - Amin = Bmin; - result->y = Amin; - if (Bmax > Amax) - Amax = Bmax; - result->h = Amax - Amin; -} - -SDL_bool -SDL_EnclosePoints(const SDL_Point * points, int count, const SDL_Rect * clip, - SDL_Rect * result) -{ - int minx = 0; - int miny = 0; - int maxx = 0; - int maxy = 0; - int x, y, i; - - if (!points) { - SDL_InvalidParamError("points"); - return SDL_FALSE; - } - - if (count < 1) { - SDL_InvalidParamError("count"); - return SDL_FALSE; - } - - if (clip) { - SDL_bool added = SDL_FALSE; - const int clip_minx = clip->x; - const int clip_miny = clip->y; - const int clip_maxx = clip->x+clip->w-1; - const int clip_maxy = clip->y+clip->h-1; - - /* Special case for empty rectangle */ - if (SDL_RectEmpty(clip)) { - return SDL_FALSE; - } - - for (i = 0; i < count; ++i) { - x = points[i].x; - y = points[i].y; - - if (x < clip_minx || x > clip_maxx || - y < clip_miny || y > clip_maxy) { - continue; - } - if (!added) { - /* Special case: if no result was requested, we are done */ - if (result == NULL) { - return SDL_TRUE; - } - - /* First point added */ - minx = maxx = x; - miny = maxy = y; - added = SDL_TRUE; - continue; - } - if (x < minx) { - minx = x; - } else if (x > maxx) { - maxx = x; - } - if (y < miny) { - miny = y; - } else if (y > maxy) { - maxy = y; - } - } - if (!added) { - return SDL_FALSE; - } - } else { - /* Special case: if no result was requested, we are done */ - if (result == NULL) { - return SDL_TRUE; - } - - /* No clipping, always add the first point */ - minx = maxx = points[0].x; - miny = maxy = points[0].y; - - for (i = 1; i < count; ++i) { - x = points[i].x; - y = points[i].y; - - if (x < minx) { - minx = x; - } else if (x > maxx) { - maxx = x; - } - if (y < miny) { - miny = y; - } else if (y > maxy) { - maxy = y; - } - } - } - - if (result) { - result->x = minx; - result->y = miny; - result->w = (maxx-minx)+1; - result->h = (maxy-miny)+1; - } - return SDL_TRUE; -} - -/* Use the Cohen-Sutherland algorithm for line clipping */ -#define CODE_BOTTOM 1 -#define CODE_TOP 2 -#define CODE_LEFT 4 -#define CODE_RIGHT 8 - -static int -ComputeOutCode(const SDL_Rect * rect, int x, int y) -{ - int code = 0; - if (y < rect->y) { - code |= CODE_TOP; - } else if (y >= rect->y + rect->h) { - code |= CODE_BOTTOM; - } - if (x < rect->x) { - code |= CODE_LEFT; - } else if (x >= rect->x + rect->w) { - code |= CODE_RIGHT; - } - return code; -} - -SDL_bool -SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2, - int *Y2) -{ - int x = 0; - int y = 0; - int x1, y1; - int x2, y2; - int rectx1; - int recty1; - int rectx2; - int recty2; - int outcode1, outcode2; - - if (!rect) { - SDL_InvalidParamError("rect"); - return SDL_FALSE; - } - - if (!X1) { - SDL_InvalidParamError("X1"); - return SDL_FALSE; - } - - if (!Y1) { - SDL_InvalidParamError("Y1"); - return SDL_FALSE; - } - - if (!X2) { - SDL_InvalidParamError("X2"); - return SDL_FALSE; - } - - if (!Y2) { - SDL_InvalidParamError("Y2"); - return SDL_FALSE; - } - - /* Special case for empty rect */ - if (SDL_RectEmpty(rect)) { - return SDL_FALSE; - } - - x1 = *X1; - y1 = *Y1; - x2 = *X2; - y2 = *Y2; - rectx1 = rect->x; - recty1 = rect->y; - rectx2 = rect->x + rect->w - 1; - recty2 = rect->y + rect->h - 1; - - /* Check to see if entire line is inside rect */ - if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 && - y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) { - return SDL_TRUE; - } - - /* Check to see if entire line is to one side of rect */ - if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) || - (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) { - return SDL_FALSE; - } - - if (y1 == y2) { - /* Horizontal line, easy to clip */ - if (x1 < rectx1) { - *X1 = rectx1; - } else if (x1 > rectx2) { - *X1 = rectx2; - } - if (x2 < rectx1) { - *X2 = rectx1; - } else if (x2 > rectx2) { - *X2 = rectx2; - } - return SDL_TRUE; - } - - if (x1 == x2) { - /* Vertical line, easy to clip */ - if (y1 < recty1) { - *Y1 = recty1; - } else if (y1 > recty2) { - *Y1 = recty2; - } - if (y2 < recty1) { - *Y2 = recty1; - } else if (y2 > recty2) { - *Y2 = recty2; - } - return SDL_TRUE; - } - - /* More complicated Cohen-Sutherland algorithm */ - outcode1 = ComputeOutCode(rect, x1, y1); - outcode2 = ComputeOutCode(rect, x2, y2); - while (outcode1 || outcode2) { - if (outcode1 & outcode2) { - return SDL_FALSE; - } - - if (outcode1) { - if (outcode1 & CODE_TOP) { - y = recty1; - x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); - } else if (outcode1 & CODE_BOTTOM) { - y = recty2; - x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); - } else if (outcode1 & CODE_LEFT) { - x = rectx1; - y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); - } else if (outcode1 & CODE_RIGHT) { - x = rectx2; - y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); - } - x1 = x; - y1 = y; - outcode1 = ComputeOutCode(rect, x, y); - } else { - if (outcode2 & CODE_TOP) { - y = recty1; - x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); - } else if (outcode2 & CODE_BOTTOM) { - y = recty2; - x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); - } else if (outcode2 & CODE_LEFT) { - /* If this assertion ever fires, here's the static analysis that warned about it: - http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */ - SDL_assert(x2 != x1); /* if equal: division by zero. */ - x = rectx1; - y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); - } else if (outcode2 & CODE_RIGHT) { - /* If this assertion ever fires, here's the static analysis that warned about it: - http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */ - SDL_assert(x2 != x1); /* if equal: division by zero. */ - x = rectx2; - y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); - } - x2 = x; - y2 = y; - outcode2 = ComputeOutCode(rect, x, y); - } - } - *X1 = x1; - *Y1 = y1; - *X2 = x2; - *Y2 = y2; - return SDL_TRUE; -} - +/* There's no float version of this at the moment, because it's not a public API + and internally we only need the int version. */ SDL_bool SDL_GetSpanEnclosingRect(int width, int height, int numrects, const SDL_Rect * rects, SDL_Rect *span) @@ -475,24 +36,16 @@ SDL_GetSpanEnclosingRect(int width, int height, if (width < 1) { SDL_InvalidParamError("width"); return SDL_FALSE; - } - - if (height < 1) { + } else if (height < 1) { SDL_InvalidParamError("height"); return SDL_FALSE; - } - - if (!rects) { + } else if (!rects) { SDL_InvalidParamError("rects"); return SDL_FALSE; - } - - if (!span) { + } else if (!span) { SDL_InvalidParamError("span"); return SDL_FALSE; - } - - if (numrects < 1) { + } else if (numrects < 1) { SDL_InvalidParamError("numrects"); return SDL_FALSE; } @@ -527,4 +80,36 @@ SDL_GetSpanEnclosingRect(int width, int height, return SDL_FALSE; } + +/* For use with the Cohen-Sutherland algorithm for line clipping, in SDL_rect_impl.h */ +#define CODE_BOTTOM 1 +#define CODE_TOP 2 +#define CODE_LEFT 4 +#define CODE_RIGHT 8 + +/* Same code twice, for float and int versions... */ +#define RECTTYPE SDL_Rect +#define POINTTYPE SDL_Point +#define SCALARTYPE int +#define COMPUTEOUTCODE ComputeOutCode +#define SDL_HASINTERSECTION SDL_HasIntersection +#define SDL_INTERSECTRECT SDL_IntersectRect +#define SDL_RECTEMPTY SDL_RectEmpty +#define SDL_UNIONRECT SDL_UnionRect +#define SDL_ENCLOSEPOINTS SDL_EnclosePoints +#define SDL_INTERSECTRECTANDLINE SDL_IntersectRectAndLine +#include "SDL_rect_impl.h" + +#define RECTTYPE SDL_FRect +#define POINTTYPE SDL_FPoint +#define SCALARTYPE float +#define COMPUTEOUTCODE ComputeOutCodeF +#define SDL_HASINTERSECTION SDL_HasIntersectionF +#define SDL_INTERSECTRECT SDL_IntersectFRect +#define SDL_RECTEMPTY SDL_FRectEmpty +#define SDL_UNIONRECT SDL_UnionFRect +#define SDL_ENCLOSEPOINTS SDL_EncloseFPoints +#define SDL_INTERSECTRECTANDLINE SDL_IntersectFRectAndLine +#include "SDL_rect_impl.h" + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_rect_impl.h b/src/video/SDL_rect_impl.h new file mode 100644 index 000000000..993bb8eb0 --- /dev/null +++ b/src/video/SDL_rect_impl.h @@ -0,0 +1,444 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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. +*/ + +/* This file is #included twice to support int and float versions with the same code. */ + +SDL_bool +SDL_HASINTERSECTION(const RECTTYPE * A, const RECTTYPE * B) +{ + SCALARTYPE Amin, Amax, Bmin, Bmax; + + if (!A) { + SDL_InvalidParamError("A"); + return SDL_FALSE; + } else if (!B) { + SDL_InvalidParamError("B"); + return SDL_FALSE; + } else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { + return SDL_FALSE; /* Special cases for empty rects */ + } + + /* Horizontal intersection */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin > Amin) { + Amin = Bmin; + } + if (Bmax < Amax) { + Amax = Bmax; + } + if (Amax <= Amin) { + return SDL_FALSE; + } + /* Vertical intersection */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin > Amin) { + Amin = Bmin; + } + if (Bmax < Amax) { + Amax = Bmax; + } + if (Amax <= Amin) { + return SDL_FALSE; + } + return SDL_TRUE; +} + +SDL_bool +SDL_INTERSECTRECT(const RECTTYPE * A, const RECTTYPE * B, RECTTYPE * result) +{ + SCALARTYPE Amin, Amax, Bmin, Bmax; + + if (!A) { + SDL_InvalidParamError("A"); + return SDL_FALSE; + } else if (!B) { + SDL_InvalidParamError("B"); + return SDL_FALSE; + } else if (!result) { + SDL_InvalidParamError("result"); + return SDL_FALSE; + } else if (SDL_RECTEMPTY(A) || SDL_RECTEMPTY(B)) { /* Special cases for empty rects */ + result->w = 0; + result->h = 0; + return SDL_FALSE; + } + + /* Horizontal intersection */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin > Amin) { + Amin = Bmin; + } + result->x = Amin; + if (Bmax < Amax) { + Amax = Bmax; + } + result->w = Amax - Amin; + + /* Vertical intersection */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin > Amin) { + Amin = Bmin; + } + result->y = Amin; + if (Bmax < Amax) { + Amax = Bmax; + } + result->h = Amax - Amin; + + return !SDL_RECTEMPTY(result); +} + +void +SDL_UNIONRECT(const RECTTYPE * A, const RECTTYPE * B, RECTTYPE * result) +{ + SCALARTYPE Amin, Amax, Bmin, Bmax; + + if (!A) { + SDL_InvalidParamError("A"); + return; + } else if (!B) { + SDL_InvalidParamError("B"); + return; + } else if (!result) { + SDL_InvalidParamError("result"); + return; + } else if (SDL_RECTEMPTY(A)) { /* Special cases for empty Rects */ + if (SDL_RECTEMPTY(B)) { /* A and B empty */ + SDL_zerop(result); + } else { /* A empty, B not empty */ + *result = *B; + } + return; + } else if (SDL_RECTEMPTY(B)) { /* A not empty, B empty */ + *result = *A; + return; + } + + /* Horizontal union */ + Amin = A->x; + Amax = Amin + A->w; + Bmin = B->x; + Bmax = Bmin + B->w; + if (Bmin < Amin) { + Amin = Bmin; + } + result->x = Amin; + if (Bmax > Amax) { + Amax = Bmax; + } + result->w = Amax - Amin; + + /* Vertical union */ + Amin = A->y; + Amax = Amin + A->h; + Bmin = B->y; + Bmax = Bmin + B->h; + if (Bmin < Amin) { + Amin = Bmin; + } + result->y = Amin; + if (Bmax > Amax) { + Amax = Bmax; + } + result->h = Amax - Amin; +} + +SDL_bool SDL_ENCLOSEPOINTS(const POINTTYPE * points, int count, const RECTTYPE * clip, + RECTTYPE * result) +{ + SCALARTYPE minx = 0; + SCALARTYPE miny = 0; + SCALARTYPE maxx = 0; + SCALARTYPE maxy = 0; + SCALARTYPE x, y; + int i; + + if (!points) { + SDL_InvalidParamError("points"); + return SDL_FALSE; + } else if (count < 1) { + SDL_InvalidParamError("count"); + return SDL_FALSE; + } + + if (clip) { + SDL_bool added = SDL_FALSE; + const SCALARTYPE clip_minx = clip->x; + const SCALARTYPE clip_miny = clip->y; + const SCALARTYPE clip_maxx = clip->x+clip->w-1; + const SCALARTYPE clip_maxy = clip->y+clip->h-1; + + /* Special case for empty rectangle */ + if (SDL_RECTEMPTY(clip)) { + return SDL_FALSE; + } + + for (i = 0; i < count; ++i) { + x = points[i].x; + y = points[i].y; + + if (x < clip_minx || x > clip_maxx || + y < clip_miny || y > clip_maxy) { + continue; + } + if (!added) { + /* Special case: if no result was requested, we are done */ + if (result == NULL) { + return SDL_TRUE; + } + + /* First point added */ + minx = maxx = x; + miny = maxy = y; + added = SDL_TRUE; + continue; + } + if (x < minx) { + minx = x; + } else if (x > maxx) { + maxx = x; + } + if (y < miny) { + miny = y; + } else if (y > maxy) { + maxy = y; + } + } + if (!added) { + return SDL_FALSE; + } + } else { + /* Special case: if no result was requested, we are done */ + if (result == NULL) { + return SDL_TRUE; + } + + /* No clipping, always add the first point */ + minx = maxx = points[0].x; + miny = maxy = points[0].y; + + for (i = 1; i < count; ++i) { + x = points[i].x; + y = points[i].y; + + if (x < minx) { + minx = x; + } else if (x > maxx) { + maxx = x; + } + if (y < miny) { + miny = y; + } else if (y > maxy) { + maxy = y; + } + } + } + + if (result) { + result->x = minx; + result->y = miny; + result->w = (maxx-minx)+1; + result->h = (maxy-miny)+1; + } + return SDL_TRUE; +} + +/* Use the Cohen-Sutherland algorithm for line clipping */ +static int +COMPUTEOUTCODE(const RECTTYPE * rect, SCALARTYPE x, SCALARTYPE y) +{ + int code = 0; + if (y < rect->y) { + code |= CODE_TOP; + } else if (y >= rect->y + rect->h) { + code |= CODE_BOTTOM; + } + if (x < rect->x) { + code |= CODE_LEFT; + } else if (x >= rect->x + rect->w) { + code |= CODE_RIGHT; + } + return code; +} + +SDL_bool +SDL_INTERSECTRECTANDLINE(const RECTTYPE * rect, SCALARTYPE *X1, SCALARTYPE *Y1, SCALARTYPE *X2, + SCALARTYPE *Y2) +{ + SCALARTYPE x = 0; + SCALARTYPE y = 0; + SCALARTYPE x1, y1; + SCALARTYPE x2, y2; + SCALARTYPE rectx1; + SCALARTYPE recty1; + SCALARTYPE rectx2; + SCALARTYPE recty2; + int outcode1, outcode2; + + if (!rect) { + SDL_InvalidParamError("rect"); + return SDL_FALSE; + } else if (!X1) { + SDL_InvalidParamError("X1"); + return SDL_FALSE; + } else if (!Y1) { + SDL_InvalidParamError("Y1"); + return SDL_FALSE; + } else if (!X2) { + SDL_InvalidParamError("X2"); + return SDL_FALSE; + } else if (!Y2) { + SDL_InvalidParamError("Y2"); + return SDL_FALSE; + } else if (SDL_RECTEMPTY(rect)) { + return SDL_FALSE; /* Special case for empty rect */ + } + + x1 = *X1; + y1 = *Y1; + x2 = *X2; + y2 = *Y2; + rectx1 = rect->x; + recty1 = rect->y; + rectx2 = rect->x + rect->w - 1; + recty2 = rect->y + rect->h - 1; + + /* Check to see if entire line is inside rect */ + if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 && + y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) { + return SDL_TRUE; + } + + /* Check to see if entire line is to one side of rect */ + if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) || + (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) { + return SDL_FALSE; + } + + if (y1 == y2) { /* Horizontal line, easy to clip */ + if (x1 < rectx1) { + *X1 = rectx1; + } else if (x1 > rectx2) { + *X1 = rectx2; + } + if (x2 < rectx1) { + *X2 = rectx1; + } else if (x2 > rectx2) { + *X2 = rectx2; + } + return SDL_TRUE; + } + + if (x1 == x2) { /* Vertical line, easy to clip */ + if (y1 < recty1) { + *Y1 = recty1; + } else if (y1 > recty2) { + *Y1 = recty2; + } + if (y2 < recty1) { + *Y2 = recty1; + } else if (y2 > recty2) { + *Y2 = recty2; + } + return SDL_TRUE; + } + + /* More complicated Cohen-Sutherland algorithm */ + outcode1 = COMPUTEOUTCODE(rect, x1, y1); + outcode2 = COMPUTEOUTCODE(rect, x2, y2); + while (outcode1 || outcode2) { + if (outcode1 & outcode2) { + return SDL_FALSE; + } + + if (outcode1) { + if (outcode1 & CODE_TOP) { + y = recty1; + x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); + } else if (outcode1 & CODE_BOTTOM) { + y = recty2; + x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); + } else if (outcode1 & CODE_LEFT) { + x = rectx1; + y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); + } else if (outcode1 & CODE_RIGHT) { + x = rectx2; + y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); + } + x1 = x; + y1 = y; + outcode1 = COMPUTEOUTCODE(rect, x, y); + } else { + if (outcode2 & CODE_TOP) { + y = recty1; + x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); + } else if (outcode2 & CODE_BOTTOM) { + y = recty2; + x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1); + } else if (outcode2 & CODE_LEFT) { + /* If this assertion ever fires, here's the static analysis that warned about it: + http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */ + SDL_assert(x2 != x1); /* if equal: division by zero. */ + x = rectx1; + y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); + } else if (outcode2 & CODE_RIGHT) { + /* If this assertion ever fires, here's the static analysis that warned about it: + http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */ + SDL_assert(x2 != x1); /* if equal: division by zero. */ + x = rectx2; + y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1); + } + x2 = x; + y2 = y; + outcode2 = COMPUTEOUTCODE(rect, x, y); + } + } + *X1 = x1; + *Y1 = y1; + *X2 = x2; + *Y2 = y2; + return SDL_TRUE; +} + +#undef RECTTYPE +#undef POINTTYPE +#undef SCALARTYPE +#undef COMPUTEOUTCODE +#undef SDL_HASINTERSECTION +#undef SDL_INTERSECTRECT +#undef SDL_RECTEMPTY +#undef SDL_UNIONRECT +#undef SDL_ENCLOSEPOINTS +#undef SDL_INTERSECTRECTANDLINE + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index b3cfa5cd2..ec981a29c 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -219,7 +219,7 @@ int SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette) { if (!surface) { - return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface"); + return SDL_InvalidParamError("SDL_SetSurfacePalette(): surface"); } if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) { return -1; @@ -646,7 +646,7 @@ SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect, /* Make sure the surfaces aren't locked */ if (!src || !dst) { - return SDL_SetError("SDL_UpperBlit: passed a NULL surface"); + return SDL_InvalidParamError("SDL_UpperBlit(): src/dst"); } if (src->locked || dst->locked) { return SDL_SetError("Surfaces must not be locked during blit"); @@ -757,7 +757,7 @@ SDL_PrivateUpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect, /* Make sure the surfaces aren't locked */ if (!src || !dst) { - return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface"); + return SDL_InvalidParamError("SDL_UpperBlitScaled(): src/dst"); } if (src->locked || dst->locked) { return SDL_SetError("Surfaces must not be locked during blit"); @@ -1404,8 +1404,7 @@ int SDL_ConvertPixels(int width, int height, } #else if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) { - SDL_SetError("SDL not built with YUV support"); - return -1; + return SDL_SetError("SDL not built with YUV support"); } #endif diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 3f401a5b2..2384a64ac 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -307,6 +307,8 @@ struct SDL_VideoDevice void (*StartTextInput) (_THIS); void (*StopTextInput) (_THIS); void (*SetTextInputRect) (_THIS, SDL_Rect *rect); + void (*ClearComposition) (_THIS); + SDL_bool (*IsTextInputShown) (_THIS); /* Screen keyboard */ SDL_bool (*HasScreenKeyboardSupport) (_THIS); @@ -330,6 +332,7 @@ struct SDL_VideoDevice /* * * */ /* Data common to all drivers */ + SDL_bool checked_texture_framebuffer; SDL_bool is_dummy; SDL_bool suspend_screensaver; SDL_Window *wakeup_window; @@ -342,6 +345,7 @@ struct SDL_VideoDevice Uint32 next_object_id; char *clipboard_text; SDL_bool setting_display_mode; + SDL_bool disable_display_mode_switching; /* * * */ /* Data used by the GL drivers */ diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index cad77f1a8..93c803e70 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -128,8 +128,6 @@ static VideoBootStrap *bootstrap[] = { NULL }; -static SDL_VideoDevice *_this = NULL; - #define CHECK_WINDOW_MAGIC(window, retval) \ if (!_this) { \ SDL_UninitializedVideo(); \ @@ -172,130 +170,59 @@ typedef struct { int bytes_per_pixel; } SDL_WindowTextureData; -static SDL_bool -ShouldUseTextureFramebuffer() -{ - const char *hint; - - /* If there's no native framebuffer support then there's no option */ - if (!_this->CreateWindowFramebuffer) { - return SDL_TRUE; - } - - /* If this is the dummy driver there is no texture support */ - if (_this->is_dummy) { - return SDL_FALSE; - } - - /* See if the user or application wants a specific behavior */ - hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - if (hint) { - if (*hint == '0' || SDL_strcasecmp(hint, "false") == 0) { - return SDL_FALSE; - } else { - return SDL_TRUE; - } - } - - /* Each platform has different performance characteristics */ -#if defined(__WIN32__) - /* GDI BitBlt() is way faster than Direct3D dynamic textures right now. - */ - return SDL_FALSE; - -#elif defined(__MACOSX__) - /* Mac OS X uses OpenGL as the native fast path (for cocoa and X11) */ - return SDL_TRUE; - -#elif defined(__LINUX__) - /* Properly configured OpenGL drivers are faster than MIT-SHM */ -#if SDL_VIDEO_OPENGL - /* Ugh, find a way to cache this value! */ - { - SDL_Window *window; - SDL_GLContext context; - SDL_bool hasAcceleratedOpenGL = SDL_FALSE; - - window = SDL_CreateWindow("OpenGL test", -32, -32, 32, 32, SDL_WINDOW_OPENGL|SDL_WINDOW_HIDDEN); - if (window) { - context = SDL_GL_CreateContext(window); - if (context) { - const GLubyte *(APIENTRY * glGetStringFunc) (GLenum); - const char *vendor = NULL; - - glGetStringFunc = SDL_GL_GetProcAddress("glGetString"); - if (glGetStringFunc) { - vendor = (const char *) glGetStringFunc(GL_VENDOR); - } - /* Add more vendors here at will... */ - if (vendor && - (SDL_strstr(vendor, "ATI Technologies") || - SDL_strstr(vendor, "NVIDIA"))) { - hasAcceleratedOpenGL = SDL_TRUE; - } - SDL_GL_DeleteContext(context); - } - SDL_DestroyWindow(window); - } - return hasAcceleratedOpenGL; - } -#elif SDL_VIDEO_OPENGL_ES || SDL_VIDEO_OPENGL_ES2 - /* Let's be optimistic about this! */ - return SDL_TRUE; -#else - return SDL_FALSE; -#endif - -#else - /* Play it safe, assume that if there is a framebuffer driver that it's - optimized for the current platform. - */ - return SDL_FALSE; -#endif -} static int -SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) +SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) { - SDL_WindowTextureData *data; + SDL_RendererInfo info; + SDL_WindowTextureData *data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); + int i; - data = SDL_GetWindowData(window, SDL_WINDOWTEXTUREDATA); if (!data) { SDL_Renderer *renderer = NULL; - int i; const char *hint = SDL_GetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION); - - /* Check to see if there's a specific driver requested */ - if (hint && *hint != '0' && *hint != '1' && + const SDL_bool specific_accelerated_renderer = ( + hint && *hint != '0' && *hint != '1' && SDL_strcasecmp(hint, "true") != 0 && SDL_strcasecmp(hint, "false") != 0 && - SDL_strcasecmp(hint, "software") != 0) { + SDL_strcasecmp(hint, "software") != 0 + ); + + /* Check to see if there's a specific driver requested */ + if (specific_accelerated_renderer) { for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { - SDL_RendererInfo info; SDL_GetRenderDriverInfo(i, &info); if (SDL_strcasecmp(info.name, hint) == 0) { renderer = SDL_CreateRenderer(window, i, 0); break; } } - } - - if (!renderer) { + if (!renderer || (SDL_GetRendererInfo(renderer, &info) == -1)) { + if (renderer) { SDL_DestroyRenderer(renderer); } + return SDL_SetError("Requested renderer for " SDL_HINT_FRAMEBUFFER_ACCELERATION " is not available"); + } + /* if it was specifically requested, even if SDL_RENDERER_ACCELERATED isn't set, we'll accept this renderer. */ + } else { for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) { - SDL_RendererInfo info; SDL_GetRenderDriverInfo(i, &info); if (SDL_strcmp(info.name, "software") != 0) { renderer = SDL_CreateRenderer(window, i, 0); - if (renderer) { - break; + if (renderer && (SDL_GetRendererInfo(renderer, &info) == 0) && (info.flags & SDL_RENDERER_ACCELERATED)) { + break; /* this will work. */ + } + if (renderer) { /* wasn't accelerated, etc, skip it. */ + SDL_DestroyRenderer(renderer); + renderer = NULL; } } } - } - if (!renderer) { - return SDL_SetError("No hardware accelerated renderers available"); + if (!renderer) { + return SDL_SetError("No hardware accelerated renderers available"); + } } + SDL_assert(renderer != NULL); /* should have explicitly checked this above. */ + /* Create the data after we successfully create the renderer (bug #1116) */ data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); if (!data) { @@ -305,6 +232,10 @@ SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * f SDL_SetWindowData(window, SDL_WINDOWTEXTUREDATA, data); data->renderer = renderer; + } else { + if (SDL_GetRendererInfo(data->renderer, &info) == -1) { + return -1; + } } /* Free any old texture and pixel data */ @@ -315,23 +246,14 @@ SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * f SDL_free(data->pixels); data->pixels = NULL; - { - SDL_RendererInfo info; - Uint32 i; - - if (SDL_GetRendererInfo(data->renderer, &info) < 0) { - return -1; - } + /* Find the first format without an alpha channel */ + *format = info.texture_formats[0]; - /* Find the first format without an alpha channel */ - *format = info.texture_formats[0]; - - for (i = 0; i < info.num_texture_formats; ++i) { - if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && - !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { - *format = info.texture_formats[i]; - break; - } + for (i = 0; i < (int) info.num_texture_formats; ++i) { + if (!SDL_ISPIXELFORMAT_FOURCC(info.texture_formats[i]) && + !SDL_ISPIXELFORMAT_ALPHA(info.texture_formats[i])) { + *format = info.texture_formats[i]; + break; } } @@ -339,6 +261,7 @@ SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * f SDL_TEXTUREACCESS_STREAMING, window->w, window->h); if (!data->texture) { + /* codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_WINDOWTEXTUREDATA and not leaked here. */ return -1; } @@ -364,6 +287,8 @@ SDL_CreateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, Uint32 * f return 0; } +static SDL_VideoDevice *_this = NULL; + static int SDL_UpdateWindowTexture(SDL_VideoDevice *unused, SDL_Window * window, const SDL_Rect * rects, int numrects) { @@ -413,7 +338,6 @@ SDL_DestroyWindowTexture(SDL_VideoDevice *unused, SDL_Window * window) SDL_free(data); } - static int cmpmodes(const void *A, const void *B) { @@ -501,7 +425,7 @@ SDL_VideoInit(const char *driver_name) i = index = 0; video = NULL; if (driver_name == NULL) { - driver_name = SDL_getenv("SDL_VIDEODRIVER"); + driver_name = SDL_GetHint(SDL_HINT_VIDEODRIVER); } if (driver_name != NULL && *driver_name != 0) { const char *driver_attempt = driver_name; @@ -564,13 +488,6 @@ SDL_VideoInit(const char *driver_name) return SDL_SetError("The video driver did not add any displays"); } - /* Add the renderer framebuffer emulation if desired */ - if (ShouldUseTextureFramebuffer()) { - _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; - _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; - _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; - } - /* Disable the screen saver by default. This is a change from <= 2.0.1, but most things using SDL are games or media players; you wouldn't want a screensaver to trigger if you're playing exclusively with a @@ -970,7 +887,7 @@ SDL_GetClosestDisplayModeForDisplay(SDL_VideoDisplay * display, SDL_DisplayMode *current, *match; if (!mode || !closest) { - SDL_SetError("Missing desired mode or closest mode parameter"); + SDL_InvalidParamError("mode/closest"); return NULL; } @@ -1268,6 +1185,7 @@ SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode) } else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window), &fullscreen_mode, &fullscreen_mode)) { + SDL_zerop(mode); return SDL_SetError("Couldn't find display mode match"); } @@ -1421,14 +1339,17 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) resized = SDL_FALSE; } - /* only do the mode change if we want exclusive fullscreen */ - if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { - if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { - return -1; - } - } else { - if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { - return -1; + /* Don't try to change the display mode if the driver doesn't want it. */ + if (_this->disable_display_mode_switching == SDL_FALSE) { + /* only do the mode change if we want exclusive fullscreen */ + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { + if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) { + return -1; + } + } else { + if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) { + return -1; + } } } @@ -1576,12 +1497,16 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) } /* Some platforms have certain graphics backends enabled by default */ - if (!_this->is_dummy && !graphics_flags && !SDL_IsVideoContextExternal()) { + if (!graphics_flags && !SDL_IsVideoContextExternal()) { #if (SDL_VIDEO_OPENGL && __MACOSX__) || (__IPHONEOS__ && !TARGET_OS_MACCATALYST) || __ANDROID__ || __NACL__ - flags |= SDL_WINDOW_OPENGL; + if (_this->GL_CreateContext != NULL) { + flags |= SDL_WINDOW_OPENGL; + } #endif #if SDL_VIDEO_METAL && (TARGET_OS_MACCATALYST || __MACOSX__ || __IPHONEOS__) - flags |= SDL_WINDOW_METAL; + if (_this->Metal_CreateView != NULL) { + flags |= SDL_WINDOW_METAL; + } #endif } @@ -1756,6 +1681,7 @@ SDL_Window * SDL_CreateWindowFrom(const void *data) { SDL_Window *window; + Uint32 flags = SDL_WINDOW_FOREIGN; if (!_this) { SDL_UninitializedVideo(); @@ -1765,6 +1691,37 @@ SDL_CreateWindowFrom(const void *data) SDL_Unsupported(); return NULL; } + + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, SDL_FALSE)) { + if (!_this->GL_CreateContext) { + SDL_SetError("OpenGL support is either not configured in SDL " + "or not available in current SDL video driver " + "(%s) or platform", _this->name); + return NULL; + } + if (SDL_GL_LoadLibrary(NULL) < 0) { + return NULL; + } + flags |= SDL_WINDOW_OPENGL; + } + + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FOREIGN_WINDOW_VULKAN, SDL_FALSE)) { + if (!_this->Vulkan_CreateSurface) { + SDL_SetError("Vulkan support is either not configured in SDL " + "or not available in current SDL video driver " + "(%s) or platform", _this->name); + return NULL; + } + if (flags & SDL_WINDOW_OPENGL) { + SDL_SetError("Vulkan and OpenGL not supported on same window"); + return NULL; + } + if (SDL_Vulkan_LoadLibrary(NULL) < 0) { + return NULL; + } + flags |= SDL_WINDOW_VULKAN; + } + window = (SDL_Window *)SDL_calloc(1, sizeof(*window)); if (!window) { SDL_OutOfMemory(); @@ -1772,7 +1729,7 @@ SDL_CreateWindowFrom(const void *data) } window->magic = &_this->window_magic; window->id = _this->next_object_id++; - window->flags = SDL_WINDOW_FOREIGN; + window->flags = flags; window->last_fullscreen_flags = window->flags; window->is_destroying = SDL_FALSE; window->opacity = 1.0f; @@ -1818,7 +1775,9 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) } /* Restore video mode, etc. */ - SDL_HideWindow(window); + if (!(window->flags & SDL_WINDOW_FOREIGN)) { + SDL_HideWindow(window); + } /* Tear down the old native window */ if (window->surface) { @@ -1827,9 +1786,13 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) window->surface = NULL; window->surface_valid = SDL_FALSE; } - if (_this->DestroyWindowFramebuffer) { - _this->DestroyWindowFramebuffer(_this, window); + + if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */ + if (_this->DestroyWindowFramebuffer) { + _this->DestroyWindowFramebuffer(_this, window); + } } + if (_this->DestroyWindow && !(flags & SDL_WINDOW_FOREIGN)) { _this->DestroyWindow(_this, window); } @@ -1845,17 +1808,6 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) need_gl_load = SDL_TRUE; } - if ((window->flags & SDL_WINDOW_METAL) != (flags & SDL_WINDOW_METAL)) { - if (flags & SDL_WINDOW_METAL) { - need_gl_load = SDL_TRUE; - } else { - need_gl_unload = SDL_TRUE; - } - } else if (window->flags & SDL_WINDOW_METAL) { - need_gl_unload = SDL_TRUE; - need_gl_load = SDL_TRUE; - } - if ((window->flags & SDL_WINDOW_VULKAN) != (flags & SDL_WINDOW_VULKAN)) { if (flags & SDL_WINDOW_VULKAN) { need_vulkan_load = SDL_TRUE; @@ -1868,18 +1820,15 @@ SDL_RecreateWindow(SDL_Window * window, Uint32 flags) } if ((flags & SDL_WINDOW_VULKAN) && (flags & SDL_WINDOW_OPENGL)) { - SDL_SetError("Vulkan and OpenGL not supported on same window"); - return -1; + return SDL_SetError("Vulkan and OpenGL not supported on same window"); } if ((flags & SDL_WINDOW_METAL) && (flags & SDL_WINDOW_OPENGL)) { - SDL_SetError("Metal and OpenGL not supported on same window"); - return -1; + return SDL_SetError("Metal and OpenGL not supported on same window"); } if ((flags & SDL_WINDOW_METAL) && (flags & SDL_WINDOW_VULKAN)) { - SDL_SetError("Metal and Vulkan not supported on same window"); - return -1; + return SDL_SetError("Metal and Vulkan not supported on same window"); } if (need_gl_unload) { @@ -2273,12 +2222,14 @@ SDL_SetWindowSize(SDL_Window * window, int w, int h) SDL_UpdateFullscreenMode(window, SDL_TRUE); } } else { + int old_w = window->w; + int old_h = window->h; window->w = w; window->h = h; if (_this->SetWindowSize) { _this->SetWindowSize(_this, window); } - if (window->w == w && window->h == h) { + if (window->w != old_w || window->h != old_h) { /* We didn't get a SDL_WINDOWEVENT_RESIZED event (by design) */ SDL_OnWindowResized(window); } @@ -2539,18 +2490,63 @@ SDL_SetWindowFullscreen(SDL_Window * window, Uint32 flags) static SDL_Surface * SDL_CreateWindowFramebuffer(SDL_Window * window) { - Uint32 format; - void *pixels; - int pitch; + Uint32 format = 0; + void *pixels = NULL; + int pitch = 0; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; + SDL_bool created_framebuffer = SDL_FALSE; - if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { - return NULL; + /* This will switch the video backend from using a software surface to + using a GPU texture through the 2D render API, if we think this would + be more efficient. This only checks once, on demand. */ + if (!_this->checked_texture_framebuffer) { + SDL_bool attempt_texture_framebuffer = SDL_TRUE; + + if (_this->is_dummy) { /* dummy driver never has GPU support, of course. */ + attempt_texture_framebuffer = SDL_FALSE; + } + + #if defined(__WIN32__) /* GDI BitBlt() is way faster than Direct3D dynamic textures right now. (!!! FIXME: is this still true?) */ + else if ((_this->CreateWindowFramebuffer != NULL) && (SDL_strcmp(_this->name, "windows") == 0)) { + attempt_texture_framebuffer = SDL_FALSE; + } + #endif + #if defined(__EMSCRIPTEN__) + else { + attempt_texture_framebuffer = SDL_FALSE; + } + #endif + + if (attempt_texture_framebuffer) { + if (SDL_CreateWindowTexture(_this, window, &format, &pixels, &pitch) == -1) { + /* !!! FIXME: if this failed halfway (made renderer, failed to make texture, etc), + !!! FIXME: we probably need to clean this up so it doesn't interfere with + !!! FIXME: a software fallback at the system level (can we blit to an + !!! FIXME: OpenGL window? etc). */ + } else { + /* future attempts will just try to use a texture framebuffer. */ + /* !!! FIXME: maybe we shouldn't override these but check if we used a texture + !!! FIXME: framebuffer at the right places; is it feasible we could have an + !!! FIXME: accelerated OpenGL window and a second ends up in software? */ + _this->CreateWindowFramebuffer = SDL_CreateWindowTexture; + _this->UpdateWindowFramebuffer = SDL_UpdateWindowTexture; + _this->DestroyWindowFramebuffer = SDL_DestroyWindowTexture; + created_framebuffer = SDL_TRUE; + } + } + + _this->checked_texture_framebuffer = SDL_TRUE; /* don't check this again. */ } - if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) { - return NULL; + if (!created_framebuffer) { + if (!_this->CreateWindowFramebuffer || !_this->UpdateWindowFramebuffer) { + return NULL; + } + + if (_this->CreateWindowFramebuffer(_this, window, &format, &pixels, &pitch) < 0) { + return NULL; + } } if (window->surface) { @@ -2608,6 +2604,8 @@ SDL_UpdateWindowSurfaceRects(SDL_Window * window, const SDL_Rect * rects, return SDL_SetError("Window surface is invalid, please call SDL_GetWindowSurface() to get a new surface"); } + SDL_assert(_this->checked_texture_framebuffer); /* we should have done this before we had a valid surface. */ + return _this->UpdateWindowFramebuffer(_this, window, rects, numrects); } @@ -3062,7 +3060,8 @@ ShouldMinimizeOnFocusLoss(SDL_Window * window) /* Real fullscreen windows should minimize on focus loss so the desktop video mode is restored */ hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS); if (!hint || !*hint || SDL_strcasecmp(hint, "auto") == 0) { - if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP || + _this->disable_display_mode_switching == SDL_TRUE) { return SDL_FALSE; } else { return SDL_TRUE; @@ -3113,7 +3112,9 @@ SDL_DestroyWindow(SDL_Window * window) window->is_destroying = SDL_TRUE; /* Restore video mode, etc. */ - SDL_HideWindow(window); + if (!(window->flags & SDL_WINDOW_FOREIGN)) { + SDL_HideWindow(window); + } /* Make sure this window no longer has focus */ if (SDL_GetKeyboardFocus() == window) { @@ -3136,8 +3137,10 @@ SDL_DestroyWindow(SDL_Window * window) window->surface = NULL; window->surface_valid = SDL_FALSE; } - if (_this->DestroyWindowFramebuffer) { - _this->DestroyWindowFramebuffer(_this, window); + if (_this->checked_texture_framebuffer) { /* never checked? No framebuffer to destroy. Don't risk calling the wrong implementation. */ + if (_this->DestroyWindowFramebuffer) { + _this->DestroyWindowFramebuffer(_this, window); + } } if (_this->DestroyWindow) { _this->DestroyWindow(_this, window); @@ -3922,6 +3925,10 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx) { int retval; + if (!_this) { + return SDL_UninitializedVideo(); + } + if (window == SDL_GL_GetCurrentWindow() && ctx == SDL_GL_GetCurrentContext()) { /* We're already current. */ @@ -4179,6 +4186,24 @@ SDL_StartTextInput(void) } } +void +SDL_ClearComposition(void) +{ + if (_this && _this->ClearComposition) { + _this->ClearComposition(_this); + } +} + +SDL_bool +SDL_IsTextInputShown(void) +{ + if (_this && _this->IsTextInputShown) { + return _this->IsTextInputShown(_this); + } + + return SDL_FALSE; +} + SDL_bool SDL_IsTextInputActive(void) { diff --git a/src/video/SDL_vulkan_internal.h b/src/video/SDL_vulkan_internal.h index 52fae34da..1ec1ab473 100644 --- a/src/video/SDL_vulkan_internal.h +++ b/src/video/SDL_vulkan_internal.h @@ -25,12 +25,10 @@ #include "SDL_stdinc.h" -#if defined(SDL_LOADSO_DISABLED) -#undef SDL_VIDEO_VULKAN -#define SDL_VIDEO_VULKAN 0 -#endif - #if SDL_VIDEO_VULKAN +#if SDL_LOADSO_DISABLED || SDL_LOADSO_DUMMY +#error You should not be here. +#endif #if SDL_VIDEO_DRIVER_ANDROID #define VK_USE_PLATFORM_ANDROID_KHR diff --git a/src/video/android/SDL_androidevents.c b/src/video/android/SDL_androidevents.c index 23a5bf50b..3424a8254 100644 --- a/src/video/android/SDL_androidevents.c +++ b/src/video/android/SDL_androidevents.c @@ -67,6 +67,7 @@ SDL_NumberOfEvents(Uint32 type) return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type); } +#if SDL_VIDEO_OPENGL_EGL static void android_egl_context_restore(SDL_Window *window) { @@ -96,7 +97,7 @@ android_egl_context_backup(SDL_Window *window) data->backup_done = 1; } } - +#endif /* * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume @@ -113,12 +114,14 @@ Android_PumpEvents_Blocking(_THIS) if (videodata->isPaused) { SDL_bool isContextExternal = SDL_IsVideoContextExternal(); +#if SDL_VIDEO_OPENGL_EGL /* Make sure this is the last thing we do before pausing */ if (!isContextExternal) { SDL_LockMutex(Android_ActivityMutex); android_egl_context_backup(Android_Window); SDL_UnlockMutex(Android_ActivityMutex); } +#endif ANDROIDAUDIO_PauseDevices(); openslES_PauseDevices(); @@ -138,11 +141,13 @@ Android_PumpEvents_Blocking(_THIS) aaudio_ResumeDevices(); /* Restore the GL Context from here, as this operation is thread dependent */ +#if SDL_VIDEO_OPENGL_EGL if (!isContextExternal && !SDL_HasEvent(SDL_QUIT)) { SDL_LockMutex(Android_ActivityMutex); android_egl_context_restore(Android_Window); SDL_UnlockMutex(Android_ActivityMutex); } +#endif /* Make sure SW Keyboard is restored when an app becomes foreground */ if (SDL_IsTextInputActive()) { @@ -188,11 +193,13 @@ Android_PumpEvents_NonBlocking(_THIS) SDL_bool isContextExternal = SDL_IsVideoContextExternal(); if (backup_context) { +#if SDL_VIDEO_OPENGL_EGL if (!isContextExternal) { SDL_LockMutex(Android_ActivityMutex); android_egl_context_backup(Android_Window); SDL_UnlockMutex(Android_ActivityMutex); } +#endif if (videodata->pauseAudio) { ANDROIDAUDIO_PauseDevices(); @@ -219,12 +226,14 @@ Android_PumpEvents_NonBlocking(_THIS) aaudio_ResumeDevices(); } +#if SDL_VIDEO_OPENGL_EGL /* Restore the GL Context from here, as this operation is thread dependent */ if (!isContextExternal && !SDL_HasEvent(SDL_QUIT)) { SDL_LockMutex(Android_ActivityMutex); android_egl_context_restore(Android_Window); SDL_UnlockMutex(Android_ActivityMutex); } +#endif /* Make sure SW Keyboard is restored when an app becomes foreground */ if (SDL_IsTextInputActive()) { diff --git a/src/video/android/SDL_androidgl.c b/src/video/android/SDL_androidgl.c index 698b87190..fe1b17b26 100644 --- a/src/video/android/SDL_androidgl.c +++ b/src/video/android/SDL_androidgl.c @@ -20,7 +20,7 @@ */ #include "../../SDL_internal.h" -#if SDL_VIDEO_DRIVER_ANDROID +#if SDL_VIDEO_DRIVER_ANDROID && SDL_VIDEO_OPENGL_EGL /* Android SDL video driver implementation */ diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index 330192918..9555ea078 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -122,12 +122,14 @@ Android_CreateDevice(int devindex) device->SetWindowTitle = Android_SetWindowTitle; device->SetWindowFullscreen = Android_SetWindowFullscreen; device->MinimizeWindow = Android_MinimizeWindow; + device->SetWindowResizable = Android_SetWindowResizable; device->DestroyWindow = Android_DestroyWindow; device->GetWindowWMInfo = Android_GetWindowWMInfo; device->free = Android_DeleteDevice; /* GL pointers */ +#if SDL_VIDEO_OPENGL_EGL device->GL_LoadLibrary = Android_GLES_LoadLibrary; device->GL_GetProcAddress = Android_GLES_GetProcAddress; device->GL_UnloadLibrary = Android_GLES_UnloadLibrary; @@ -137,6 +139,7 @@ Android_CreateDevice(int devindex) device->GL_GetSwapInterval = Android_GLES_GetSwapInterval; device->GL_SwapWindow = Android_GLES_SwapWindow; device->GL_DeleteContext = Android_GLES_DeleteContext; +#endif #if SDL_VIDEO_VULKAN device->Vulkan_LoadLibrary = Android_Vulkan_LoadLibrary; diff --git a/src/video/android/SDL_androidwindow.c b/src/video/android/SDL_androidwindow.c index c8e45331a..f9ae3f10c 100644 --- a/src/video/android/SDL_androidwindow.c +++ b/src/video/android/SDL_androidwindow.c @@ -81,6 +81,7 @@ Android_CreateWindow(_THIS, SDL_Window * window) /* Do not create EGLSurface for Vulkan window since it will then make the window incompatible with vkCreateAndroidSurfaceKHR */ +#if SDL_VIDEO_OPENGL_EGL if ((window->flags & SDL_WINDOW_OPENGL) != 0) { data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->native_window); @@ -91,6 +92,7 @@ Android_CreateWindow(_THIS, SDL_Window * window) goto endfunction; } } +#endif window->driverdata = data; Android_Window = window; @@ -165,6 +167,12 @@ Android_MinimizeWindow(_THIS, SDL_Window *window) Android_JNI_MinizeWindow(); } +void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable) +{ + /* Set orientation */ + Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS)); +} + void Android_DestroyWindow(_THIS, SDL_Window *window) { @@ -175,9 +183,13 @@ Android_DestroyWindow(_THIS, SDL_Window *window) if (window->driverdata) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + +#if SDL_VIDEO_OPENGL_EGL if (data->egl_surface != EGL_NO_SURFACE) { SDL_EGL_DestroySurface(_this, data->egl_surface); } +#endif + if (data->native_window) { ANativeWindow_release(data->native_window); } @@ -198,7 +210,11 @@ Android_GetWindowWMInfo(_THIS, SDL_Window *window, SDL_SysWMinfo *info) info->version.minor == SDL_MINOR_VERSION) { info->subsystem = SDL_SYSWM_ANDROID; info->info.android.window = data->native_window; + +#if SDL_VIDEO_OPENGL_EGL info->info.android.surface = data->egl_surface; +#endif + return SDL_TRUE; } else { SDL_SetError("Application not compiled with SDL %d.%d", diff --git a/src/video/android/SDL_androidwindow.h b/src/video/android/SDL_androidwindow.h index efda30303..58e459006 100644 --- a/src/video/android/SDL_androidwindow.h +++ b/src/video/android/SDL_androidwindow.h @@ -30,6 +30,7 @@ extern int Android_CreateWindow(_THIS, SDL_Window *window); extern void Android_SetWindowTitle(_THIS, SDL_Window *window); extern void Android_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen); extern void Android_MinimizeWindow(_THIS, SDL_Window *window); +extern void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable); extern void Android_DestroyWindow(_THIS, SDL_Window *window); extern SDL_bool Android_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info); @@ -37,8 +38,10 @@ extern SDL_Window *Android_Window; typedef struct { +#if SDL_VIDEO_OPENGL_EGL EGLSurface egl_surface; EGLContext egl_context; /* We use this to preserve the context when losing focus */ +#endif SDL_bool backup_done; ANativeWindow *native_window; diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index e8ce12d86..7d19030b2 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -40,6 +40,9 @@ #ifndef MAC_OS_X_VERSION_10_13 #define NSAppKitVersionNumber10_12 1504 #endif +#if (IOGRAPHICSTYPES_REV < 40) +#define kDisplayModeNativeFlag 0x02000000 +#endif static void diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 56cb86b27..ec875e570 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -253,7 +253,7 @@ + (NSCursor *)invisibleCursor static void Cocoa_WarpMouse(SDL_Window * window, int x, int y) { - Cocoa_WarpMouseGlobal(x + window->x, y + window->y); + Cocoa_WarpMouseGlobal(window->x + x, window->y + y); } static int @@ -262,9 +262,9 @@ + (NSCursor *)invisibleCursor /* We will re-apply the relative mode when the window gets focus, if it * doesn't have focus right now. */ - SDL_Window *window = SDL_GetMouseFocus(); + SDL_Window *window = SDL_GetKeyboardFocus(); if (!window) { - return 0; + return 0; } /* We will re-apply the relative mode when the window finishes being moved, diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 17a7228c5..974872248 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -2055,9 +2055,19 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent */ SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Cocoa_WindowListener *listener = data->listener; + NSWindow *nswindow = data->nswindow; + SDL_VideoData *videodata = ((SDL_WindowData *) window->driverdata)->videodata; if (![listener isInFullscreenSpace]) { SetWindowStyle(window, GetWindowStyle(window)); } + if (videodata->allow_spaces) { + if (resizable) { + /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */ + [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + } else { + [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged]; + } + } }} void diff --git a/src/video/dummy/SDL_nullframebuffer.c b/src/video/dummy/SDL_nullframebuffer.c index f11ee3fe4..dd7cbbd16 100644 --- a/src/video/dummy/SDL_nullframebuffer.c +++ b/src/video/dummy/SDL_nullframebuffer.c @@ -33,17 +33,13 @@ int SDL_DUMMY_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * forma SDL_Surface *surface; const Uint32 surface_format = SDL_PIXELFORMAT_RGB888; int w, h; - int bpp; - Uint32 Rmask, Gmask, Bmask, Amask; /* Free the old framebuffer surface */ - surface = (SDL_Surface *) SDL_GetWindowData(window, DUMMY_SURFACE); - SDL_FreeSurface(surface); + SDL_DUMMY_DestroyWindowFramebuffer(_this, window); /* Create a new one */ - SDL_PixelFormatEnumToMasks(surface_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); SDL_GetWindowSize(window, &w, &h); - surface = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask); + surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format); if (!surface) { return -1; } diff --git a/src/video/dummy/SDL_nullvideo.c b/src/video/dummy/SDL_nullvideo.c index aafed848d..a7fb1aac2 100644 --- a/src/video/dummy/SDL_nullvideo.c +++ b/src/video/dummy/SDL_nullvideo.c @@ -46,6 +46,7 @@ #include "SDL_nullvideo.h" #include "SDL_nullevents_c.h" #include "SDL_nullframebuffer_c.h" +#include "SDL_hints.h" #define DUMMYVID_DRIVER_NAME "dummy" @@ -59,7 +60,7 @@ static void DUMMY_VideoQuit(_THIS); static int DUMMY_Available(void) { - const char *envr = SDL_getenv("SDL_VIDEODRIVER"); + const char *envr = SDL_GetHint(SDL_HINT_VIDEODRIVER); if ((envr) && (SDL_strcmp(envr, DUMMYVID_DRIVER_NAME) == 0)) { return (1); } diff --git a/src/video/emscripten/SDL_emscriptenevents.c b/src/video/emscripten/SDL_emscriptenevents.c index 0f7da8e3f..39578f854 100644 --- a/src/video/emscripten/SDL_emscriptenevents.c +++ b/src/video/emscripten/SDL_emscriptenevents.c @@ -493,7 +493,7 @@ static EM_BOOL Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData) { Uint32 scancode; - SDL_bool prevent_default; + SDL_bool prevent_default = SDL_FALSE; SDL_bool is_nav_key; /* .keyCode is deprecated, but still the most reliable way to get keys */ @@ -577,12 +577,10 @@ Emscripten_HandleKey(int eventType, const EmscriptenKeyboardEvent *keyEvent, voi break; } } - SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode); + prevent_default = SDL_SendKeyboardKey(eventType == EMSCRIPTEN_EVENT_KEYDOWN ? SDL_PRESSED : SDL_RELEASED, scancode); } } - 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 */ diff --git a/src/video/emscripten/SDL_emscriptenframebuffer.c b/src/video/emscripten/SDL_emscriptenframebuffer.c index d4e9cb8e8..372c6f5ac 100644 --- a/src/video/emscripten/SDL_emscriptenframebuffer.c +++ b/src/video/emscripten/SDL_emscriptenframebuffer.c @@ -26,6 +26,8 @@ #include "SDL_emscriptenframebuffer.h" #include "SDL_hints.h" +#include + int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) { @@ -57,18 +59,9 @@ int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * form return 0; } -int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +static void +Emscripten_UpdateWindowFramebufferWorker(SDL_Surface* surface) { - SDL_Surface *surface; - - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - surface = data->surface; - if (!surface) { - return SDL_SetError("Couldn't find framebuffer surface for window"); - } - - /* Send the data to the display */ - EM_ASM_INT({ var w = $0; var h = $1; @@ -156,6 +149,29 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec SDL2.ctx.putImageData(SDL2.image, 0, 0); return 0; }, surface->w, surface->h, surface->pixels); +} + +int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +{ + SDL_Surface *surface; + + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + surface = data->surface; + if (!surface) { + return SDL_SetError("Couldn't find framebuffer surface for window"); + } + + /* Send the data to the display */ + + if (emscripten_is_main_runtime_thread()) { + Emscripten_UpdateWindowFramebufferWorker(surface); + } else { + emscripten_sync_run_in_main_runtime_thread( + EM_FUNC_SIG_VI, + Emscripten_UpdateWindowFramebufferWorker, + (uint32_t)surface + ); + } if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) { /* give back control to browser for screen refresh */ diff --git a/src/video/emscripten/SDL_emscriptenmouse.c b/src/video/emscripten/SDL_emscriptenmouse.c index e73072590..e41480725 100644 --- a/src/video/emscripten/SDL_emscriptenmouse.c +++ b/src/video/emscripten/SDL_emscriptenmouse.c @@ -24,6 +24,7 @@ #include #include +#include #include "SDL_emscriptenmouse.h" #include "SDL_emscriptenvideo.h" @@ -62,19 +63,10 @@ Emscripten_CreateDefaultCursor() return Emscripten_CreateCursorFromString("default", SDL_FALSE); } -static SDL_Cursor* -Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) +static const char* +Emscripten_GetCursorUrl(int w, int h, int hot_x, int hot_y, void* pixels) { - const char *cursor_url = NULL; - SDL_Surface *conv_surf; - - conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); - - if (!conv_surf) { - return NULL; - } - - cursor_url = (const char *)EM_ASM_INT({ + return (const char *)EM_ASM_INT({ var w = $0; var h = $1; var hot_x = $2; @@ -122,7 +114,40 @@ Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) stringToUTF8(url, urlBuf, url.length + 1); return urlBuf; - }, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels); + }, w, h, hot_x, hot_y, pixels); +} + +static SDL_Cursor* +Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y) +{ + const char *cursor_url = NULL; + SDL_Surface *conv_surf; + + conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0); + + if (!conv_surf) { + return NULL; + } + + if (emscripten_is_main_runtime_thread()) { + cursor_url = Emscripten_GetCursorUrl( + surface->w, + surface->h, + hot_x, + hot_y, + conv_surf->pixels + ); + } else { + cursor_url = (const char *)emscripten_sync_run_in_main_runtime_thread( + EM_FUNC_SIG_IIIIIII, + Emscripten_GetCursorUrl, + surface->w, + surface->h, + hot_x, + hot_y, + conv_surf->pixels + ); + } SDL_FreeSurface(conv_surf); @@ -206,16 +231,15 @@ Emscripten_ShowCursor(SDL_Cursor* cursor) curdata = (Emscripten_CursorData *) cursor->driverdata; if(curdata->system_cursor) { - EM_ASM_INT({ + MAIN_THREAD_EM_ASM({ if (Module['canvas']) { Module['canvas'].style['cursor'] = UTF8ToString($0); } - return 0; }, curdata->system_cursor); } } else { - EM_ASM( + MAIN_THREAD_EM_ASM( if (Module['canvas']) { Module['canvas'].style['cursor'] = 'none'; } diff --git a/src/video/emscripten/SDL_emscriptenvideo.c b/src/video/emscripten/SDL_emscriptenvideo.c index 8f4227667..4c6038f09 100644 --- a/src/video/emscripten/SDL_emscriptenvideo.c +++ b/src/video/emscripten/SDL_emscriptenvideo.c @@ -43,6 +43,7 @@ static int Emscripten_VideoInit(_THIS); static int Emscripten_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); static void Emscripten_VideoQuit(_THIS); static int Emscripten_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); +static int Emscripten_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, float * vdpi); static int Emscripten_CreateWindow(_THIS, SDL_Window * window); static void Emscripten_SetWindowSize(_THIS, SDL_Window * window); @@ -82,6 +83,7 @@ Emscripten_CreateDevice(int devindex) device->VideoInit = Emscripten_VideoInit; device->VideoQuit = Emscripten_VideoQuit; device->GetDisplayUsableBounds = Emscripten_GetDisplayUsableBounds; + device->GetDisplayDPI = Emscripten_GetDisplayDPI; device->SetDisplayMode = Emscripten_SetDisplayMode; @@ -172,16 +174,37 @@ Emscripten_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * if (rect) { rect->x = 0; rect->y = 0; - rect->w = EM_ASM_INT_V({ + rect->w = MAIN_THREAD_EM_ASM_INT({ return window.innerWidth; }); - rect->h = EM_ASM_INT_V({ + rect->h = MAIN_THREAD_EM_ASM_INT({ return window.innerHeight; }); } return 0; } +static int +Emscripten_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi_out, float * hdpi_out, float * vdpi_out) +{ + const float dpi_reference = 96.0f; + float dpi; + + dpi = (float)emscripten_get_device_pixel_ratio() * dpi_reference; + + if (ddpi_out) { + *ddpi_out = dpi; + } + if (hdpi_out) { + *hdpi_out = dpi; + } + if (vdpi_out) { + *vdpi_out = dpi; + } + + return 0; +} + static void Emscripten_PumpEvents(_THIS) { diff --git a/src/video/haiku/SDL_BApp.h b/src/video/haiku/SDL_BApp.h new file mode 100644 index 000000000..215f83662 --- /dev/null +++ b/src/video/haiku/SDL_BApp.h @@ -0,0 +1,431 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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_BAPP_H +#define SDL_BAPP_H + +#include +#include +#include +#if SDL_VIDEO_OPENGL +#include +#endif + +#include "../../video/haiku/SDL_bkeyboard.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../SDL_internal.h" + +#include "SDL_video.h" + +/* Local includes */ +#include "../../events/SDL_events_c.h" +#include "../../video/haiku/SDL_bframebuffer.h" + +#ifdef __cplusplus +} +#endif + +#include + + + + +/* Forward declarations */ +class SDL_BWin; + +/* Message constants */ +enum ToSDL { + /* Intercepted by BWindow on its way to BView */ + BAPP_MOUSE_MOVED, + BAPP_MOUSE_BUTTON, + BAPP_MOUSE_WHEEL, + BAPP_KEY, + BAPP_REPAINT, /* from _UPDATE_ */ + /* From BWindow */ + BAPP_MAXIMIZE, /* from B_ZOOM */ + BAPP_MINIMIZE, + BAPP_RESTORE, /* TODO: IMPLEMENT! */ + BAPP_SHOW, + BAPP_HIDE, + BAPP_MOUSE_FOCUS, /* caused by MOUSE_MOVE */ + BAPP_KEYBOARD_FOCUS, /* from WINDOW_ACTIVATED */ + BAPP_WINDOW_CLOSE_REQUESTED, + BAPP_WINDOW_MOVED, + BAPP_WINDOW_RESIZED, + BAPP_SCREEN_CHANGED +}; + + + +/* Create a descendant of BApplication */ +class SDL_BApp : public BApplication { +public: + SDL_BApp(const char* signature) : + BApplication(signature) { +#if SDL_VIDEO_OPENGL + _current_context = NULL; +#endif + } + + + virtual ~SDL_BApp() { + } + + + virtual void RefsReceived(BMessage* message) { + char filePath[512]; + entry_ref entryRef; + for (int32 i = 0; message->FindRef("refs", i, &entryRef) == B_OK; i++) { + BPath referencePath = BPath(&entryRef); + SDL_SendDropFile(NULL, referencePath.Path()); + } + return; + } + + /* Event-handling functions */ + virtual void MessageReceived(BMessage* message) { + /* Sort out SDL-related messages */ + switch ( message->what ) { + case BAPP_MOUSE_MOVED: + _HandleMouseMove(message); + break; + + case BAPP_MOUSE_BUTTON: + _HandleMouseButton(message); + break; + + case BAPP_MOUSE_WHEEL: + _HandleMouseWheel(message); + break; + + case BAPP_KEY: + _HandleKey(message); + break; + + case BAPP_REPAINT: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_EXPOSED); + break; + + case BAPP_MAXIMIZE: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_MAXIMIZED); + break; + + case BAPP_MINIMIZE: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_MINIMIZED); + break; + + case BAPP_SHOW: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_SHOWN); + break; + + case BAPP_HIDE: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_HIDDEN); + break; + + case BAPP_MOUSE_FOCUS: + _HandleMouseFocus(message); + break; + + case BAPP_KEYBOARD_FOCUS: + _HandleKeyboardFocus(message); + break; + + case BAPP_WINDOW_CLOSE_REQUESTED: + _HandleBasicWindowEvent(message, SDL_WINDOWEVENT_CLOSE); + break; + + case BAPP_WINDOW_MOVED: + _HandleWindowMoved(message); + break; + + case BAPP_WINDOW_RESIZED: + _HandleWindowResized(message); + break; + + case B_LOCALE_CHANGED: + SDL_SendLocaleChangedEvent(); + break; + + case BAPP_SCREEN_CHANGED: + /* TODO: Handle screen resize or workspace change */ + break; + + default: + BApplication::MessageReceived(message); + break; + } + } + + /* Window creation/destruction methods */ + int32 GetID(SDL_Window *win) { + int32 i; + for(i = 0; i < _GetNumWindowSlots(); ++i) { + if( GetSDLWindow(i) == NULL ) { + _SetSDLWindow(win, i); + return i; + } + } + + /* Expand the vector if all slots are full */ + if( i == _GetNumWindowSlots() ) { + _PushBackWindow(win); + return i; + } + + /* TODO: error handling */ + return 0; + } + + /* FIXME: Bad coding practice, but I can't include SDL_BWin.h here. Is + there another way to do this? */ + void ClearID(SDL_BWin *bwin); /* Defined in SDL_BeApp.cc */ + + + SDL_Window *GetSDLWindow(int32 winID) { + return _window_map[winID]; + } + +#if SDL_VIDEO_OPENGL + BGLView *GetCurrentContext() { + return _current_context; + } + + void SetCurrentContext(BGLView *newContext) { + if(_current_context) + _current_context->UnlockGL(); + _current_context = newContext; + if (_current_context) + _current_context->LockGL(); + } +#endif + +private: + /* Event management */ + void _HandleBasicWindowEvent(BMessage *msg, int32 sdlEventType) { + SDL_Window *win; + int32 winID; + if( + !_GetWinID(msg, &winID) + ) { + return; + } + win = GetSDLWindow(winID); + SDL_SendWindowEvent(win, sdlEventType, 0, 0); + } + + void _HandleMouseMove(BMessage *msg) { + SDL_Window *win; + int32 winID; + int32 x = 0, y = 0; + if( + !_GetWinID(msg, &winID) || + msg->FindInt32("x", &x) != B_OK || /* x movement */ + msg->FindInt32("y", &y) != B_OK /* y movement */ + ) { + return; + } + win = GetSDLWindow(winID); + + // Simple relative mode support for mouse. + if (SDL_GetMouse()->relative_mode) { + int winWidth, winHeight, winPosX, winPosY; + SDL_GetWindowSize(win, &winWidth, &winHeight); + SDL_GetWindowPosition(win, &winPosX, &winPosY); + int dx = x - (winWidth / 2); + int dy = y - (winHeight / 2); + SDL_SendMouseMotion(win, 0, SDL_GetMouse()->relative_mode, dx, dy); + set_mouse_position((winPosX + winWidth / 2), (winPosY + winHeight / 2)); + if (!be_app->IsCursorHidden()) + be_app->HideCursor(); + } else { + SDL_SendMouseMotion(win, 0, 0, x, y); + if (SDL_ShowCursor(-1) && be_app->IsCursorHidden()) + be_app->ShowCursor(); + } + } + + void _HandleMouseButton(BMessage *msg) { + SDL_Window *win; + int32 winID; + int32 button, state; /* left/middle/right, pressed/released */ + if( + !_GetWinID(msg, &winID) || + msg->FindInt32("button-id", &button) != B_OK || + msg->FindInt32("button-state", &state) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + SDL_SendMouseButton(win, 0, state, button); + } + + void _HandleMouseWheel(BMessage *msg) { + SDL_Window *win; + int32 winID; + int32 xTicks, yTicks; + if( + !_GetWinID(msg, &winID) || + msg->FindInt32("xticks", &xTicks) != B_OK || + msg->FindInt32("yticks", &yTicks) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + SDL_SendMouseWheel(win, 0, xTicks, -yTicks, SDL_MOUSEWHEEL_NORMAL); + } + + void _HandleKey(BMessage *msg) { + int32 scancode, state; /* scancode, pressed/released */ + if( + msg->FindInt32("key-state", &state) != B_OK || + msg->FindInt32("key-scancode", &scancode) != B_OK + ) { + return; + } + + /* Make sure this isn't a repeated event (key pressed and held) */ + if(state == SDL_PRESSED && HAIKU_GetKeyState(scancode) == SDL_PRESSED) { + return; + } + HAIKU_SetKeyState(scancode, state); + SDL_SendKeyboardKey(state, HAIKU_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_zeroa(text); + SDL_memcpy(text, keyUtf8, count); + SDL_SendKeyboardText(text); + } + } + } + + void _HandleMouseFocus(BMessage *msg) { + SDL_Window *win; + int32 winID; + bool bSetFocus; /* If false, lose focus */ + if( + !_GetWinID(msg, &winID) || + msg->FindBool("focusGained", &bSetFocus) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + if(bSetFocus) { + SDL_SetMouseFocus(win); + } else if(SDL_GetMouseFocus() == win) { + /* Only lose all focus if this window was the current focus */ + SDL_SetMouseFocus(NULL); + } + } + + void _HandleKeyboardFocus(BMessage *msg) { + SDL_Window *win; + int32 winID; + bool bSetFocus; /* If false, lose focus */ + if( + !_GetWinID(msg, &winID) || + msg->FindBool("focusGained", &bSetFocus) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + if(bSetFocus) { + SDL_SetKeyboardFocus(win); + } else if(SDL_GetKeyboardFocus() == win) { + /* Only lose all focus if this window was the current focus */ + SDL_SetKeyboardFocus(NULL); + } + } + + void _HandleWindowMoved(BMessage *msg) { + SDL_Window *win; + int32 winID; + int32 xPos, yPos; + /* Get the window id and new x/y position of the window */ + if( + !_GetWinID(msg, &winID) || + msg->FindInt32("window-x", &xPos) != B_OK || + msg->FindInt32("window-y", &yPos) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + SDL_SendWindowEvent(win, SDL_WINDOWEVENT_MOVED, xPos, yPos); + } + + void _HandleWindowResized(BMessage *msg) { + SDL_Window *win; + int32 winID; + int32 w, h; + /* Get the window id ]and new x/y position of the window */ + if( + !_GetWinID(msg, &winID) || + msg->FindInt32("window-w", &w) != B_OK || + msg->FindInt32("window-h", &h) != B_OK + ) { + return; + } + win = GetSDLWindow(winID); + SDL_SendWindowEvent(win, SDL_WINDOWEVENT_RESIZED, w, h); + } + + bool _GetWinID(BMessage *msg, int32 *winID) { + return msg->FindInt32("window-id", winID) == B_OK; + } + + + + /* Vector functions: Wraps vector stuff in case we need to change + implementation */ + void _SetSDLWindow(SDL_Window *win, int32 winID) { + _window_map[winID] = win; + } + + int32 _GetNumWindowSlots() { + return _window_map.size(); + } + + + void _PopBackWindow() { + _window_map.pop_back(); + } + + void _PushBackWindow(SDL_Window *win) { + _window_map.push_back(win); + } + + + /* Members */ + std::vector _window_map; /* Keeps track of SDL_Windows by index-id */ + +#if SDL_VIDEO_OPENGL + BGLView *_current_context; +#endif +}; + +#endif diff --git a/src/video/haiku/SDL_BWin.h b/src/video/haiku/SDL_BWin.h index dc6e442a8..1ac517164 100644 --- a/src/video/haiku/SDL_BWin.h +++ b/src/video/haiku/SDL_BWin.h @@ -39,7 +39,6 @@ extern "C" { #include #include #include -#include #if SDL_VIDEO_OPENGL #include #endif @@ -58,19 +57,48 @@ enum WinCommands { BWIN_SET_TITLE, BWIN_SET_BORDERED, BWIN_SET_RESIZABLE, - BWIN_FULLSCREEN + BWIN_FULLSCREEN, + BWIN_UPDATE_FRAMEBUFFER, + BWIN_MINIMUM_SIZE_WINDOW }; +// non-OpenGL framebuffer view +class SDL_BView: public BView +{ +public: + SDL_BView(BRect frame, const char* name, uint32 resizingMode) + : BView(frame, name, resizingMode, B_WILL_DRAW), + fBitmap(NULL) + { + } + + void Draw(BRect dirty) + { + if (fBitmap != NULL) + DrawBitmap(fBitmap, B_ORIGIN); + } + + void SetBitmap(BBitmap *bitmap) + { + fBitmap = bitmap; + } + +private: + BBitmap *fBitmap; +}; -class SDL_BWin:public BDirectWindow +class SDL_BWin: public BWindow { public: /* Constructor/Destructor */ SDL_BWin(BRect bounds, window_look look, uint32 flags) - : BDirectWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags) + : BWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags) { _last_buttons = 0; + _cur_view = NULL; + _SDL_View = NULL; + #if SDL_VIDEO_OPENGL _SDL_GLView = NULL; _gl_type = 0; @@ -79,59 +107,88 @@ class SDL_BWin:public BDirectWindow _inhibit_resize = false; _mouse_focused = false; _prev_frame = NULL; + _fullscreen = NULL; /* Handle framebuffer stuff */ - _connected = _connection_disabled = false; - _buffer_created = _buffer_dirty = false; - _trash_window_buffer = false; _buffer_locker = new BLocker(); _bitmap = NULL; - _clips = NULL; - _num_clips = 0; - -#ifdef DRAWTHREAD - _draw_thread_id = spawn_thread(HAIKU_DrawThread, "drawing_thread", - B_NORMAL_PRIORITY, (void*) this); - resume_thread(_draw_thread_id); -#endif } virtual ~ SDL_BWin() { Lock(); - _connection_disabled = true; - int32 result; + + if (_SDL_View != NULL && _SDL_View != _cur_view) { + delete _SDL_View; + _SDL_View = NULL; + } #if SDL_VIDEO_OPENGL if (_SDL_GLView) { - _SDL_GLView->UnlockGL(); - RemoveChild(_SDL_GLView); /* Why was this outside the if - statement before? */ + if (((SDL_BApp*)be_app)->GetCurrentContext() == _SDL_GLView) + ((SDL_BApp*)be_app)->SetCurrentContext(NULL); + if (_SDL_GLView == _cur_view) + RemoveChild(_SDL_GLView); + _SDL_GLView = NULL; + // _SDL_GLView deleted by HAIKU_GL_DeleteContext } #endif Unlock(); -#if SDL_VIDEO_OPENGL - if (_SDL_GLView) { - delete _SDL_GLView; - } -#endif delete _prev_frame; /* Clean up framebuffer stuff */ _buffer_locker->Lock(); -#ifdef DRAWTHREAD - wait_for_thread(_draw_thread_id, &result); -#endif - SDL_free(_clips); delete _buffer_locker; } + + void SetCurrentView(BView *view) + { + if (_cur_view != view) { + if (_cur_view != NULL) + RemoveChild(_cur_view); + _cur_view = view; + if (_cur_view != NULL) + AddChild(_cur_view); + } + } + + void UpdateCurrentView() + { + if (_SDL_GLView != NULL) { + SetCurrentView(_SDL_GLView); + } else if (_SDL_View != NULL) { + SetCurrentView(_SDL_View); + } else { + SetCurrentView(NULL); + } + } + SDL_BView *CreateView() { + Lock(); + if (_SDL_View == NULL) { + _SDL_View = new SDL_BView(Bounds(), "SDL View", B_FOLLOW_ALL_SIDES); + UpdateCurrentView(); + } + Unlock(); + return _SDL_View; + } + + void RemoveView() { + Lock(); + if(_SDL_View != NULL) { + SDL_BView *oldView = _SDL_View; + _SDL_View = NULL; + UpdateCurrentView(); + delete oldView; + } + Unlock(); + } /* * * * * OpenGL functionality * * * * */ #if SDL_VIDEO_OPENGL - virtual BGLView *CreateGLView(Uint32 gl_flags) { + BGLView *CreateGLView(Uint32 gl_flags) { Lock(); if (_SDL_GLView == NULL) { _SDL_GLView = new BGLView(Bounds(), "SDL GLView", @@ -139,92 +196,29 @@ class SDL_BWin:public BDirectWindow (B_WILL_DRAW | B_FRAME_EVENTS), gl_flags); _gl_type = gl_flags; + UpdateCurrentView(); } - AddChild(_SDL_GLView); - _SDL_GLView->EnableDirectMode(false); /* Disable direct mode */ - _SDL_GLView->LockGL(); /* "New" GLViews are created */ Unlock(); - return (_SDL_GLView); + return _SDL_GLView; } - virtual void RemoveGLView() { + void RemoveGLView() { Lock(); - if(_SDL_GLView) { - _SDL_GLView->UnlockGL(); - RemoveChild(_SDL_GLView); + if(_SDL_GLView != NULL) { + if (((SDL_BApp*)be_app)->GetCurrentContext() == _SDL_GLView) + ((SDL_BApp*)be_app)->SetCurrentContext(NULL); + _SDL_GLView = NULL; + UpdateCurrentView(); + // _SDL_GLView deleted by HAIKU_GL_DeleteContext } Unlock(); } - virtual void SwapBuffers(void) { - _SDL_GLView->UnlockGL(); - _SDL_GLView->LockGL(); + void SwapBuffers(void) { _SDL_GLView->SwapBuffers(); } #endif - /* * * * * Framebuffering* * * * */ - virtual void DirectConnected(direct_buffer_info *info) { - if(!_connected && _connection_disabled) { - return; - } - - /* Determine if the pixel buffer is usable after this update */ - _trash_window_buffer = _trash_window_buffer - || ((info->buffer_state & B_BUFFER_RESIZED) - || (info->buffer_state & B_BUFFER_RESET) - || (info->driver_state == B_MODE_CHANGED)); - LockBuffer(); - - switch(info->buffer_state & B_DIRECT_MODE_MASK) { - case B_DIRECT_START: - _connected = true; - - case B_DIRECT_MODIFY: - if (info->clip_list_count > _num_clips) - { - if(_clips) { - SDL_free(_clips); - _clips = NULL; - } - } - - _num_clips = info->clip_list_count; - if (_clips == NULL) - _clips = (clipping_rect *)SDL_malloc(_num_clips*sizeof(clipping_rect)); - if(_clips) { - SDL_memcpy(_clips, info->clip_list, - _num_clips*sizeof(clipping_rect)); - - _bits = (uint8*) info->bits; - _row_bytes = info->bytes_per_row; - _bounds = info->window_bounds; - _bytes_per_px = info->bits_per_pixel / 8; - _buffer_dirty = true; - } - break; - - case B_DIRECT_STOP: - _connected = false; - break; - } -#if SDL_VIDEO_OPENGL - if(_SDL_GLView) { - _SDL_GLView->DirectConnected(info); - } -#endif - - - /* Call the base object directconnected */ - BDirectWindow::DirectConnected(info); - - UnlockBuffer(); - - } - - - - /* * * * * Event sending * * * * */ /* Hook functions */ virtual void FrameMoved(BPoint origin) { @@ -235,10 +229,10 @@ class SDL_BWin:public BDirectWindow _PostWindowEvent(msg); /* Perform normal hook operations */ - BDirectWindow::FrameMoved(origin); + BWindow::FrameMoved(origin); } - virtual void FrameResized(float width, float height) { + void FrameResized(float width, float height) { /* Post a message to the BApp so that it can handle the window event */ BMessage msg(BAPP_WINDOW_RESIZED); @@ -247,10 +241,10 @@ class SDL_BWin:public BDirectWindow _PostWindowEvent(msg); /* Perform normal hook operations */ - BDirectWindow::FrameResized(width, height); + BWindow::FrameResized(width, height); } - virtual bool QuitRequested() { + bool QuitRequested() { BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED); _PostWindowEvent(msg); @@ -258,13 +252,13 @@ class SDL_BWin:public BDirectWindow return false; } - virtual void WindowActivated(bool active) { + void WindowActivated(bool active) { BMessage msg(BAPP_KEYBOARD_FOCUS); /* Mouse focus sold separately */ msg.AddBool("focusGained", active); _PostWindowEvent(msg); } - virtual void Zoom(BPoint origin, + void Zoom(BPoint origin, float width, float height) { BMessage msg(BAPP_MAXIMIZE); /* Closest thing to maximization Haiku has */ @@ -275,13 +269,13 @@ class SDL_BWin:public BDirectWindow _prev_frame = new BRect(Frame()); /* Perform normal hook operations */ - BDirectWindow::Zoom(origin, width, height); + BWindow::Zoom(origin, width, height); } /* Member functions */ - virtual void Show() { + void Show() { while(IsHidden()) { - BDirectWindow::Show(); + BWindow::Show(); } _shown = true; @@ -289,25 +283,33 @@ class SDL_BWin:public BDirectWindow _PostWindowEvent(msg); } - virtual void Hide() { - BDirectWindow::Hide(); + void Hide() { + BWindow::Hide(); _shown = false; BMessage msg(BAPP_HIDE); _PostWindowEvent(msg); } - virtual void Minimize(bool minimize) { - BDirectWindow::Minimize(minimize); + void Minimize(bool minimize) { + BWindow::Minimize(minimize); int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE); BMessage msg(minState); _PostWindowEvent(msg); } + void ScreenChanged(BRect screenFrame, color_space depth) + { + if (_fullscreen) { + MoveTo(screenFrame.left, screenFrame.top); + ResizeTo(screenFrame.Width(), screenFrame.Height()); + } + } + /* BView message interruption */ - virtual void DispatchMessage(BMessage * msg, BHandler * target) + void DispatchMessage(BMessage * msg, BHandler * target) { BPoint where; /* Used by mouse moved */ int32 buttons; /* Used for mouse button events */ @@ -356,7 +358,7 @@ class SDL_BWin:public BDirectWindow } } break; - + case B_UNMAPPED_KEY_DOWN: /* modifier keys are unmapped */ if (msg->FindInt32("key", &key) == B_OK) { _KeyEvent((SDL_Scancode)key, NULL, 0, SDL_PRESSED); @@ -376,15 +378,15 @@ class SDL_BWin:public BDirectWindow - CTRL+Q to close window (and other shortcuts) - PrintScreen to make screenshot into /boot/home - etc.. */ - /* BDirectWindow::DispatchMessage(msg, target); */ + /* BWindow::DispatchMessage(msg, target); */ break; } - BDirectWindow::DispatchMessage(msg, target); + BWindow::DispatchMessage(msg, target); } /* Handle command messages */ - virtual void MessageReceived(BMessage* message) { + void MessageReceived(BMessage* message) { switch (message->what) { /* Handle commands from SDL */ case BWIN_SET_TITLE: @@ -396,12 +398,18 @@ class SDL_BWin:public BDirectWindow case BWIN_RESIZE_WINDOW: _ResizeTo(message); break; - case BWIN_SET_BORDERED: - _SetBordered(message); + case BWIN_SET_BORDERED: { + bool bEnabled; + if (message->FindBool("window-border", &bEnabled) == B_OK) + _SetBordered(bEnabled); break; - case BWIN_SET_RESIZABLE: - _SetResizable(message); + } + case BWIN_SET_RESIZABLE: { + bool bEnabled; + if (message->FindBool("window-resizable", &bEnabled) == B_OK) + _SetResizable(bEnabled); break; + } case BWIN_SHOW_WINDOW: Show(); break; @@ -417,12 +425,34 @@ class SDL_BWin:public BDirectWindow case BWIN_RESTORE_WINDOW: _Restore(); break; - case BWIN_FULLSCREEN: - _SetFullScreen(message); + case BWIN_FULLSCREEN: { + bool fullscreen; + if (message->FindBool("fullscreen", &fullscreen) == B_OK) + _SetFullScreen(fullscreen); + break; + } + case BWIN_MINIMUM_SIZE_WINDOW: + _SetMinimumSize(message); break; + case BWIN_UPDATE_FRAMEBUFFER: { + BMessage* pendingMessage; + while ((pendingMessage + = MessageQueue()->FindMessage(BWIN_UPDATE_FRAMEBUFFER, 0))) { + MessageQueue()->RemoveMessage(pendingMessage); + delete pendingMessage; + } + if (_bitmap != NULL) { + if (_SDL_View != NULL && _cur_view == _SDL_View) + _SDL_View->Draw(Bounds()); + else if (_SDL_GLView != NULL && _cur_view == _SDL_GLView) { + _SDL_GLView->CopyPixelsIn(_bitmap, B_ORIGIN); + } + } + break; + } default: /* Perform normal message handling */ - BDirectWindow::MessageReceived(message); + BWindow::MessageReceived(message); break; } @@ -433,19 +463,9 @@ class SDL_BWin:public BDirectWindow /* Accessor methods */ bool IsShown() { return _shown; } int32 GetID() { return _id; } - uint32 GetRowBytes() { return _row_bytes; } - int32 GetFbX() { return _bounds.left; } - int32 GetFbY() { return _bounds.top; } - bool ConnectionEnabled() { return !_connection_disabled; } - bool Connected() { return _connected; } - clipping_rect *GetClips() { return _clips; } - int32 GetNumClips() { return _num_clips; } - uint8* GetBufferPx() { return _bits; } - int32 GetBytesPerPx() { return _bytes_per_px; } - bool CanTrashWindowBuffer() { return _trash_window_buffer; } - bool BufferExists() { return _buffer_created; } - bool BufferIsDirty() { return _buffer_dirty; } BBitmap *GetBitmap() { return _bitmap; } + BView *GetCurView() { return _cur_view; } + SDL_BView *GetView() { return _SDL_View; } #if SDL_VIDEO_OPENGL BGLView *GetGLView() { return _SDL_GLView; } Uint32 GetGLType() { return _gl_type; } @@ -453,12 +473,9 @@ class SDL_BWin:public BDirectWindow /* Setter methods */ void SetID(int32 id) { _id = id; } - void SetBufferExists(bool bufferExists) { _buffer_created = bufferExists; } void LockBuffer() { _buffer_locker->Lock(); } void UnlockBuffer() { _buffer_locker->Unlock(); } - void SetBufferDirty(bool bufferDirty) { _buffer_dirty = bufferDirty; } - void SetTrashBuffer(bool trash) { _trash_window_buffer = trash; } - void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; } + void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; if (_SDL_View != NULL) _SDL_View->SetBitmap(bitmap); } private: @@ -564,7 +581,10 @@ class SDL_BWin:public BDirectWindow ) { return; } - MoveTo(x, y); + if (_fullscreen) + _non_fullscreen_frame.OffsetTo(x, y); + else + MoveTo(x, y); } void _ResizeTo(BMessage *msg) { @@ -575,27 +595,48 @@ class SDL_BWin:public BDirectWindow ) { return; } - ResizeTo(w, h); + if (_fullscreen) { + _non_fullscreen_frame.right = _non_fullscreen_frame.left + w; + _non_fullscreen_frame.bottom = _non_fullscreen_frame.top + h; + } else + ResizeTo(w, h); } - void _SetBordered(BMessage *msg) { - bool bEnabled; - if(msg->FindBool("window-border", &bEnabled) != B_OK) { - return; + void _SetBordered(bool bEnabled) { + if (_fullscreen) + _bordered = bEnabled; + else + SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK); + } + + void _SetResizable(bool bEnabled) { + if (_fullscreen) + _resizable = bEnabled; + else { + if (bEnabled) { + SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); + } else { + SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); + } } - SetLook(bEnabled ? B_TITLED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK); } - void _SetResizable(BMessage *msg) { - bool bEnabled; - if(msg->FindBool("window-resizable", &bEnabled) != B_OK) { + void _SetMinimumSize(BMessage *msg) { + float maxHeight; + float maxWidth; + float _; + int32 minHeight; + int32 minWidth; + + // This is a bit convoluted, we only want to set the minimum not the maximum + // But there is no direct call to do that, so store the maximum size beforehand + GetSizeLimits(&_, &maxWidth, &_, &maxHeight); + if (msg->FindInt32("window-w", &minWidth) != B_OK) return; - } - if (bEnabled) { - SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); - } else { - SetFlags(Flags() | (B_NOT_RESIZABLE | B_NOT_ZOOMABLE)); - } + if (msg->FindInt32("window-h", &minHeight) != B_OK) + return; + SetSizeLimits((float)minWidth, maxWidth, (float)minHeight, maxHeight); + UpdateSizeLimits(); } void _Restore() { @@ -603,23 +644,42 @@ class SDL_BWin:public BDirectWindow Minimize(false); } else if(IsHidden()) { Show(); + } else if (_fullscreen) { + } else if(_prev_frame != NULL) { /* Zoomed */ MoveTo(_prev_frame->left, _prev_frame->top); ResizeTo(_prev_frame->Width(), _prev_frame->Height()); } } - void _SetFullScreen(BMessage *msg) { - bool fullscreen; - if( - msg->FindBool("fullscreen", &fullscreen) != B_OK - ) { - return; + void _SetFullScreen(bool fullscreen) { + if (fullscreen != _fullscreen) { + if (fullscreen) { + BScreen screen(this); + BRect screenFrame = screen.Frame(); + printf("screen frame: "); screenFrame.PrintToStream(); printf("\n"); + _bordered = Look() != B_NO_BORDER_WINDOW_LOOK; + _resizable = !(Flags() & B_NOT_RESIZABLE); + _non_fullscreen_frame = Frame(); + _SetBordered(false); + _SetResizable(false); + MoveTo(screenFrame.left, screenFrame.top); + ResizeTo(screenFrame.Width(), screenFrame.Height()); + _fullscreen = fullscreen; + } else { + _fullscreen = fullscreen; + MoveTo(_non_fullscreen_frame.left, _non_fullscreen_frame.top); + ResizeTo(_non_fullscreen_frame.Width(), _non_fullscreen_frame.Height()); + _SetBordered(_bordered); + _SetResizable(_resizable); + } } - SetFullScreen(fullscreen); } /* Members */ + + BView* _cur_view; + SDL_BView* _SDL_View; #if SDL_VIDEO_OPENGL BGLView * _SDL_GLView; Uint32 _gl_type; @@ -632,23 +692,15 @@ class SDL_BWin:public BDirectWindow bool _inhibit_resize; BRect *_prev_frame; /* Previous position and size of the window */ + bool _fullscreen; + // valid only if fullscreen + BRect _non_fullscreen_frame; + bool _bordered; + bool _resizable; /* Framebuffer members */ - bool _connected, - _connection_disabled, - _buffer_created, - _buffer_dirty, - _trash_window_buffer; - uint8 *_bits; - uint32 _row_bytes; - clipping_rect _bounds; - BLocker *_buffer_locker; - clipping_rect *_clips; - uint32 _num_clips; - int32 _bytes_per_px; - thread_id _draw_thread_id; - - BBitmap *_bitmap; + BLocker *_buffer_locker; + BBitmap *_bitmap; }; diff --git a/src/video/haiku/SDL_bframebuffer.cc b/src/video/haiku/SDL_bframebuffer.cc index c1017eb46..971231924 100644 --- a/src/video/haiku/SDL_bframebuffer.cc +++ b/src/video/haiku/SDL_bframebuffer.cc @@ -35,10 +35,6 @@ extern "C" { #endif -#ifndef DRAWTHREAD -static int32 HAIKU_UpdateOnce(SDL_Window *window); -#endif - static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) { return ((SDL_BWin*)(window->driverdata)); } @@ -56,11 +52,11 @@ int HAIKU_CreateWindowFramebuffer(_THIS, SDL_Window * window, return -1; } - while(!bwin->Connected()) { snooze(100); } - /* Make sure we have exclusive access to frame buffer data */ bwin->LockBuffer(); + bwin->CreateView(); + /* format */ display_mode bmode; bscreen.GetMode(&bmode); @@ -76,7 +72,7 @@ int HAIKU_CreateWindowFramebuffer(_THIS, SDL_Window * window, bitmap = new BBitmap(bwin->Bounds(), (color_space)bmode.space, false, /* Views not accepted */ true); /* Contiguous memory required */ - + if(bitmap->InitCheck() != B_OK) { delete bitmap; return SDL_SetError("Could not initialize back buffer!"); @@ -84,15 +80,13 @@ int HAIKU_CreateWindowFramebuffer(_THIS, SDL_Window * window, bwin->SetBitmap(bitmap); - + /* Set the pixel pointer */ *pixels = bitmap->Bits(); /* pitch = width of window, in bytes */ *pitch = bitmap->BytesPerRow(); - bwin->SetBufferExists(true); - bwin->SetTrashBuffer(false); bwin->UnlockBuffer(); return 0; } @@ -106,149 +100,25 @@ int HAIKU_UpdateWindowFramebuffer(_THIS, SDL_Window * window, SDL_BWin *bwin = _ToBeWin(window); -#ifdef DRAWTHREAD - bwin->LockBuffer(); - bwin->SetBufferDirty(true); - bwin->UnlockBuffer(); -#else - bwin->SetBufferDirty(true); - HAIKU_UpdateOnce(window); -#endif + bwin->PostMessage(BWIN_UPDATE_FRAMEBUFFER); return 0; } -int32 HAIKU_DrawThread(void *data) { - SDL_BWin *bwin = (SDL_BWin*)data; - - BScreen bscreen; - if(!bscreen.IsValid()) { - return -1; - } - - while(bwin->ConnectionEnabled()) { - if( bwin->Connected() && bwin->BufferExists() && bwin->BufferIsDirty() ) { - bwin->LockBuffer(); - BBitmap *bitmap = NULL; - bitmap = bwin->GetBitmap(); - int32 windowPitch = bitmap->BytesPerRow(); - int32 bufferPitch = bwin->GetRowBytes(); - uint8 *windowpx; - uint8 *bufferpx; - - int32 BPP = bwin->GetBytesPerPx(); - int32 windowSub = bwin->GetFbX() * BPP + - bwin->GetFbY() * windowPitch; - clipping_rect *clips = bwin->GetClips(); - int32 numClips = bwin->GetNumClips(); - int i, y; - - /* Blit each clipping rectangle */ - bscreen.WaitForRetrace(); - for(i = 0; i < numClips; ++i) { - /* Get addresses of the start of each clipping rectangle */ - int32 width = clips[i].right - clips[i].left + 1; - int32 height = clips[i].bottom - clips[i].top + 1; - bufferpx = bwin->GetBufferPx() + - clips[i].top * bufferPitch + clips[i].left * BPP; - windowpx = (uint8*)bitmap->Bits() + - clips[i].top * windowPitch + clips[i].left * BPP - - windowSub; - - /* Copy each row of pixels from the window buffer into the frame - buffer */ - for(y = 0; y < height; ++y) - { - - if(bwin->CanTrashWindowBuffer()) { - goto escape; /* Break out before the buffer is killed */ - } - - memcpy(bufferpx, windowpx, width * BPP); - bufferpx += bufferPitch; - windowpx += windowPitch; - } - } - - bwin->SetBufferDirty(false); -escape: - bwin->UnlockBuffer(); - } else { - snooze(16000); - } - } - - return B_OK; -} - void HAIKU_DestroyWindowFramebuffer(_THIS, SDL_Window * window) { SDL_BWin *bwin = _ToBeWin(window); - + bwin->LockBuffer(); - + /* Free and clear the window buffer */ BBitmap *bitmap = bwin->GetBitmap(); delete bitmap; bwin->SetBitmap(NULL); - bwin->SetBufferExists(false); - bwin->UnlockBuffer(); -} + bwin->RemoveView(); -/* - * TODO: - * This was written to test if certain errors were caused by threading issues. - * The specific issues have since become rare enough that they may have been - * solved, but I doubt it- they were pretty sporadic before now. - */ -#ifndef DRAWTHREAD -static int32 HAIKU_UpdateOnce(SDL_Window *window) { - SDL_BWin *bwin = _ToBeWin(window); - BScreen bscreen; - if(!bscreen.IsValid()) { - return -1; - } - - if(bwin->ConnectionEnabled() && bwin->Connected()) { - bwin->LockBuffer(); - int32 windowPitch = window->surface->pitch; - int32 bufferPitch = bwin->GetRowBytes(); - uint8 *windowpx; - uint8 *bufferpx; - - int32 BPP = bwin->GetBytesPerPx(); - uint8 *windowBaseAddress = (uint8*)window->surface->pixels; - int32 windowSub = bwin->GetFbX() * BPP + - bwin->GetFbY() * windowPitch; - clipping_rect *clips = bwin->GetClips(); - int32 numClips = bwin->GetNumClips(); - int i, y; - - /* Blit each clipping rectangle */ - bscreen.WaitForRetrace(); - for(i = 0; i < numClips; ++i) { - /* Get addresses of the start of each clipping rectangle */ - int32 width = clips[i].right - clips[i].left + 1; - int32 height = clips[i].bottom - clips[i].top + 1; - bufferpx = bwin->GetBufferPx() + - clips[i].top * bufferPitch + clips[i].left * BPP; - windowpx = windowBaseAddress + - clips[i].top * windowPitch + clips[i].left * BPP - windowSub; - - /* Copy each row of pixels from the window buffer into the frame - buffer */ - for(y = 0; y < height; ++y) - { - memcpy(bufferpx, windowpx, width * BPP); - bufferpx += bufferPitch; - windowpx += windowPitch; - } - } - bwin->UnlockBuffer(); - } - return 0; + bwin->UnlockBuffer(); } -#endif #ifdef __cplusplus } diff --git a/src/video/haiku/SDL_bopengl.cc b/src/video/haiku/SDL_bopengl.cc index e221177f4..0c7a704d8 100644 --- a/src/video/haiku/SDL_bopengl.cc +++ b/src/video/haiku/SDL_bopengl.cc @@ -84,16 +84,21 @@ void *HAIKU_GL_GetProcAddress(_THIS, const char *proc) } - - int HAIKU_GL_SwapWindow(_THIS, SDL_Window * window) { _ToBeWin(window)->SwapBuffers(); return 0; } int HAIKU_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) { - SDL_BWin* win = (SDL_BWin*)context; - _GetBeApp()->SetCurrentContext(win ? win->GetGLView() : NULL); + BGLView* glView = (BGLView*)context; + // printf("HAIKU_GL_MakeCurrent(%llx), win = %llx, thread = %d\n", (uint64)context, (uint64)window, find_thread(NULL)); + if (glView != NULL) { + if ((glView->Window() == NULL) || (window == NULL) || (_ToBeWin(window)->GetGLView() != glView)) { + SDL_SetError("MakeCurrent failed"); + return -1; + } + } + _GetBeApp()->SetCurrentContext(glView); return 0; } @@ -102,6 +107,11 @@ SDL_GLContext HAIKU_GL_CreateContext(_THIS, SDL_Window * window) { /* FIXME: Not sure what flags should be included here; may want to have most of them */ SDL_BWin *bwin = _ToBeWin(window); + // printf("HAIKU_GL_CreateContext, win = %llx, thread = %d\n", (uint64)window, find_thread(NULL)); + if (bwin->GetGLView() != NULL) { + SDL_SetError("Context already creaded"); + return NULL; + } Uint32 gl_flags = BGL_RGB; if (_this->gl_config.alpha_size) { gl_flags |= BGL_ALPHA; @@ -123,13 +133,25 @@ SDL_GLContext HAIKU_GL_CreateContext(_THIS, SDL_Window * window) { _this->gl_config.accum_alpha_size) { gl_flags |= BGL_ACCUM; } +#if __GNUC__ > 3 + if (_this->gl_config.share_with_current_context) { + gl_flags |= BGL_SHARE_CONTEXT; + } +#endif bwin->CreateGLView(gl_flags); - return (SDL_GLContext)(bwin); + _GetBeApp()->SetCurrentContext(bwin->GetGLView()); + return (SDL_GLContext)(bwin->GetGLView()); } void HAIKU_GL_DeleteContext(_THIS, SDL_GLContext context) { - /* Currently, automatically unlocks the view */ - ((SDL_BWin*)context)->RemoveGLView(); + // printf("HAIKU_GL_DeleteContext(%llx), thread = %d\n", (uint64)context, find_thread(NULL)); + BGLView* glView = (BGLView*)context; + SDL_BWin *bwin = (SDL_BWin*)glView->Window(); + if (bwin == NULL) { + delete glView; + } else { + bwin->RemoveGLView(); + } } diff --git a/src/video/haiku/SDL_bvideo.cc b/src/video/haiku/SDL_bvideo.cc index 77259f908..1ac3201f2 100644 --- a/src/video/haiku/SDL_bvideo.cc +++ b/src/video/haiku/SDL_bvideo.cc @@ -94,6 +94,7 @@ HAIKU_CreateDevice(int devindex) device->SetWindowGammaRamp = HAIKU_SetWindowGammaRamp; device->GetWindowGammaRamp = HAIKU_GetWindowGammaRamp; device->SetWindowMouseGrab = HAIKU_SetWindowMouseGrab; + device->SetWindowMinimumSize = HAIKU_SetWindowMinimumSize; device->DestroyWindow = HAIKU_DestroyWindow; device->GetWindowWMInfo = HAIKU_GetWindowWMInfo; device->CreateWindowFramebuffer = HAIKU_CreateWindowFramebuffer; @@ -190,6 +191,31 @@ HAIKU_FreeCursor(SDL_Cursor * cursor) SDL_free(cursor); } +static SDL_Cursor * +HAIKU_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) +{ + SDL_Cursor *cursor; + SDL_Surface *converted; + + converted = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0); + if (!converted) { + return NULL; + } + + BBitmap *cursorBitmap = new BBitmap(BRect(0, 0, surface->w - 1, surface->h - 1), B_RGBA32); + cursorBitmap->SetBits(converted->pixels, converted->h * converted->pitch, 0, B_RGBA32); + SDL_FreeSurface(converted); + + cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor)); + if (cursor) { + cursor->driverdata = (void *)new BCursor(cursorBitmap, BPoint(hot_x, hot_y)); + } else { + return NULL; + } + + return cursor; +} + static int HAIKU_ShowCursor(SDL_Cursor *cursor) { SDL_Mouse *mouse = SDL_GetMouse(); @@ -222,7 +248,7 @@ HAIKU_SetRelativeMouseMode(SDL_bool enabled) bewin->Lock(); if (enabled) - _SDL_GLView->SetEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS, B_NO_POINTER_HISTORY); + _SDL_GLView->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY); else _SDL_GLView->SetEventMask(0, 0); bewin->Unlock(); @@ -235,6 +261,7 @@ static void HAIKU_MouseInit(_THIS) SDL_Mouse *mouse = SDL_GetMouse(); if (!mouse) return; + mouse->CreateCursor = HAIKU_CreateCursor; mouse->CreateSystemCursor = HAIKU_CreateSystemCursor; mouse->ShowCursor = HAIKU_ShowCursor; mouse->FreeCursor = HAIKU_FreeCursor; diff --git a/src/video/haiku/SDL_bwindow.cc b/src/video/haiku/SDL_bwindow.cc index 57aba1741..587affad2 100644 --- a/src/video/haiku/SDL_bwindow.cc +++ b/src/video/haiku/SDL_bwindow.cc @@ -205,6 +205,13 @@ int HAIKU_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp) { } +void HAIKU_SetWindowMinimumSize(_THIS, SDL_Window * window){ + BMessage msg(BWIN_MINIMUM_SIZE_WINDOW); + msg.AddInt32("window-w", window->w -1); + msg.AddInt32("window-h", window->h -1); + _ToBeWin(window)->PostMessage(&msg); +} + void HAIKU_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { /* TODO: Implement this! */ } diff --git a/src/video/haiku/SDL_bwindow.h b/src/video/haiku/SDL_bwindow.h index 1d6a3c591..58a85d872 100644 --- a/src/video/haiku/SDL_bwindow.h +++ b/src/video/haiku/SDL_bwindow.h @@ -32,6 +32,7 @@ extern void HAIKU_SetWindowTitle(_THIS, SDL_Window * window); extern void HAIKU_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon); extern void HAIKU_SetWindowPosition(_THIS, SDL_Window * window); extern void HAIKU_SetWindowSize(_THIS, SDL_Window * window); +extern void HAIKU_SetWindowMinimumSize(_THIS, SDL_Window * window); extern void HAIKU_ShowWindow(_THIS, SDL_Window * window); extern void HAIKU_HideWindow(_THIS, SDL_Window * window); extern void HAIKU_RaiseWindow(_THIS, SDL_Window * window); diff --git a/src/video/nacl/SDL_naclwindow.c b/src/video/nacl/SDL_naclwindow.c index 255ac084b..f0245aef2 100644 --- a/src/video/nacl/SDL_naclwindow.c +++ b/src/video/nacl/SDL_naclwindow.c @@ -35,8 +35,7 @@ NACL_CreateWindow(_THIS, SDL_Window * window) SDL_VideoData *driverdata = (SDL_VideoData *) _this->driverdata; if (driverdata->window) { - SDL_SetError("NaCl only supports one window"); - return -1; + return SDL_SetError("NaCl only supports one window"); } driverdata->window = window; diff --git a/src/video/offscreen/SDL_offscreenframebuffer.c b/src/video/offscreen/SDL_offscreenframebuffer.c index 9b774896b..3ca57e897 100644 --- a/src/video/offscreen/SDL_offscreenframebuffer.c +++ b/src/video/offscreen/SDL_offscreenframebuffer.c @@ -34,17 +34,13 @@ int SDL_OFFSCREEN_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * f SDL_Surface *surface; const Uint32 surface_format = SDL_PIXELFORMAT_RGB888; int w, h; - int bpp; - Uint32 Rmask, Gmask, Bmask, Amask; /* Free the old framebuffer surface */ - surface = (SDL_Surface *) SDL_GetWindowData(window, OFFSCREEN_SURFACE); - SDL_FreeSurface(surface); + SDL_OFFSCREEN_DestroyWindowFramebuffer(_this, window); /* Create a new one */ - SDL_PixelFormatEnumToMasks(surface_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); SDL_GetWindowSize(window, &w, &h); - surface = SDL_CreateRGBSurface(0, w, h, bpp, Rmask, Gmask, Bmask, Amask); + surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, surface_format); if (!surface) { return -1; } diff --git a/src/video/os2/SDL_os2dive.c b/src/video/os2/SDL_os2dive.c index 52f1483b8..95aae6f05 100644 --- a/src/video/os2/SDL_os2dive.c +++ b/src/video/os2/SDL_os2dive.c @@ -67,10 +67,12 @@ OS2VIDEOOUTPUT voDive = { static BOOL voQueryInfo(VIDEOOUTPUTINFO *pInfo) { - DIVE_CAPS sDiveCaps = { 0 }; - FOURCC fccFormats[100] = { 0 }; + DIVE_CAPS sDiveCaps; + FOURCC fccFormats[100]; /* Query information about display hardware from DIVE. */ + SDL_zeroa(fccFormats); + SDL_zero(sDiveCaps); sDiveCaps.pFormatData = fccFormats; sDiveCaps.ulFormatLength = 100; sDiveCaps.ulStructLen = sizeof(DIVE_CAPS); @@ -172,7 +174,7 @@ static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, /* Setup DIVE blitter. */ SETUP_BLITTER sSetupBlitter; SWP swp; - POINTL pointl = { 0 }; + POINTL pointl = { 0,0 }; WinQueryWindowPos(hwnd, &swp); WinMapWindowPoints(hwnd, HWND_DESKTOP, &pointl, 1); diff --git a/src/video/os2/SDL_os2messagebox.c b/src/video/os2/SDL_os2messagebox.c index 94bc5e30f..c904fa5cb 100644 --- a/src/video/os2/SDL_os2messagebox.c +++ b/src/video/os2/SDL_os2messagebox.c @@ -35,8 +35,8 @@ #define IDD_PB_FIRST 1003 typedef struct _MSGBOXDLGDATA { - USHORT cb; - HWND hwndUnder; + USHORT cb; + HWND hwndUnder; } MSGBOXDLGDATA; static VOID _wmInitDlg(HWND hwnd, MSGBOXDLGDATA *pDlgData) @@ -205,9 +205,9 @@ static HWND _makeDlg(const SDL_MessageBoxData *messageboxdata) pSDLBtnData = (SDL_MessageBoxButtonData *)messageboxdata->buttons; ULONG cSDLBtnData = messageboxdata->numbuttons; - PSZ pszTitle = OS2_UTF8ToSys((PSZ) messageboxdata->title); + PSZ pszTitle = OS2_UTF8ToSys(messageboxdata->title); ULONG cbTitle = (pszTitle == NULL)? 1 : (SDL_strlen(pszTitle) + 1); - PSZ pszText = OS2_UTF8ToSys((PSZ) messageboxdata->message); + PSZ pszText = OS2_UTF8ToSys(messageboxdata->message); ULONG cbText = (pszText == NULL)? 1 : (SDL_strlen(pszText) + 1); PDLGTEMPLATE pTemplate; @@ -406,7 +406,7 @@ static HWND _makeDlg(const SDL_MessageBoxData *messageboxdata) pDlgItem->cchClassName = 0; /* 0 - offClassname is WC_ constant. */ pDlgItem->offClassName = (USHORT)WC_BUTTON; - pszBtnText = OS2_UTF8ToSys((PSZ)pSDLBtnData[ulIdx].text); + pszBtnText = OS2_UTF8ToSys(pSDLBtnData[ulIdx].text); cbBtnText = (pszBtnText == NULL)? 1 : (SDL_strlen(pszBtnText) + 1); pDlgItem->cchText = cbBtnText; pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the text. */ diff --git a/src/video/os2/SDL_os2util.c b/src/video/os2/SDL_os2util.c index adc2fd5e0..bcc6c54e8 100644 --- a/src/video/os2/SDL_os2util.c +++ b/src/video/os2/SDL_os2util.c @@ -27,8 +27,8 @@ HPOINTER utilCreatePointer(SDL_Surface *surface, ULONG ulHotX, ULONG ulHotY) { HBITMAP hbm; - BITMAPINFOHEADER2 bmih = { 0 }; - BITMAPINFO bmi = { 0 }; + BITMAPINFOHEADER2 bmih; + BITMAPINFO bmi; HPS hps; PULONG pulBitmap; PULONG pulDst, pulSrc, pulDstMask; @@ -40,7 +40,7 @@ HPOINTER utilCreatePointer(SDL_Surface *surface, ULONG ulHotX, ULONG ulHotY) return NULLHANDLE; } - pulBitmap = SDL_malloc(surface->h * surface->w * 4 * 2); + pulBitmap = (PULONG) SDL_malloc(surface->h * surface->w * 2 * sizeof(ULONG)); if (pulBitmap == NULL) { SDL_OutOfMemory(); return NULLHANDLE; @@ -72,6 +72,9 @@ HPOINTER utilCreatePointer(SDL_Surface *surface, ULONG ulHotX, ULONG ulHotY) } /* Create system bitmap object. */ + SDL_zero(bmih); + SDL_zero(bmi); + bmih.cbFix = sizeof(BITMAPINFOHEADER2); bmih.cx = surface->w; bmih.cy = 2 * surface->h; diff --git a/src/video/os2/SDL_os2video.c b/src/video/os2/SDL_os2video.c index d624575cf..64731d71d 100644 --- a/src/video/os2/SDL_os2video.c +++ b/src/video/os2/SDL_os2video.c @@ -335,7 +335,7 @@ static VOID _wmChar(WINDATA *pWinData, MPARAM mp1, MPARAM mp2) static VOID _wmMove(WINDATA *pWinData) { SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(pWinData->window); - POINTL pointl = { 0 }; + POINTL pointl = { 0,0 }; RECTL rectl; WinQueryWindowRect(pWinData->hwnd, &rectl); @@ -1219,7 +1219,7 @@ static int OS2_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, { SDL_ShapeTree *pShapeTree; WINDATA *pWinData; - SHAPERECTS stShapeRects = { 0 }; + SHAPERECTS stShapeRects; HPS hps; debug_os2("Enter"); @@ -1235,6 +1235,7 @@ static int OS2_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, pShapeTree = SDL_CalculateShapeTree(*shape_mode, shape); shaper->driverdata = pShapeTree; + SDL_zero(stShapeRects); stShapeRects.ulWinHeight = shaper->window->h; SDL_TraverseShapeTree(pShapeTree, &_combineRectRegions, &stShapeRects); @@ -1401,18 +1402,19 @@ static char *OS2_GetClipboardText(_THIS) static SDL_bool OS2_HasClipboardText(_THIS) { SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata; - SDL_bool fClipboard; + PSZ pszClipboard; + SDL_bool result; if (!WinOpenClipbrd(pVData->hab)) { debug_os2("WinOpenClipbrd() failed"); return SDL_FALSE; } - fClipboard = ((PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT) != NULL)? - SDL_TRUE : SDL_FALSE; + pszClipboard = (PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT); + result = (pszClipboard && *pszClipboard) ? SDL_TRUE : SDL_FALSE; WinCloseClipbrd(pVData->hab); - return fClipboard; + return result; } diff --git a/src/video/os2/SDL_os2vman.c b/src/video/os2/SDL_os2vman.c index 3fb93f13e..acb920061 100644 --- a/src/video/os2/SDL_os2vman.c +++ b/src/video/os2/SDL_os2vman.c @@ -91,10 +91,10 @@ static VOID APIENTRY ExitVMan(VOID) static BOOL _vmanInit(void) { ULONG ulRC; - CHAR acBuf[255]; + CHAR acBuf[256]; INITPROCOUT stInitProcOut; - if (hmodVMan != NULLHANDLE) /* Already was initialized */ + if (hmodVMan != NULLHANDLE) /* already initialized */ return TRUE; /* Load vman.dll */ @@ -108,8 +108,7 @@ static BOOL _vmanInit(void) /* Get VMIEntry */ ulRC = DosQueryProcAddr(hmodVMan, 0L, "VMIEntry", (PFN *)&pfnVMIEntry); if (ulRC != NO_ERROR) { - debug_os2("Could not query address of pfnVMIEntry func. of VMAN.DLL, " - "rc = %u", ulRC); + debug_os2("Could not query address of VMIEntry from VMAN.DLL (Err: %lu)", ulRC); DosFreeModule(hmodVMan); hmodVMan = NULLHANDLE; return FALSE; @@ -327,9 +326,8 @@ static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, PPOINTL pptlSrcOrg; PBLTRECT pbrDst; HWREQIN sHWReqIn; - BITBLTINFO sBitbltInfo = { 0 }; + BITBLTINFO sBitbltInfo; ULONG ulIdx; -/* RECTL rectlScreenUpdate;*/ if (pVOData->pBuffer == NULL) return FALSE; @@ -454,6 +452,7 @@ static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, rclSrcBounds.xRight = bmiSrc.ulWidth; rclSrcBounds.yTop = bmiSrc.ulHeight; + SDL_zero(sBitbltInfo); sBitbltInfo.ulLength = sizeof(BITBLTINFO); sBitbltInfo.ulBltFlags = BF_DEFAULT_STATE | BF_ROP_INCL_SRC | BF_PAT_HOLLOW; sBitbltInfo.cBlits = cSDLRects; diff --git a/src/video/riscos/SDL_riscosevents.c b/src/video/riscos/SDL_riscosevents.c index b7ae62e9e..b0a0d7509 100644 --- a/src/video/riscos/SDL_riscosevents.c +++ b/src/video/riscos/SDL_riscosevents.c @@ -67,7 +67,6 @@ RISCOS_PollKeyboard(_THIS) /* Check for key presses */ while (key < 0xff) { - SDL_bool already_pressed = SDL_FALSE; key = _kernel_osbyte(121, key + 1, 0) & 0xff; switch (key) { case 255: @@ -83,22 +82,16 @@ RISCOS_PollKeyboard(_THIS) break; default: - /* Do we already know of this key? */ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_RISCOS_translate_keycode(key)); + + /* Record the press so we can detect release later. */ for (i = 0; i < RISCOS_MAX_KEYS_PRESSED; i++) { if (driverdata->key_pressed[i] == key) { - already_pressed = SDL_TRUE; break; } - } - - if (!already_pressed) { - SDL_SendKeyboardKey(SDL_PRESSED, SDL_RISCOS_translate_keycode(key)); - /* Record the press so we can detect release later. */ - for (i = 0; i < RISCOS_MAX_KEYS_PRESSED; i++) { - if (driverdata->key_pressed[i] == 255) { - driverdata->key_pressed[i] = key; - break; - } + if (driverdata->key_pressed[i] == 255) { + driverdata->key_pressed[i] = key; + break; } } } diff --git a/src/video/sdlgenblit.pl b/src/video/sdlgenblit.pl index bb70cebb6..c2a22b049 100755 --- a/src/video/sdlgenblit.pl +++ b/src/video/sdlgenblit.pl @@ -220,16 +220,82 @@ sub output_copycore my $A_is_const_FF = shift; my $s = ""; my $d = ""; + my $dst_has_alpha = ($dst =~ /A/) ? 1 : 0; + my $src_has_alpha = ($src =~ /A/) ? 1 : 0; + my $sa = ""; + my $da = ""; - # Nice and easy... - if ( $src eq $dst && !$modulate && !$blend ) { - print FILE <<__EOF__; + if (!$modulate && !$blend) { + # Nice and easy... + if ( $src eq $dst ) { + print FILE <<__EOF__; *dst = *src; __EOF__ - return; + return; + } + + # Matching color-order + $sa = $src; + $sa =~ s/[A8]//g; + $da = $dst; + $da =~ s/[A8]//g; + if ($sa eq $da) { + if ($dst_has_alpha && $src_has_alpha) { + $da = substr $dst, 0, 1; + if ($da eq "A") { + # RGBA -> ARGB + print FILE <<__EOF__; + pixel = *src; + pixel = (pixel >> 8) | (pixel << 24); + *dst = pixel; +__EOF__ + } else { + # ARGB -> RGBA -- unused + print FILE <<__EOF__; + pixel = *src; + pixel = (pixel << 8) | A; + *dst = pixel; +__EOF__ + } + } elsif ($dst_has_alpha) { + $da = substr $dst, 0, 1; + if ($da eq "A") { + # RGB -> ARGB + print FILE <<__EOF__; + pixel = *src; + pixel |= (A << 24); + *dst = pixel; +__EOF__ + } else { + # RGB -> RGBA -- unused + print FILE <<__EOF__; + pixel = *src; + pixel = (pixel << 8) | A; + *dst = pixel; +__EOF__ + } + } else { + $sa = substr $src, 0, 1; + if ($sa eq "A") { + # ARGB -> RGB + print FILE <<__EOF__; + pixel = *src; + pixel &= 0xFFFFFF; + *dst = pixel; +__EOF__ + } else { + # RGBA -> RGB + print FILE <<__EOF__; + pixel = *src; + pixel >>= 8; + *dst = pixel; +__EOF__ + } + } + return; + } } - my $dst_has_alpha = ($dst =~ /A/) ? 1 : 0; my $ignore_dst_alpha = !$dst_has_alpha && !$blend; if ( $blend ) { @@ -366,6 +432,14 @@ sub output_copyfunc my $is_modulateA_done = 0; my $A_is_const_FF = 0; + my $sa = $src; + my $da = $dst; + my $matching_colors = 0; + + $sa =~ s/[A8]//g; + $da =~ s/[A8]//g; + $matching_colors = (!$modulate && !$blend && ($sa eq $da)) ? 1 : 0; + output_copyfuncname("static void", $src, $dst, $modulate, $blend, $scale, 1, "\n"); print FILE <<__EOF__; { @@ -424,8 +498,8 @@ sub output_copyfunc print FILE <<__EOF__; Uint32 pixel; __EOF__ - if (!$ignore_dst_alpha && !$src_has_alpha) { - if ($modulate){ + if ( !$ignore_dst_alpha && !$src_has_alpha ) { + if ( $modulate ) { $is_modulateA_done = 1; print FILE <<__EOF__; const Uint32 A = (flags & SDL_COPY_MODULATE_ALPHA) ? modulateA : 0xFF; @@ -436,14 +510,18 @@ sub output_copyfunc const Uint32 A = 0xFF; __EOF__ } - print FILE <<__EOF__; + if ( !$matching_colors ) { + print FILE <<__EOF__; Uint32 R, G, B; __EOF__ - } elsif (!$ignore_dst_alpha) { - print FILE <<__EOF__; + } + } elsif ( !$ignore_dst_alpha ) { + if ( !$matching_colors ) { + print FILE <<__EOF__; Uint32 R, G, B, A; __EOF__ - } else { + } + } elsif ( !$matching_colors ) { print FILE <<__EOF__; Uint32 R, G, B; __EOF__ diff --git a/src/video/uikit/SDL_uikitevents.m b/src/video/uikit/SDL_uikitevents.m index 5253aa75a..b7ef0bf40 100644 --- a/src/video/uikit/SDL_uikitevents.m +++ b/src/video/uikit/SDL_uikitevents.m @@ -87,7 +87,7 @@ touch events to get processed (which is important to get certain static void OnGCKeyboardConnected(GCKeyboard *keyboard) API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0)) { keyboard_connected = SDL_TRUE; - keyboard.keyboardInput.keyChangedHandler = ^(GCKeyboardInput *keyboard, GCControllerButtonInput *key, GCKeyCode keyCode, BOOL pressed) + keyboard.keyboardInput.keyChangedHandler = ^(GCKeyboardInput *kbrd, GCControllerButtonInput *key, GCKeyCode keyCode, BOOL pressed) { SDL_SendKeyboardKey(pressed ? SDL_PRESSED : SDL_RELEASED, (SDL_Scancode)keyCode); }; @@ -225,15 +225,15 @@ static void OnGCMouseConnected(GCMouse *mouse) API_AVAILABLE(macos(11.0), ios(14 }; int auxiliary_button = SDL_BUTTON_X1; - for (GCControllerButtonInput *button in mouse.mouseInput.auxiliaryButtons) { - button.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) + for (GCControllerButtonInput *btn in mouse.mouseInput.auxiliaryButtons) { + btn.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { OnGCMouseButtonChanged(mouseID, auxiliary_button, pressed); }; ++auxiliary_button; } - mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput *mouse, float deltaX, float deltaY) + mouse.mouseInput.mouseMovedHandler = ^(GCMouseInput *mouseInput, float deltaX, float deltaY) { if (SDL_GCMouseRelativeMode()) { SDL_SendMouseMotion(SDL_GetMouseFocus(), mouseID, 1, (int)deltaX, -(int)deltaY); diff --git a/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index 7aecea803..b6d56f350 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -86,7 +86,7 @@ action = [UIAlertAction actionWithTitle:@(sdlButton->text) style:style - handler:^(UIAlertAction *action) { + handler:^(UIAlertAction *alertAction) { clickedindex = (int)(sdlButton - messageboxdata->buttons); }]; [alert addAction:action]; @@ -186,8 +186,8 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) #endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ } -int -UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +static void +UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid, int *returnValue) { BOOL success = NO; @@ -199,12 +199,26 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) } if (!success) { - return SDL_SetError("Could not show message box."); + *returnValue = SDL_SetError("Could not show message box."); + } else { + *returnValue = 0; } - - return 0; } +int +UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ @autoreleasepool +{ + __block int returnValue = 0; + + if ([NSThread isMainThread]) { + UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); + } else { + dispatch_sync(dispatch_get_main_queue(), ^{ UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); }); + } + return returnValue; +}} + #endif /* SDL_VIDEO_DRIVER_UIKIT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/uikit/SDL_uikitopengles.m b/src/video/uikit/SDL_uikitopengles.m index 8722dca93..86fefd76c 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -162,8 +162,8 @@ int UIKit_GL_SwapWindow(_THIS, SDL_Window * window) } if (_this->gl_config.share_with_current_context) { - EAGLContext *context = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); - sharegroup = context.sharegroup; + EAGLContext *currContext = (__bridge EAGLContext *) SDL_GL_GetCurrentContext(); + sharegroup = currContext.sharegroup; } if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { diff --git a/src/video/vita/SDL_vitaframebuffer.c b/src/video/vita/SDL_vitaframebuffer.c index 992c7af84..1c558486b 100644 --- a/src/video/vita/SDL_vitaframebuffer.c +++ b/src/video/vita/SDL_vitaframebuffer.c @@ -31,7 +31,7 @@ #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) #define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8 -void *vita_gpu_alloc(SceKernelMemBlockType type, unsigned int size, SceUID *uid) +void *vita_gpu_alloc(unsigned int type, unsigned int size, SceUID *uid) { void *mem; diff --git a/src/video/vita/SDL_vitagl_pvr.c b/src/video/vita/SDL_vitagl_pvr.c index 3b7fb7477..d51150c03 100644 --- a/src/video/vita/SDL_vitagl_pvr.c +++ b/src/video/vita/SDL_vitagl_pvr.c @@ -20,11 +20,12 @@ */ #include "../../SDL_internal.h" -#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR +#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR && SDL_VIDEO_VITA_PVR_OGL #include #include #include #include +#include #include "SDL_error.h" #include "SDL_log.h" @@ -34,6 +35,16 @@ #define MAX_PATH 256 // vita limits are somehow wrong +/* Defaults */ +int FB_WIDTH = 960; +int FB_HEIGHT = 544; + +void getFBSize(int *width, int *height) +{ + *width = FB_WIDTH; + *height = FB_HEIGHT; +} + int VITA_GL_LoadLibrary(_THIS, const char *path) { @@ -53,6 +64,9 @@ VITA_GL_LoadLibrary(_THIS, const char *path) sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL); sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL); + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libGL.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx"); sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); @@ -74,30 +88,45 @@ VITA_GL_LoadLibrary(_THIS, const char *path) SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window) { - return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); -} + char gl_version[3]; + SDL_GLContext context = NULL; + int temp_major = _this->gl_config.major_version; + int temp_minor = _this->gl_config.minor_version; + int temp_profile = _this->gl_config.profile_mask; -int -VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) -{ - if (window && context) { - return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context); - } else { - return SDL_EGL_MakeCurrent(_this, NULL, NULL); + /* Set version to 2.0 and PROFILE to ES */ + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 0; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; + + context = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); + + if (context != NULL) + { + FB_WIDTH = window->w; + FB_HEIGHT = window->h; + set_getprocaddress((void *(*)(const char *))eglGetProcAddress); + set_getmainfbsize(getFBSize); + SDL_snprintf(gl_version, 3, "%d%d", temp_major, temp_minor); + gl4es_setenv("LIBGL_NOTEXRECT", "1", 1); /* Currently broken in driver */ + gl4es_setenv("LIBGL_GL", gl_version, 1); + initialize_gl4es(); } + + /* Restore gl_config */ + _this->gl_config.major_version = temp_major; + _this->gl_config.minor_version = temp_minor; + _this->gl_config.profile_mask = temp_profile; + + return context; } -int -VITA_GL_SwapWindow(_THIS, SDL_Window * window) +void * +VITA_GL_GetProcAddress(_THIS, const char *proc) { - SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; - if (videodata->ime_active) { - sceImeUpdate(); - } - return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); + return gl4es_GetProcAddress(proc); } - #endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vita/SDL_vitagl_pvr_c.h b/src/video/vita/SDL_vitagl_pvr_c.h index 670eaebb0..2329d472b 100644 --- a/src/video/vita/SDL_vitagl_pvr_c.h +++ b/src/video/vita/SDL_vitagl_pvr_c.h @@ -19,17 +19,16 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SDL_vitagl_c_h_ -#define SDL_vitagl_c_h_ +#ifndef SDL_vitagl_pvr_c_h_ +#define SDL_vitagl_pvr_c_h_ #include "SDL_vitavideo.h" -extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); -extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window); extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); extern int VITA_GL_LoadLibrary(_THIS, const char *path); +extern void *VITA_GL_GetProcAddress(_THIS, const char *proc); -#endif /* SDL_vitagl_c_h_ */ +#endif /* SDL_vitagl_pvr_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vita/SDL_vitagl.c b/src/video/vita/SDL_vitagles.c similarity index 91% rename from src/video/vita/SDL_vitagl.c rename to src/video/vita/SDL_vitagles.c index f65022865..18ca7d57b 100644 --- a/src/video/vita/SDL_vitagl.c +++ b/src/video/vita/SDL_vitagles.c @@ -27,7 +27,7 @@ #include "SDL_error.h" #include "SDL_log.h" #include "SDL_vitavideo.h" -#include "SDL_vitagl_c.h" +#include "SDL_vitagles_c.h" /*****************************************************************************/ /* SDL OpenGL/OpenGL ES functions */ @@ -45,7 +45,7 @@ } while (0) void -VITA_GL_KeyboardCallback(ScePigletPreSwapData *data) +VITA_GLES_KeyboardCallback(ScePigletPreSwapData *data) { SceCommonDialogUpdateParam commonDialogParam; SDL_zero(commonDialogParam); @@ -62,20 +62,20 @@ VITA_GL_KeyboardCallback(ScePigletPreSwapData *data) } int -VITA_GL_LoadLibrary(_THIS, const char *path) +VITA_GLES_LoadLibrary(_THIS, const char *path) { pibInit(PIB_SHACCCG | PIB_GET_PROC_ADDR_CORE); return 0; } void * -VITA_GL_GetProcAddress(_THIS, const char *proc) +VITA_GLES_GetProcAddress(_THIS, const char *proc) { return eglGetProcAddress(proc); } void -VITA_GL_UnloadLibrary(_THIS) +VITA_GLES_UnloadLibrary(_THIS) { eglTerminate(_this->gl_data->display); } @@ -84,7 +84,7 @@ static EGLint width = 960; static EGLint height = 544; SDL_GLContext -VITA_GL_CreateContext(_THIS, SDL_Window * window) +VITA_GLES_CreateContext(_THIS, SDL_Window * window) { SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata; @@ -159,13 +159,13 @@ VITA_GL_CreateContext(_THIS, SDL_Window * window) _this->gl_data->surface = surface; preSwapCallback = (PFNEGLPIGLETVITASETPRESWAPCALLBACKSCEPROC) eglGetProcAddress("eglPigletVitaSetPreSwapCallbackSCE"); - preSwapCallback(VITA_GL_KeyboardCallback); + preSwapCallback(VITA_GLES_KeyboardCallback); return context; } int -VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) { if (!eglMakeCurrent(_this->gl_data->display, _this->gl_data->surface, _this->gl_data->surface, _this->gl_data->context)) @@ -176,7 +176,7 @@ VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) } int -VITA_GL_SetSwapInterval(_THIS, int interval) +VITA_GLES_SetSwapInterval(_THIS, int interval) { EGLBoolean status; status = eglSwapInterval(_this->gl_data->display, interval); @@ -190,13 +190,13 @@ VITA_GL_SetSwapInterval(_THIS, int interval) } int -VITA_GL_GetSwapInterval(_THIS) +VITA_GLES_GetSwapInterval(_THIS) { return _this->gl_data->swapinterval; } int -VITA_GL_SwapWindow(_THIS, SDL_Window * window) +VITA_GLES_SwapWindow(_THIS, SDL_Window * window) { if (!eglSwapBuffers(_this->gl_data->display, _this->gl_data->surface)) { return SDL_SetError("eglSwapBuffers() failed"); @@ -205,7 +205,7 @@ VITA_GL_SwapWindow(_THIS, SDL_Window * window) } void -VITA_GL_DeleteContext(_THIS, SDL_GLContext context) +VITA_GLES_DeleteContext(_THIS, SDL_GLContext context) { SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata; EGLBoolean status; diff --git a/src/video/vita/SDL_vitagl_c.h b/src/video/vita/SDL_vitagles_c.h similarity index 67% rename from src/video/vita/SDL_vitagl_c.h rename to src/video/vita/SDL_vitagles_c.h index 272653d70..10fd8533a 100644 --- a/src/video/vita/SDL_vitagl_c.h +++ b/src/video/vita/SDL_vitagles_c.h @@ -19,8 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef SDL_vitagl_c_h_ -#define SDL_vitagl_c_h_ +#ifndef SDL_vitagles_c_h_ +#define SDL_vitagles_c_h_ #include @@ -39,19 +39,19 @@ typedef struct SDL_GLDriverData { uint32_t swapinterval; }SDL_GLDriverData; -extern void * VITA_GL_GetProcAddress(_THIS, const char *proc); -extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); -extern void VITA_GL_SwapBuffers(_THIS); +extern void * VITA_GLES_GetProcAddress(_THIS, const char *proc); +extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); +extern void VITA_GLES_SwapBuffers(_THIS); -extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window); -extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); +extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); -extern int VITA_GL_LoadLibrary(_THIS, const char *path); -extern void VITA_GL_UnloadLibrary(_THIS); -extern int VITA_GL_SetSwapInterval(_THIS, int interval); -extern int VITA_GL_GetSwapInterval(_THIS); +extern int VITA_GLES_LoadLibrary(_THIS, const char *path); +extern void VITA_GLES_UnloadLibrary(_THIS); +extern int VITA_GLES_SetSwapInterval(_THIS, int interval); +extern int VITA_GLES_GetSwapInterval(_THIS); -#endif /* SDL_vitagl_c_h_ */ +#endif /* SDL_vitagles_c_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vita/SDL_vitagles_pvr.c b/src/video/vita/SDL_vitagles_pvr.c new file mode 100644 index 000000000..bb06d2946 --- /dev/null +++ b/src/video/vita/SDL_vitagles_pvr.c @@ -0,0 +1,103 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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_VITA && SDL_VIDEO_VITA_PVR +#include +#include +#include +#include + +#include "SDL_error.h" +#include "SDL_log.h" +#include "SDL_vitavideo.h" +#include "../SDL_egl_c.h" +#include "SDL_vitagles_pvr_c.h" + +#define MAX_PATH 256 // vita limits are somehow wrong + +int +VITA_GLES_LoadLibrary(_THIS, const char *path) +{ + PVRSRV_PSP2_APPHINT hint; + char* override = SDL_getenv("VITA_MODULE_PATH"); + char* skip_init = SDL_getenv("VITA_PVR_SKIP_INIT"); + char* default_path = "app0:module"; + char target_path[MAX_PATH]; + + if (skip_init == NULL) // we don't care about actual value + { + if (override != NULL) + { + default_path = override; + } + + sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL); + sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL); + + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + + SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libIMGEGL.suprx"); + sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL); + + PVRSRVInitializeAppHint(&hint); + + SDL_snprintf(hint.szGLES1, MAX_PATH, "%s/%s", default_path, "libGLESv1_CM.suprx"); + SDL_snprintf(hint.szGLES2, MAX_PATH, "%s/%s", default_path, "libGLESv2.suprx"); + SDL_snprintf(hint.szWindowSystem, MAX_PATH, "%s/%s", default_path, "libpvrPSP2_WSEGL.suprx"); + + PVRSRVCreateVirtualAppHint(&hint); + } + + return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0); +} + +SDL_GLContext +VITA_GLES_CreateContext(_THIS, SDL_Window * window) +{ + return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); +} + +int +VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context) +{ + if (window && context) { + return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context); + } else { + return SDL_EGL_MakeCurrent(_this, NULL, NULL); + } +} + +int +VITA_GLES_SwapWindow(_THIS, SDL_Window * window) +{ + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + if (videodata->ime_active) { + sceImeUpdate(); + } + return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface); +} + + +#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vita/SDL_vitagles_pvr_c.h b/src/video/vita/SDL_vitagles_pvr_c.h new file mode 100644 index 000000000..c3a13c436 --- /dev/null +++ b/src/video/vita/SDL_vitagles_pvr_c.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + 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_vitagles_pvr_c_h_ +#define SDL_vitagles_pvr_c_h_ + +#include "SDL_vitavideo.h" + +extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context); +extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); +extern int VITA_GLES_LoadLibrary(_THIS, const char *path); + + +#endif /* SDL_vitagles_pvr_c_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vita/SDL_vitatouch.c b/src/video/vita/SDL_vitatouch.c index f28c880bd..43a3ecbd2 100644 --- a/src/video/vita/SDL_vitatouch.c +++ b/src/video/vita/SDL_vitatouch.c @@ -108,17 +108,30 @@ VITA_PollTouch(void) float x = 0; float y = 0; float force = (touch[port].report[i].force - force_info[port].min) / force_info[port].range; + int finger_down = 0; + + if (touch_old[port].reportNum > 0) { + for (int j = 0; j < touch_old[port].reportNum; j++) { + if (touch[port].report[i].id == touch_old[port].report[j].id ) { + finger_down = 1; + } + } + } + VITA_ConvertTouchXYToSDLXY(&x, &y, touch[port].report[i].x, touch[port].report[i].y, port); finger_id = (SDL_FingerID) touch[port].report[i].id; - // Send an initial touch - SDL_SendTouch((SDL_TouchID)port, - finger_id, - Vita_Window, - SDL_TRUE, - x, - y, - force); + // Skip if finger was already previously down + if(!finger_down) { + // Send an initial touch + SDL_SendTouch((SDL_TouchID)port, + finger_id, + Vita_Window, + SDL_TRUE, + x, + y, + force); + } // Always send the motion SDL_SendTouchMotion((SDL_TouchID)port, diff --git a/src/video/vita/SDL_vitavideo.c b/src/video/vita/SDL_vitavideo.c index ad9e559a3..60bd18f45 100644 --- a/src/video/vita/SDL_vitavideo.c +++ b/src/video/vita/SDL_vitavideo.c @@ -41,15 +41,17 @@ #include "SDL_vitaframebuffer.h" #if defined(SDL_VIDEO_VITA_PIB) - #include "SDL_vitagl_c.h" + #include "SDL_vitagles_c.h" #elif defined(SDL_VIDEO_VITA_PVR) + #include "SDL_vitagles_pvr_c.h" +#if defined(SDL_VIDEO_VITA_PVR_OGL) #include "SDL_vitagl_pvr_c.h" - #include "../SDL_egl_c.h" - #define VITA_GL_GetProcAddress SDL_EGL_GetProcAddress - #define VITA_GL_UnloadLibrary SDL_EGL_UnloadLibrary - #define VITA_GL_SetSwapInterval SDL_EGL_SetSwapInterval - #define VITA_GL_GetSwapInterval SDL_EGL_GetSwapInterval - #define VITA_GL_DeleteContext SDL_EGL_DeleteContext +#endif + #define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddress + #define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary + #define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval + #define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval + #define VITA_GLES_DeleteContext SDL_EGL_DeleteContext #endif SDL_Window *Vita_Window; @@ -140,15 +142,26 @@ VITA_Create() */ #if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR) +#if defined(SDL_VIDEO_VITA_PVR_OGL) +if(SDL_getenv("VITA_PVR_OGL") != NULL) { device->GL_LoadLibrary = VITA_GL_LoadLibrary; - device->GL_GetProcAddress = VITA_GL_GetProcAddress; - device->GL_UnloadLibrary = VITA_GL_UnloadLibrary; device->GL_CreateContext = VITA_GL_CreateContext; - device->GL_MakeCurrent = VITA_GL_MakeCurrent; - device->GL_SetSwapInterval = VITA_GL_SetSwapInterval; - device->GL_GetSwapInterval = VITA_GL_GetSwapInterval; - device->GL_SwapWindow = VITA_GL_SwapWindow; - device->GL_DeleteContext = VITA_GL_DeleteContext; + device->GL_GetProcAddress = VITA_GL_GetProcAddress; +} else { +#endif + device->GL_LoadLibrary = VITA_GLES_LoadLibrary; + device->GL_CreateContext = VITA_GLES_CreateContext; + device->GL_GetProcAddress = VITA_GLES_GetProcAddress; +#if defined(SDL_VIDEO_VITA_PVR_OGL) +} +#endif + + device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary; + device->GL_MakeCurrent = VITA_GLES_MakeCurrent; + device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval; + device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval; + device->GL_SwapWindow = VITA_GLES_SwapWindow; + device->GL_DeleteContext = VITA_GLES_DeleteContext; #endif device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport; @@ -245,6 +258,9 @@ VITA_CreateWindow(_THIS, SDL_Window * window) SDL_WindowData *wdata; #if defined(SDL_VIDEO_VITA_PVR) Psp2NativeWindow win; + int temp_major = 2; + int temp_minor = 1; + int temp_profile = 0; #endif /* Allocate window internal data */ @@ -259,8 +275,7 @@ VITA_CreateWindow(_THIS, SDL_Window * window) // Vita can only have one window if (Vita_Window != NULL) { - SDL_SetError("Only one window supported"); - return -1; + return SDL_SetError("Only one window supported"); } Vita_Window = window; @@ -283,11 +298,26 @@ VITA_CreateWindow(_THIS, SDL_Window * window) win.windowSize = PSP2_WINDOW_960X544; } if ((window->flags & SDL_WINDOW_OPENGL) != 0) { + if(SDL_getenv("VITA_PVR_OGL") != NULL) { + /* Set version to 2.1 and PROFILE to ES */ + temp_major = _this->gl_config.major_version; + temp_minor = _this->gl_config.minor_version; + temp_profile = _this->gl_config.profile_mask; + + _this->gl_config.major_version = 2; + _this->gl_config.minor_version = 1; + _this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES; + } wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win); - if (wdata->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); } + if(SDL_getenv("VITA_PVR_OGL") != NULL) { + /* Revert */ + _this->gl_config.major_version = temp_major; + _this->gl_config.minor_version = temp_minor; + _this->gl_config.profile_mask = temp_profile; + } } #endif diff --git a/src/video/vita/SDL_vitavideo.h b/src/video/vita/SDL_vitavideo.h index 04488dde3..9fdf7e69c 100644 --- a/src/video/vita/SDL_vitavideo.h +++ b/src/video/vita/SDL_vitavideo.h @@ -90,16 +90,23 @@ SDL_bool VITA_GetWindowWMInfo(_THIS, SDL_Window * window, struct SDL_SysWMinfo *info); #if SDL_VIDEO_DRIVER_VITA +#if defined(SDL_VIDEO_VITA_PVR_OGL) /* OpenGL functions */ int VITA_GL_LoadLibrary(_THIS, const char *path); -void *VITA_GL_GetProcAddress(_THIS, const char *proc); -void VITA_GL_UnloadLibrary(_THIS); SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window); -int VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); -int VITA_GL_SetSwapInterval(_THIS, int interval); -int VITA_GL_GetSwapInterval(_THIS); -int VITA_GL_SwapWindow(_THIS, SDL_Window * window); -void VITA_GL_DeleteContext(_THIS, SDL_GLContext context); +void *VITA_GL_GetProcAddress(_THIS, const char *proc); +#endif + +/* OpenGLES functions */ +int VITA_GLES_LoadLibrary(_THIS, const char *path); +void *VITA_GLES_GetProcAddress(_THIS, const char *proc); +void VITA_GLES_UnloadLibrary(_THIS); +SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window); +int VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); +int VITA_GLES_SetSwapInterval(_THIS, int interval); +int VITA_GLES_GetSwapInterval(_THIS); +int VITA_GLES_SwapWindow(_THIS, SDL_Window * window); +void VITA_GLES_DeleteContext(_THIS, SDL_GLContext context); #endif /* VITA on screen keyboard */ diff --git a/src/video/wayland/SDL_waylanddyn.h b/src/video/wayland/SDL_waylanddyn.h index c867ec001..3d8d973cc 100644 --- a/src/video/wayland/SDL_waylanddyn.h +++ b/src/video/wayland/SDL_waylanddyn.h @@ -52,6 +52,14 @@ enum libdecor_window_state; #include "xkbcommon/xkbcommon.h" #include "xkbcommon/xkbcommon-compose.h" +/* Must be included before our #defines, see Bugzilla #4957 */ +#include "wayland-client-core.h" + +#define SDL_WAYLAND_CHECK_VERSION(x, y, z) \ + (WAYLAND_VERSION_MAJOR > x || \ + (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \ + (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z)) + #ifdef __cplusplus extern "C" { @@ -71,9 +79,6 @@ void SDL_WAYLAND_UnloadSymbols(void); } #endif -/* Must be included before our #defines, see Bugzilla #4957 */ -#include "wayland-client-core.h" - #ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC #if defined(_WAYLAND_CLIENT_H) || defined(WAYLAND_CLIENT_H) diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index dfa62ec69..e515d9d6f 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -40,6 +40,7 @@ #include "xdg-shell-client-protocol.h" #include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -83,6 +84,7 @@ static const struct { { XKB_KEY_Super_R, SDLK_RGUI }, { XKB_KEY_Hyper_L, SDLK_LGUI }, { XKB_KEY_Hyper_R, SDLK_RGUI }, + { XKB_KEY_BackSpace, SDLK_BACKSPACE }, }; struct SDL_WaylandTouchPoint { @@ -387,8 +389,10 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, input->sx_w = sx_w; input->sy_w = sy_w; if (input->pointer_focus) { - const int sx = wl_fixed_to_int(sx_w); - const int sy = wl_fixed_to_int(sy_w); + const float sx_f = (float)wl_fixed_to_double(sx_w); + const float sy_f = (float)wl_fixed_to_double(sy_w); + const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x); + const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y); SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); } } @@ -472,6 +476,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial) const uint32_t *directions_libdecor = directions; #endif + /* Hit tests shouldn't apply to xdg_popups, right? */ + SDL_assert(!WINDOW_IS_XDG_POPUP(window)); + switch (rc) { case SDL_HITTEST_DRAGGABLE: #ifdef HAVE_LIBDECOR_H @@ -715,8 +722,8 @@ touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial, int id, wl_fixed_t fx, wl_fixed_t fy) { SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); - const double dblx = wl_fixed_to_double(fx); - const double dbly = wl_fixed_to_double(fy); + const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; + const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; const float x = dblx / window_data->sdlwindow->w; const float y = dbly / window_data->sdlwindow->h; @@ -748,8 +755,8 @@ touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp, int id, wl_fixed_t fx, wl_fixed_t fy) { SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); - const double dblx = wl_fixed_to_double(fx); - const double dbly = wl_fixed_to_double(fy); + const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; + const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; const float x = dblx / window_data->sdlwindow->w; const float y = dbly / window_data->sdlwindow->h; @@ -815,6 +822,16 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, return; } + #define GET_MOD_INDEX(mod) \ + WAYLAND_xkb_keymap_mod_get_index(input->xkb.keymap, XKB_MOD_NAME_##mod) + input->xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT); + input->xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL); + input->xkb.idx_alt = 1 << GET_MOD_INDEX(ALT); + input->xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO); + input->xkb.idx_num = 1 << GET_MOD_INDEX(NUM); + input->xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS); + #undef GET_MOD_INDEX + input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap); if (!input->xkb.state) { fprintf(stderr, "failed to create XKB state\n"); @@ -829,10 +846,14 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, */ /* Look up the preferred locale, falling back to "C" as default */ - if (!(locale = SDL_getenv("LC_ALL"))) - if (!(locale = SDL_getenv("LC_CTYPE"))) - if (!(locale = SDL_getenv("LANG"))) + if (!(locale = SDL_getenv("LC_ALL"))) { + if (!(locale = SDL_getenv("LC_CTYPE"))) { + if (!(locale = SDL_getenv("LANG"))) { locale = "C"; + } + } + } + /* Set up XKB compose table */ input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS); @@ -903,7 +924,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, } static SDL_bool -keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime) +keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime) { SDL_WindowData *window = input->keyboard_focus; const xkb_keysym_t *syms; @@ -920,12 +941,16 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint sym = syms[0]; #ifdef SDL_USE_IME - if (SDL_IME_ProcessKeyEvent(sym, key + 8)) { + if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) { *handled_by_ime = SDL_TRUE; return SDL_TRUE; } #endif + if (state == SDL_RELEASED) { + return SDL_FALSE; + } + if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) { switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) { case XKB_COMPOSE_COMPOSING: @@ -959,7 +984,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, SDL_bool handled_by_ime = SDL_FALSE; if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - has_text = keyboard_input_get_text(text, input, key, &handled_by_ime); + has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime); } else { if (keyboard_repeat_is_set(&input->keyboard_repeat)) { // Send any due key repeat events before stopping the repeat and generating the key up event @@ -969,6 +994,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time); keyboard_repeat_clear(&input->keyboard_repeat); } + keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime); } if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) { @@ -987,7 +1013,9 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, SDL_SendKeyboardText(text); } } - keyboard_repeat_set(&input->keyboard_repeat, time, scancode, has_text, text); + if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) { + keyboard_repeat_set(&input->keyboard_repeat, time, scancode, has_text, text); + } } } @@ -1052,10 +1080,24 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, { struct SDL_WaylandInput *input = data; Wayland_Keymap keymap; + uint32_t modstate = (mods_depressed | mods_latched | mods_locked); WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); + SDL_ToggleModState(KMOD_SHIFT, modstate & input->xkb.idx_shift); + SDL_ToggleModState(KMOD_CTRL, modstate & input->xkb.idx_ctrl); + SDL_ToggleModState(KMOD_ALT, modstate & input->xkb.idx_alt); + SDL_ToggleModState(KMOD_GUI, modstate & input->xkb.idx_gui); + SDL_ToggleModState(KMOD_NUM, modstate & input->xkb.idx_num); + SDL_ToggleModState(KMOD_CAPS, modstate & input->xkb.idx_caps); + + if (group == input->xkb.current_group) { + return; + } + + /* The layout changed, remap and fire an event */ + input->xkb.current_group = group; keymap.layout = group; SDL_GetDefaultKeymap(keymap.keymap); WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap, @@ -1312,36 +1354,145 @@ data_device_handle_motion(void *data, struct wl_data_device *wl_data_device, { } +/* Decodes URI escape sequences in string buf of len bytes + (excluding the terminating NULL byte) in-place. Since + URI-encoded characters take three times the space of + normal characters, this should not be an issue. + + Returns the number of decoded bytes that wound up in + the buffer, excluding the terminating NULL byte. + + The buffer is guaranteed to be NULL-terminated but + may contain embedded NULL bytes. + + On error, -1 is returned. + + FIXME: This was shamelessly copied from SDL_x11events.c + */ +static int Wayland_URIDecode(char *buf, int len) { + int ri, wi, di; + char decode = '\0'; + if (buf == NULL || len < 0) { + errno = EINVAL; + return -1; + } + if (len == 0) { + len = SDL_strlen(buf); + } + for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) { + if (di == 0) { + /* start decoding */ + if (buf[ri] == '%') { + decode = '\0'; + di += 1; + continue; + } + /* normal write */ + buf[wi] = buf[ri]; + wi += 1; + continue; + } else if (di == 1 || di == 2) { + char off = '\0'; + char isa = buf[ri] >= 'a' && buf[ri] <= 'f'; + char isA = buf[ri] >= 'A' && buf[ri] <= 'F'; + char isn = buf[ri] >= '0' && buf[ri] <= '9'; + if (!(isa || isA || isn)) { + /* not a hexadecimal */ + int sri; + for (sri = ri - di; sri <= ri; sri += 1) { + buf[wi] = buf[sri]; + wi += 1; + } + di = 0; + continue; + } + /* itsy bitsy magicsy */ + if (isn) { + off = 0 - '0'; + } else if (isa) { + off = 10 - 'a'; + } else if (isA) { + off = 10 - 'A'; + } + decode |= (buf[ri] + off) << (2 - di) * 4; + if (di == 2) { + buf[wi] = decode; + wi += 1; + di = 0; + } else { + di += 1; + } + continue; + } + } + buf[wi] = '\0'; + return wi; +} + +/* Convert URI to local filename + return filename if possible, else NULL + + FIXME: This was shamelessly copied from SDL_x11events.c +*/ +static char* Wayland_URIToLocal(char* uri) { + char *file = NULL; + SDL_bool local; + + if (SDL_memcmp(uri,"file:/",6) == 0) uri += 6; /* local file? */ + else if (SDL_strstr(uri,":/") != NULL) return file; /* wrong scheme */ + + local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/'); + + /* got a hostname? */ + if (!local && uri[0] == '/' && uri[2] != '/') { + char* hostname_end = SDL_strchr(uri+1, '/'); + if (hostname_end != NULL) { + char hostname[ 257 ]; + if (gethostname(hostname, 255) == 0) { + hostname[ 256 ] = '\0'; + if (SDL_memcmp(uri+1, hostname, hostname_end - (uri+1)) == 0) { + uri = hostname_end + 1; + local = SDL_TRUE; + } + } + } + } + if (local) { + file = uri; + /* Convert URI escape sequences to real characters */ + Wayland_URIDecode(file, 0); + if (uri[1] == '/') { + file++; + } else { + file--; + } + } + return file; +} + static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_device) { SDL_WaylandDataDevice *data_device = data; - void *buffer = NULL; - size_t length = 0; - - const char *current_uri = NULL; - const char *last_char = NULL; - char *current_char = NULL; if (data_device->drag_offer != NULL) { /* TODO: SDL Support more mime types */ - buffer = Wayland_data_offer_receive(data_device->drag_offer, - &length, FILE_MIME, SDL_FALSE); - - /* uri-list */ - current_uri = (const char *)buffer; - last_char = (const char *)buffer + length; - for (current_char = buffer; current_char < last_char; ++current_char) { - if (*current_char == '\n' || *current_char == 0) { - if (*current_uri != 0 && *current_uri != '#') { - *current_char = 0; - SDL_SendDropFile(NULL, current_uri); + size_t length; + void *buffer = Wayland_data_offer_receive(data_device->drag_offer, + &length, FILE_MIME, SDL_FALSE); + if (buffer) { + char *saveptr = NULL; + char *token = SDL_strtokr((char *) buffer, "\r\n", &saveptr); + while (token != NULL) { + char *fn = Wayland_URIToLocal(token); + if (fn) { + SDL_SendDropFile(NULL, fn); /* FIXME: Window? */ } - current_uri = (const char *)current_char + 1; + token = SDL_strtokr(NULL, "\r\n", &saveptr); } + SDL_SendDropComplete(NULL); /* FIXME: Window? */ + SDL_free(buffer); } - - SDL_free(buffer); } } @@ -1396,7 +1547,9 @@ text_input_preedit_string(void *data, int32_t cursor_begin, int32_t cursor_end) { + SDL_WaylandTextInput *text_input = data; char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + text_input->has_preedit = SDL_TRUE; if (text) { size_t text_bytes = SDL_strlen(text), i = 0; size_t cursor = 0; @@ -1448,7 +1601,11 @@ text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3, uint32_t serial) { - /* No-op */ + SDL_WaylandTextInput *text_input = data; + if (!text_input->has_preedit) { + SDL_SendEditingText("", 0, 0); + } + text_input->has_preedit = SDL_FALSE; } static const struct zwp_text_input_v3_listener text_input_listener = { @@ -1529,6 +1686,363 @@ Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version) } } +static void +tablet_tool_handle_type(void* data, struct zwp_tablet_tool_v2* tool, uint32_t type) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_hardware_serial(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial_hi, uint32_t serial_lo) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_hardware_id_wacom(void* data, struct zwp_tablet_tool_v2* tool, uint32_t id_hi, uint32_t id_lo) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_capability(void* data, struct zwp_tablet_tool_v2* tool, uint32_t capability) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_done(void* data, struct zwp_tablet_tool_v2* tool) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_removed(void* data, struct zwp_tablet_tool_v2* tool) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_proximity_in(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, struct zwp_tablet_v2* tablet, struct wl_surface* surface) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window; + + if (!surface) { + return; + } + + if (!SDL_WAYLAND_own_surface(surface)) { + return; + } + + window = (SDL_WindowData*)wl_surface_get_user_data(surface); + + if (window) { + input->tool_focus = window; + input->tool_prox_serial = serial; + + input->is_down = SDL_FALSE; + + input->btn_stylus = SDL_FALSE; + input->btn_stylus2 = SDL_FALSE; + input->btn_stylus3 = SDL_FALSE; + + SDL_SetMouseFocus(window->sdlwindow); + SDL_SetCursor(NULL); + } +} + +static void +tablet_tool_handle_proximity_out(void* data, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + + if (input->tool_focus) { + SDL_SetMouseFocus(NULL); + input->tool_focus = NULL; + } +} + +uint32_t +tablet_tool_btn_to_sdl_button(struct SDL_WaylandTabletInput* input) +{ + unsigned int tool_btn = input->btn_stylus3 << 2 | input->btn_stylus2 << 1 | input->btn_stylus << 0; + switch (tool_btn) { + case 0b000: + return SDL_BUTTON_LEFT; + case 0b001: + return SDL_BUTTON_RIGHT; + case 0b010: + return SDL_BUTTON_MIDDLE; + case 0b100: + return SDL_BUTTON_X1; + default: + return SDL_BUTTON_LEFT; + } +} + +static void +tablet_tool_handle_down(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + input->is_down = SDL_TRUE; + if (!window) { + /* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd. + * that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still + * received. To prevent SIGSEGV this returns when this is the case. + */ + return; + } + + SDL_SendMouseButton(window->sdlwindow, 0, SDL_PRESSED, tablet_tool_btn_to_sdl_button(input)); +} + +static void +tablet_tool_handle_up(void* data, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + + input->is_down = SDL_FALSE; + + if (!window) { + /* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd. + * that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still + * received. To prevent SIGSEGV this returns when this is the case. + */ + return; + } + + SDL_SendMouseButton(window->sdlwindow, 0, SDL_RELEASED, tablet_tool_btn_to_sdl_button(input)); +} + +static void +tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + struct SDL_WaylandTabletInput* input = data; + SDL_WindowData* window = input->tool_focus; + + input->sx_w = sx_w; + input->sy_w = sy_w; + if (input->tool_focus) { + const float sx_f = (float)wl_fixed_to_double(sx_w); + const float sy_f = (float)wl_fixed_to_double(sy_w); + const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x); + const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y); + SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy); + } +} + +static void +tablet_tool_handle_pressure(void* data, struct zwp_tablet_tool_v2* tool, uint32_t pressure) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_distance(void* data, struct zwp_tablet_tool_v2* tool, uint32_t distance) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_tilt(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t xtilt, wl_fixed_t ytilt) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_button(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, uint32_t button, uint32_t state) +{ + struct SDL_WaylandTabletInput* input = data; + + if (input->is_down) { + tablet_tool_handle_up(data, tool); + input->is_down = SDL_TRUE; + } + + switch (button) { + /* see %{_includedir}/linux/input-event-codes.h */ + case 0x14b: /* BTN_STYLUS */ + input->btn_stylus = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + case 0x14c: /* BTN_STYLUS2 */ + input->btn_stylus2 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + case 0x149: /* BTN_STYLUS3 */ + input->btn_stylus3 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE; + break; + } + + if (input->is_down) { + tablet_tool_handle_down(data, tool, serial); + } +} + +static void +tablet_tool_handle_rotation(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t degrees) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_slider(void* data, struct zwp_tablet_tool_v2* tool, int32_t position) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_wheel(void* data, struct zwp_tablet_tool_v2* tool, int32_t degrees, int32_t clicks) +{ + /* unimplemented */ +} + +static void +tablet_tool_handle_frame(void* data, struct zwp_tablet_tool_v2* tool, uint32_t time) +{ + /* unimplemented */ +} + + +static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = { + tablet_tool_handle_type, + tablet_tool_handle_hardware_serial, + tablet_tool_handle_hardware_id_wacom, + tablet_tool_handle_capability, + tablet_tool_handle_done, + tablet_tool_handle_removed, + tablet_tool_handle_proximity_in, + tablet_tool_handle_proximity_out, + tablet_tool_handle_down, + tablet_tool_handle_up, + tablet_tool_handle_motion, + tablet_tool_handle_pressure, + tablet_tool_handle_distance, + tablet_tool_handle_tilt, + tablet_tool_handle_rotation, + tablet_tool_handle_slider, + tablet_tool_handle_wheel, + tablet_tool_handle_button, + tablet_tool_handle_frame +}; + +struct SDL_WaylandTabletObjectListNode* +tablet_object_list_new_node(void* object) +{ + struct SDL_WaylandTabletObjectListNode* node; + + node = SDL_calloc(1, sizeof *node); + if (node == NULL) { + return NULL; + } + + node->next = NULL; + node->object = object; + + return node; +} + +void tablet_object_list_append(struct SDL_WaylandTabletObjectListNode* head, void* object) +{ + if (head->object == NULL) { + head->object = object; + return; + } + + while (head->next) { + head = head->next; + } + + head->next = tablet_object_list_new_node(object); +} + +void tablet_object_list_destroy(struct SDL_WaylandTabletObjectListNode* head, void (*deleter)(void* object)) +{ + while (head) { + struct SDL_WaylandTabletObjectListNode* next = head->next; + if (head->object) { + (*deleter)(head->object); + } + SDL_free(head); + head = next; + } +} + + +static void +tablet_seat_handle_tablet_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_v2* tablet) +{ + struct SDL_WaylandTabletInput* input = data; + + tablet_object_list_append(input->tablets, tablet); +} + +static void +tablet_seat_handle_tool_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_tool_v2* tool) +{ + struct SDL_WaylandTabletInput* input = data; + + zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, data); + zwp_tablet_tool_v2_set_user_data(tool, data); + + tablet_object_list_append(input->tools, tool); +} + +static void +tablet_seat_handle_pad_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_pad_v2* pad) +{ + struct SDL_WaylandTabletInput* input = data; + + tablet_object_list_append(input->pads, pad); +} + +static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { + tablet_seat_handle_tablet_added, + tablet_seat_handle_tool_added, + tablet_seat_handle_pad_added +}; + +void +Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager) +{ + struct SDL_WaylandTabletInput* tablet_input; + + if (!tablet_manager || !input || !input->seat) { + return; + } + + tablet_input = SDL_calloc(1, sizeof *tablet_input); + if (tablet_input == NULL) { + return; + } + + input->tablet = tablet_input; + + tablet_input->seat = (struct SDL_WaylandTabletSeat*)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2*)tablet_manager, input->seat); + + tablet_input->tablets = tablet_object_list_new_node(NULL); + tablet_input->tools = tablet_object_list_new_node(NULL); + tablet_input->pads = tablet_object_list_new_node(NULL); + + zwp_tablet_seat_v2_add_listener((struct zwp_tablet_seat_v2*)tablet_input->seat, &tablet_seat_listener, tablet_input); +} + +#define TABLET_OBJECT_LIST_DELETER(fun) (void (*)(void*))fun +void +Wayland_input_destroy_tablet(struct SDL_WaylandInput* input) +{ + tablet_object_list_destroy(input->tablet->pads, TABLET_OBJECT_LIST_DELETER(zwp_tablet_pad_v2_destroy)); + tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy)); + tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy)); + + zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2*)input->tablet->seat); + + SDL_free(input->tablet); + input->tablet = NULL; +} + void Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) { @@ -1542,6 +2056,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version)); input->sx_w = wl_fixed_from_int(0); input->sy_w = wl_fixed_from_int(0); + input->xkb.current_group = ~0; d->input = input; if (d->data_device_manager != NULL) { @@ -1554,6 +2069,10 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version) wl_seat_add_listener(input->seat, &seat_listener, input); wl_seat_set_user_data(input->seat, input); + if (d->tablet_manager) { + Wayland_input_add_tablet(input, d->tablet_manager); + } + WAYLAND_wl_display_flush(d->display); } @@ -1594,6 +2113,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d) wl_touch_destroy(input->touch); } + if (input->tablet) { + Wayland_input_destroy_tablet(input); + } + if (input->seat) wl_seat_destroy(input->seat); @@ -1834,12 +2357,19 @@ int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *wi if (SDL_RectEmpty(&window->mouse_rect)) { confine_rect = NULL; } else { + SDL_Rect scaled_mouse_rect; + + scaled_mouse_rect.x = (int)SDL_floorf((float)window->mouse_rect.x / w->pointer_scale_x); + scaled_mouse_rect.y = (int)SDL_floorf((float)window->mouse_rect.y / w->pointer_scale_y); + scaled_mouse_rect.w = (int)SDL_ceilf((float)window->mouse_rect.w / w->pointer_scale_x); + scaled_mouse_rect.h = (int)SDL_ceilf((float)window->mouse_rect.h / w->pointer_scale_y); + confine_rect = wl_compositor_create_region(d->compositor); wl_region_add(confine_rect, - window->mouse_rect.x, - window->mouse_rect.y, - window->mouse_rect.w, - window->mouse_rect.h); + scaled_mouse_rect.x, + scaled_mouse_rect.y, + scaled_mouse_rect.w, + scaled_mouse_rect.h); } confined_pointer = diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 24256a7d0..59dc0c8af 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -29,6 +29,34 @@ #include "SDL_waylanddatamanager.h" #include "SDL_waylandkeyboard.h" +struct SDL_WaylandTabletSeat; + +struct SDL_WaylandTabletObjectListNode { + void* object; + struct SDL_WaylandTabletObjectListNode* next; +}; + +struct SDL_WaylandTabletInput { + struct SDL_WaylandTabletSeat* seat; + + struct SDL_WaylandTabletObjectListNode* tablets; + struct SDL_WaylandTabletObjectListNode* tools; + struct SDL_WaylandTabletObjectListNode* pads; + + SDL_WindowData *tool_focus; + uint32_t tool_prox_serial; + + /* Last motion location */ + wl_fixed_t sx_w; + wl_fixed_t sy_w; + + SDL_bool is_down; + + SDL_bool btn_stylus; + SDL_bool btn_stylus2; + SDL_bool btn_stylus3; +}; + typedef struct { // repeat_rate in range of [1, 1000] int32_t repeat_rate; @@ -68,6 +96,17 @@ struct SDL_WaylandInput { struct xkb_state *state; struct xkb_compose_table *compose_table; struct xkb_compose_state *compose_state; + + /* Keyboard layout "group" */ + uint32_t current_group; + + /* Modifier bitshift values */ + uint32_t idx_shift; + uint32_t idx_ctrl; + uint32_t idx_alt; + uint32_t idx_gui; + uint32_t idx_num; + uint32_t idx_caps; } xkb; /* information about axis events on current frame */ @@ -80,6 +119,8 @@ struct SDL_WaylandInput { } pointer_curr_axis_info; SDL_WaylandKeyboardRepeat keyboard_repeat; + + struct SDL_WaylandTabletInput* tablet; }; extern void Wayland_PumpEvents(_THIS); @@ -107,6 +148,9 @@ extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d); extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input); extern int Wayland_input_ungrab_keyboard(SDL_Window *window); +extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager); +extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input); + #endif /* SDL_waylandevents_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandkeyboard.h b/src/video/wayland/SDL_waylandkeyboard.h index dd8c146e6..604e0f37f 100644 --- a/src/video/wayland/SDL_waylandkeyboard.h +++ b/src/video/wayland/SDL_waylandkeyboard.h @@ -27,6 +27,7 @@ typedef struct SDL_WaylandTextInput { struct zwp_text_input_v3 *text_input; SDL_Rect cursor_rect; + SDL_bool has_preedit; } SDL_WaylandTextInput; extern int Wayland_InitKeyboard(_THIS); diff --git a/src/video/wayland/SDL_waylandopengles.c b/src/video/wayland/SDL_waylandopengles.c index 6b10cbee7..4c834fd86 100644 --- a/src/video/wayland/SDL_waylandopengles.c +++ b/src/video/wayland/SDL_waylandopengles.c @@ -205,11 +205,11 @@ Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h) data = (SDL_WindowData *) window->driverdata; if (w) { - *w = window->w * data->scale_factor; + *w = data->drawable_width; } if (h) { - *h = window->h * data->scale_factor; + *h = data->drawable_height; } } } diff --git a/src/video/wayland/SDL_waylandsym.h b/src/video/wayland/SDL_waylandsym.h index 366ce9e94..6891325c7 100644 --- a/src/video/wayland/SDL_waylandsym.h +++ b/src/video/wayland/SDL_waylandsym.h @@ -72,21 +72,19 @@ SDL_WAYLAND_SYM(void, wl_list_remove, (struct wl_list *)) SDL_WAYLAND_SYM(int, wl_list_length, (const struct wl_list *)) SDL_WAYLAND_SYM(int, wl_list_empty, (const struct wl_list *)) SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *)) - -/* These functions are available in Wayland >= 1.4 */ -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_MODULE(WAYLAND_CLIENT_1_18) SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *)) SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *)) -SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_20) +#if SDL_WAYLAND_CHECK_VERSION(1, 20, 0) +/* wayland-scanner 1.20 generates code that will call these, so these are + * non-optional when we are compiling against Wayland 1.20. We don't + * explicitly call them ourselves, though, so if we are only compiling + * against Wayland 1.18, they're unnecessary. */ SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interfac, uint32_t version, uint32_t flags, ...)) SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args)) +#endif SDL_WAYLAND_INTERFACE(wl_seat_interface) SDL_WAYLAND_INTERFACE(wl_surface_interface) @@ -122,6 +120,7 @@ SDL_WAYLAND_SYM(int, xkb_state_key_get_syms, (struct xkb_state *, xkb_keycode_t, SDL_WAYLAND_SYM(int, xkb_keysym_to_utf8, (xkb_keysym_t, char *, size_t) ) SDL_WAYLAND_SYM(struct xkb_keymap *, xkb_keymap_new_from_string, (struct xkb_context *, const char *, enum xkb_keymap_format, enum xkb_keymap_compile_flags)) SDL_WAYLAND_SYM(struct xkb_state *, xkb_state_new, (struct xkb_keymap *) ) +SDL_WAYLAND_SYM(int, xkb_keymap_key_repeats, (struct xkb_keymap *keymap, xkb_keycode_t key) ); SDL_WAYLAND_SYM(void, xkb_keymap_unref, (struct xkb_keymap *) ) SDL_WAYLAND_SYM(void, xkb_state_unref, (struct xkb_state *) ) SDL_WAYLAND_SYM(void, xkb_context_unref, (struct xkb_context *) ) @@ -148,6 +147,8 @@ SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *, xkb_layout_index_t, const xkb_keysym_t **) ) SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) ) +SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *, + const char *) ) #ifdef HAVE_LIBDECOR_H SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR) diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index f009fb7c6..0305c46a1 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -52,6 +52,9 @@ #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" +#include "tablet-unstable-v2-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -59,6 +62,9 @@ #define WAYLANDVID_DRIVER_NAME "wayland" +static void +display_handle_done(void *data, struct wl_output *output); + /* Initialization/Query functions */ static int Wayland_VideoInit(_THIS); @@ -133,32 +139,22 @@ static const char *SDL_WAYLAND_output_tag = "sdl-output"; void SDL_WAYLAND_register_surface(struct wl_surface *surface) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag); - } + wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag); } void SDL_WAYLAND_register_output(struct wl_output *output) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag); - } + wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag); } SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag; - } - return SDL_TRUE; /* For older clients we have to assume this is us... */ + return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag; } SDL_bool SDL_WAYLAND_own_output(struct wl_output *output) { - if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) { - return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag; - } - return SDL_TRUE; /* For older clients we have to assume this is us... */ + return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag; } static void @@ -230,6 +226,7 @@ Wayland_CreateDevice(int devindex) device->WaitEventTimeout = Wayland_WaitEventTimeout; device->SendWakeupEvent = Wayland_SendWakeupEvent; +#if SDL_VIDEO_OPENGL_EGL device->GL_SwapWindow = Wayland_GLES_SwapWindow; device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval; device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval; @@ -240,6 +237,7 @@ Wayland_CreateDevice(int devindex) device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary; device->GL_GetProcAddress = Wayland_GLES_GetProcAddress; device->GL_DeleteContext = Wayland_GLES_DeleteContext; +#endif device->CreateSDLWindow = Wayland_CreateWindow; device->ShowWindow = Wayland_ShowWindow; @@ -281,6 +279,8 @@ Wayland_CreateDevice(int devindex) device->free = Wayland_DeleteDevice; + device->disable_display_mode_switching = SDL_TRUE; + return device; } @@ -289,6 +289,155 @@ VideoBootStrap Wayland_bootstrap = { Wayland_CreateDevice }; +static void +xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, + int32_t x, int32_t y) +{ + SDL_WaylandOutputData* driverdata = data; + + driverdata->x = x; + driverdata->y = y; + driverdata->has_logical_position = SDL_TRUE; +} + +static void +xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, + int32_t width, int32_t height) +{ + SDL_WaylandOutputData* driverdata = data; + + if (driverdata->width != 0 && driverdata->height != 0) { + /* FIXME: GNOME has a bug where the logical size does not account for + * scale, resulting in bogus viewport sizes. + * + * Until this is fixed, validate that _some_ kind of scaling is being + * done (we can't match exactly because fractional scaling can't be + * detected otherwise), then override if necessary. + * -flibit + */ + const float scale = (float) driverdata->width / (float) width; + if ((scale == 1.0f) && (driverdata->scale_factor != 1.0f)) { + SDL_LogWarn( + SDL_LOG_CATEGORY_VIDEO, + "xdg_output scale did not match, overriding with wl_output scale" + ); + return; + } + } + + driverdata->width = width; + driverdata->height = height; + driverdata->has_logical_size = SDL_TRUE; +} + +static void +xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) +{ + SDL_WaylandOutputData* driverdata = data; + + /* + * xdg-output.done events are deprecated and only apply below version 3 of the protocol. + * A wl-output.done event will be emitted in version 3 or higher. + */ + if (zxdg_output_v1_get_version(driverdata->xdg_output) < 3) { + display_handle_done(data, driverdata->output); + } +} + +static void +xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output, + const char *name) +{ +} + +static void +xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output, + const char *description) +{ +} + +static const struct zxdg_output_v1_listener xdg_output_listener = { + xdg_output_handle_logical_position, + xdg_output_handle_logical_size, + xdg_output_handle_done, + xdg_output_handle_name, + xdg_output_handle_description, +}; + +static void +AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90) +{ + struct EmulatedMode + { + int w; + int h; + }; + + /* Resolution lists courtesy of XWayland */ + const struct EmulatedMode mode_list[] = { + /* 16:9 (1.77) */ + { 7680, 4320 }, + { 6144, 3160 }, + { 5120, 2880 }, + { 4096, 2304 }, + { 3840, 2160 }, + { 3200, 1800 }, + { 2880, 1620 }, + { 2560, 1440 }, + { 2048, 1152 }, + { 1920, 1080 }, + { 1600, 900 }, + { 1368, 768 }, + { 1280, 720 }, + { 864, 486 }, + + /* 16:10 (1.6) */ + { 2560, 1600 }, + { 1920, 1200 }, + { 1680, 1050 }, + { 1440, 900 }, + { 1280, 800 }, + + /* 3:2 (1.5) */ + { 720, 480 }, + + /* 4:3 (1.33) */ + { 2048, 1536 }, + { 1920, 1440 }, + { 1600, 1200 }, + { 1440, 1080 }, + { 1400, 1050 }, + { 1280, 1024 }, + { 1280, 960 }, + { 1152, 864 }, + { 1024, 768 }, + { 800, 600 }, + { 640, 480 } + }; + + int i; + const int native_width = dpy->display_modes->w; + const int native_height = dpy->display_modes->h; + + for (i = 0; i < SDL_arraysize(mode_list); ++i) { + /* Only add modes that are smaller than the native mode */ + if ((mode_list[i].w < native_width && mode_list[i].h < native_height) || + (mode_list[i].w < native_width && mode_list[i].h == native_height)) { + SDL_DisplayMode mode = *dpy->display_modes; + + if (rot_90) { + mode.w = mode_list[i].h; + mode.h = mode_list[i].w; + } else { + mode.w = mode_list[i].w; + mode.h = mode_list[i].h; + } + + SDL_AddDisplayMode(dpy, &mode); + } + } +} + static void display_handle_geometry(void *data, struct wl_output *output, @@ -305,7 +454,7 @@ display_handle_geometry(void *data, SDL_VideoDisplay *display; int i; - if (driverdata->done) { + if (driverdata->wl_output_done_count) { /* Clear the wl_output ref so Reset doesn't free it */ display = SDL_GetDisplay(driverdata->index); for (i = 0; i < display->num_display_modes; i += 1) { @@ -316,11 +465,14 @@ display_handle_geometry(void *data, SDL_ResetDisplayModes(driverdata->index); /* The display has officially started over. */ - driverdata->done = SDL_FALSE; + driverdata->wl_output_done_count = 0; } - driverdata->x = x; - driverdata->y = y; + /* Apply the change from wl-output only if xdg-output is not supported */ + if (!driverdata->has_logical_position) { + driverdata->x = x; + driverdata->y = y; + } driverdata->physical_width = physical_width; driverdata->physical_height = physical_height; if (driverdata->index == -1) { @@ -367,36 +519,21 @@ display_handle_mode(void *data, int refresh) { SDL_WaylandOutputData* driverdata = data; - SDL_DisplayMode mode; if (flags & WL_OUTPUT_MODE_CURRENT) { - /* Don't rotate this yet, handle_done will do it later */ - driverdata->width = width; - driverdata->height = height; - driverdata->refresh = refresh; - } + driverdata->native_width = width; + driverdata->native_height = height; + + /* + * Don't rotate this yet, wl-output coordinates are transformed in + * handle_done and xdg-output coordinates are pre-transformed. + */ + if (!driverdata->has_logical_size) { + driverdata->width = width; + driverdata->height = height; + } - /* Note that the width/height are NOT multiplied by scale_factor! - * This is intentional and is designed to get the unscaled modes, which is - * important for high-DPI games intending to use the display mode as the - * target drawable size. The scaled desktop mode will be added at the end - * when display_handle_done is called (see below). - */ - SDL_zero(mode); - mode.format = SDL_PIXELFORMAT_RGB888; - if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { - mode.w = height; - mode.h = width; - } else { - mode.w = width; - mode.h = height; - } - mode.refresh_rate = refresh / 1000; /* mHz to Hz */ - mode.driverdata = driverdata->output; - if (driverdata->index > -1) { - SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &mode); - } else { - SDL_AddDisplayMode(&driverdata->placeholder, &mode); + driverdata->refresh = refresh; } } @@ -405,20 +542,73 @@ display_handle_done(void *data, struct wl_output *output) { SDL_WaylandOutputData* driverdata = data; - SDL_DisplayMode mode; + SDL_VideoData* video = driverdata->videodata; + SDL_DisplayMode native_mode, desktop_mode; SDL_VideoDisplay *dpy; - if (driverdata->done) + /* + * When using xdg-output, two wl-output.done events will be emitted: + * one at the completion of wl-display and one at the completion of xdg-output. + * + * All required events must be received before proceeding. + */ + const int event_await_count = 1 + (driverdata->xdg_output != NULL); + + driverdata->wl_output_done_count = SDL_min(driverdata->wl_output_done_count + 1, event_await_count + 1); + + if (driverdata->wl_output_done_count != event_await_count) { return; + } - driverdata->done = SDL_TRUE; + /* The native display resolution */ + SDL_zero(native_mode); + native_mode.format = SDL_PIXELFORMAT_RGB888; - SDL_zero(mode); - mode.format = SDL_PIXELFORMAT_RGB888; if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { - mode.w = driverdata->height / driverdata->scale_factor; - mode.h = driverdata->width / driverdata->scale_factor; + native_mode.w = driverdata->native_height; + native_mode.h = driverdata->native_width; + } else { + native_mode.w = driverdata->native_width; + native_mode.h = driverdata->native_height; + } + native_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */ + native_mode.driverdata = driverdata->output; + + /* The scaled desktop mode */ + SDL_zero(desktop_mode); + desktop_mode.format = SDL_PIXELFORMAT_RGB888; + /* Scale the desktop coordinates, if xdg-output isn't present */ + if (!driverdata->has_logical_size) { + driverdata->width /= driverdata->scale_factor; + driverdata->height /= driverdata->scale_factor; + } + + /* xdg-output dimensions are already transformed, so no need to rotate. */ + if (driverdata->has_logical_size || !(driverdata->transform & WL_OUTPUT_TRANSFORM_90)) { + desktop_mode.w = driverdata->width; + desktop_mode.h = driverdata->height; + } else { + desktop_mode.w = driverdata->height; + desktop_mode.h = driverdata->width; + } + desktop_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */ + desktop_mode.driverdata = driverdata->output; + + /* + * The native display mode is only exposed separately from the desktop size if: + * the desktop is scaled and the wp_viewporter protocol is supported. + */ + if (driverdata->scale_factor > 1.0f && video->viewporter != NULL) { + if (driverdata->index > -1) { + SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &native_mode); + } else { + SDL_AddDisplayMode(&driverdata->placeholder, &native_mode); + } + } + + /* Calculate the display DPI */ + if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) { driverdata->hdpi = driverdata->physical_height ? (((float) driverdata->height) * 25.4f / driverdata->physical_height) : 0.0f; @@ -430,9 +620,6 @@ display_handle_done(void *data, ((float) driverdata->physical_height) / 25.4f, ((float) driverdata->physical_width) / 25.4f); } else { - mode.w = driverdata->width / driverdata->scale_factor; - mode.h = driverdata->height / driverdata->scale_factor; - driverdata->hdpi = driverdata->physical_width ? (((float) driverdata->width) * 25.4f / driverdata->physical_width) : 0.0f; @@ -444,8 +631,6 @@ display_handle_done(void *data, ((float) driverdata->physical_width) / 25.4f, ((float) driverdata->physical_height) / 25.4f); } - mode.refresh_rate = driverdata->refresh / 1000; /* mHz to Hz */ - mode.driverdata = driverdata->output; if (driverdata->index > -1) { dpy = SDL_GetDisplay(driverdata->index); @@ -453,9 +638,14 @@ display_handle_done(void *data, dpy = &driverdata->placeholder; } - SDL_AddDisplayMode(dpy, &mode); - SDL_SetCurrentDisplayMode(dpy, &mode); - SDL_SetDesktopDisplayMode(dpy, &mode); + SDL_AddDisplayMode(dpy, &desktop_mode); + SDL_SetCurrentDisplayMode(dpy, &desktop_mode); + SDL_SetDesktopDisplayMode(dpy, &desktop_mode); + + /* Add emulated modes if wp_viewporter is supported. */ + if (video->viewporter) { + AddEmulatedModes(dpy, (driverdata->transform & WL_OUTPUT_TRANSFORM_90) != 0); + } if (driverdata->index == -1) { /* First time getting display info, create the VideoDisplay */ @@ -502,11 +692,29 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id) data->videodata = d; data->output = output; data->registry_id = id; - data->scale_factor = 1.0; + data->scale_factor = 1.0f; data->index = -1; wl_output_add_listener(output, &output_listener, data); SDL_WAYLAND_register_output(output); + + /* Keep a list of outputs for deferred xdg-output initialization. */ + if (d->output_list != NULL) { + SDL_WaylandOutputData *node = (SDL_WaylandOutputData*)d->output_list; + + while (node->next != NULL) { + node = (SDL_WaylandOutputData*)node->next; + } + + node->next = (struct SDL_WaylandOutputData*)data; + } else { + d->output_list = (struct SDL_WaylandOutputData*)data; + } + + if (data->videodata->xdg_output_manager) { + data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output); + zxdg_output_v1_add_listener(data->xdg_output, &xdg_output_listener, data); + } } static void @@ -522,6 +730,9 @@ Wayland_free_display(uint32_t id) data = (SDL_WaylandOutputData *) display->driverdata; if (data->registry_id == id) { SDL_DelVideoDisplay(i); + if (data->xdg_output) { + zxdg_output_v1_destroy(data->xdg_output); + } wl_output_destroy(data->output); SDL_free(data); @@ -538,6 +749,16 @@ Wayland_free_display(uint32_t id) } } +static void +Wayland_init_xdg_output(SDL_VideoData *d) +{ + SDL_WaylandOutputData *node; + for (node = d->output_list; node != NULL; node = node->next) { + node->xdg_output = zxdg_output_manager_v1_get_xdg_output(node->videodata->xdg_output_manager, node->output); + zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node); + } +} + #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager, @@ -598,7 +819,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, } else if (SDL_strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id, version); } else if (SDL_strcmp(interface, "xdg_wm_base") == 0) { - d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1); + d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3)); xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL); } else if (SDL_strcmp(interface, "wl_shm") == 0) { d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); @@ -618,6 +839,17 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id, Wayland_add_data_device_manager(d, id, version); } else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) { d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1); + } else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) { + d->tablet_manager = wl_registry_bind(d->registry, id, &zwp_tablet_manager_v2_interface, 1); + if (d->input) { + Wayland_input_add_tablet(d->input, d->tablet_manager); + } + } else if (SDL_strcmp(interface, "zxdg_output_manager_v1") == 0) { + version = SDL_min(version, 3); /* Versions 1 through 3 are supported. */ + d->xdg_output_manager = wl_registry_bind(d->registry, id, &zxdg_output_manager_v1_interface, version); + Wayland_init_xdg_output(d); + } else if (SDL_strcmp(interface, "wp_viewporter") == 0) { + d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1); #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (SDL_strcmp(interface, "qt_touch_extension") == 0) { @@ -644,6 +876,29 @@ static const struct wl_registry_listener registry_listener = { display_handle_global, display_remove_global }; + +#ifdef HAVE_LIBDECOR_H +static SDL_bool should_use_libdecor(SDL_VideoData *data) +{ + if (!SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR) { + return SDL_FALSE; + } + + if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) { + return SDL_FALSE; + } + + if (SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR, SDL_FALSE)) { + return SDL_TRUE; + } + + if (data->decoration_manager) { + return SDL_FALSE; + } + + return SDL_TRUE; +} +#endif int Wayland_VideoInit(_THIS) @@ -667,14 +922,8 @@ Wayland_VideoInit(_THIS) #ifdef HAVE_LIBDECOR_H /* Don't have server-side decorations? Try client-side instead. */ - if (!data->decoration_manager && SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR && SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) { + if (should_use_libdecor(data)) { data->shell.libdecor = libdecor_new(data->display, &libdecor_interface); - - /* If libdecor works, we don't need xdg-shell anymore. */ - if (data->shell.libdecor && data->shell.xdg) { - xdg_wm_base_destroy(data->shell.xdg); - data->shell.xdg = NULL; - } } #endif @@ -735,6 +984,10 @@ Wayland_VideoQuit(_THIS) for (i = 0; i < _this->num_displays; ++i) { SDL_VideoDisplay *display = &_this->displays[i]; + if (((SDL_WaylandOutputData*)display->driverdata)->xdg_output) { + zxdg_output_v1_destroy(((SDL_WaylandOutputData*)display->driverdata)->xdg_output); + } + wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output); SDL_free(display->driverdata); display->driverdata = NULL; @@ -777,6 +1030,9 @@ Wayland_VideoQuit(_THIS) Wayland_touch_destroy(data); #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + if (data->tablet_manager) + zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager); + if (data->data_device_manager) wl_data_device_manager_destroy(data->data_device_manager); @@ -796,6 +1052,14 @@ Wayland_VideoQuit(_THIS) } #endif + if (data->xdg_output_manager) { + zxdg_output_manager_v1_destroy(data->xdg_output_manager); + } + + if (data->viewporter) { + wp_viewporter_destroy(data->viewporter); + } + if (data->compositor) wl_compositor_destroy(data->compositor); diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index 31168a9d5..6f941db80 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -34,6 +34,7 @@ struct xkb_context; struct SDL_WaylandInput; +struct SDL_WaylandTabletManager; #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch; @@ -46,6 +47,8 @@ typedef struct { int size; } SDL_WaylandCursorTheme; +typedef struct SDL_WaylandOutputData SDL_WaylandOutputData; + typedef struct { SDL_bool initializing; struct wl_display *display; @@ -70,6 +73,8 @@ typedef struct { struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager; struct xdg_activation_v1 *activation_manager; struct zwp_text_input_manager_v3 *text_input_manager; + struct zxdg_output_manager_v1 *xdg_output_manager; + struct wp_viewporter *viewporter; EGLDisplay edpy; EGLContext context; @@ -77,6 +82,8 @@ typedef struct { struct xkb_context *xkb_context; struct SDL_WaylandInput *input; + struct SDL_WaylandTabletManager *tablet_manager; + SDL_WaylandOutputData *output_list; #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch *touch; @@ -89,19 +96,23 @@ typedef struct { int relative_mouse_mode; } SDL_VideoData; -typedef struct { +struct SDL_WaylandOutputData { SDL_VideoData *videodata; struct wl_output *output; + struct zxdg_output_v1 *xdg_output; uint32_t registry_id; float scale_factor; + int native_width, native_height; int x, y, width, height, refresh, transform; SDL_DisplayOrientation orientation; int physical_width, physical_height; float ddpi, hdpi, vdpi; + SDL_bool has_logical_position, has_logical_size; int index; SDL_VideoDisplay placeholder; - SDL_bool done; -} SDL_WaylandOutputData; + int wl_output_done_count; + SDL_WaylandOutputData *next; +}; /* Needed here to get wl_surface declaration, fixes GitHub#4594 */ #include "SDL_waylanddyn.h" diff --git a/src/video/wayland/SDL_waylandvulkan.c b/src/video/wayland/SDL_waylandvulkan.c index eb4435131..90b318fc8 100644 --- a/src/video/wayland/SDL_waylandvulkan.c +++ b/src/video/wayland/SDL_waylandvulkan.c @@ -139,11 +139,11 @@ void Wayland_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h) data = (SDL_WindowData *) window->driverdata; if (w) { - *w = window->w * data->scale_factor; + *w = data->drawable_width; } if (h) { - *h = window->h * data->scale_factor; + *h = data->drawable_height; } } } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 3eae22bf7..0bbae4691 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -21,33 +21,314 @@ #include "../../SDL_internal.h" -#if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL +#if SDL_VIDEO_DRIVER_WAYLAND #include "../SDL_sysvideo.h" #include "../../events/SDL_windowevents_c.h" +#include "../../events/SDL_mouse_c.h" #include "../SDL_egl_c.h" #include "SDL_waylandevents_c.h" #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" #include "SDL_hints.h" +#include "SDL_events.h" #include "xdg-shell-client-protocol.h" #include "xdg-decoration-unstable-v1-client-protocol.h" #include "idle-inhibit-unstable-v1-client-protocol.h" #include "xdg-activation-v1-client-protocol.h" +#include "viewporter-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include #endif static void -CommitMinMaxDimensions(SDL_Window *window) +GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height) +{ + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + int fs_width, fs_height; + int buf_width, buf_height; + + /* + * Fullscreen desktop mandates a desktop sized window, so that's what applications will get. + * If the application is DPI aware, it will need to handle the transformations between the + * differently sized window and backbuffer spaces on its own. + */ + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { + fs_width = output->width; + fs_height = output->height; + + /* If the application is DPI aware, we can expose the true backbuffer size */ + if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + buf_width = output->native_width; + buf_height = output->native_height; + } else { + buf_width = fs_width; + buf_height = fs_height; + } + } else { + /* + * If a mode was set, use it, otherwise use the native resolution + * for DPI aware apps and the desktop size for legacy apps. + */ + if (window->fullscreen_mode.w != 0 && window->fullscreen_mode.h != 0) { + fs_width = window->fullscreen_mode.w; + fs_height = window->fullscreen_mode.h; + } else if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + fs_width = output->native_width; + fs_height = output->native_height; + } else { + fs_width = output->width; + fs_height = output->height; + } + + buf_width = fs_width; + buf_height = fs_height; + } + + if (width) { + *width = fs_width; + } + if (height) { + *height = fs_height; + } + if (drawable_width) { + *drawable_width = buf_width; + } + if (drawable_height) { + *drawable_height = buf_height; + } +} + +static inline SDL_bool +DesktopIsScaled(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + + return data->scale_factor != 1.0f; +} + +static inline SDL_bool +DesktopIsFractionalScaled(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + if ((output->native_width != (int)(output->width * data->scale_factor) || + output->native_height != (int)(output->height * data->scale_factor))) { + return SDL_TRUE; + } + + return SDL_FALSE; +} + +static SDL_bool +NeedFullscreenViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *video = data->waylandData; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + int fs_width, fs_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL); + + /* + * Fullscreen needs a viewport: + * - If the desktop uses fractional scaling + * - Fullscreen desktop was not requested OR the window is DPI aware + * + * - The desktop uses non-fractional scaling + * - Fullscreen desktop was NOT requested + * + * - The desktop is not scaled + * - A non-native fullscreen mode was explicitly set by the client + */ + if (video->viewporter != NULL && (window->flags & SDL_WINDOW_FULLSCREEN)) { + if (DesktopIsFractionalScaled(window)) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP || + (window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) { + return SDL_TRUE; + } + } else if (DesktopIsScaled(window)) { + if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) { + return SDL_TRUE; + } + } else if (fs_width != output->native_width && fs_height != output->native_height) { + return SDL_TRUE; + } + } + + return SDL_FALSE; +} + +static inline SDL_bool +NeedWindowedViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *video = data->waylandData; + + return !(window->flags & SDL_WINDOW_FULLSCREEN) && (video->viewporter != NULL) && + DesktopIsFractionalScaled(window) && (window->flags & SDL_WINDOW_ALLOW_HIGHDPI); +} + +/* Never set a fullscreen window size larger than the desktop. */ +SDL_FORCE_INLINE int +GetWindowWidth(SDL_Window *window) +{ + return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->width : window->w; +} + +SDL_FORCE_INLINE int +GetWindowHeight(SDL_Window *window) +{ + return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->height : window->h; +} + +static void +GetWindowBufferSize(SDL_Window *window, int *width, int *height) +{ + SDL_WindowData *data = window->driverdata; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + int buf_width; + int buf_height; + + if (NeedWindowedViewport(window)) { + const float frac_scale_x = (float)output->native_width / (float)output->width; + const float frac_scale_y = (float)output->native_height / (float)output->height; + + buf_width = (int)SDL_lroundf(window->w * frac_scale_x); + buf_height = (int)SDL_lroundf(window->h * frac_scale_y); + } else { /* Windowed or fullscreen with no viewport */ + buf_width = window->w * data->scale_factor; + buf_height = window->h * data->scale_factor; + } + + if (width) { + *width = buf_width; + } + if (height) { + *height = buf_height; + } +} + +static void +SetViewport(SDL_Window *window, int src_width, int src_height, int dst_width, int dst_height) +{ + SDL_WindowData *wind = window->driverdata; + SDL_VideoData *video = wind->waylandData; + + if (video->viewporter) { + if (wind->viewport == NULL) { + wind->viewport = wp_viewporter_get_viewport(video->viewporter, wind->surface); + } + + wp_viewport_set_source(wind->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(src_width), wl_fixed_from_int(src_height)); + wp_viewport_set_destination(wind->viewport, dst_width, dst_height); + } +} + +static void +UnsetViewport(SDL_Window *window) +{ + SDL_WindowData *wind = window->driverdata; + + if (wind->viewport) { + wp_viewport_destroy(wind->viewport); + wind->viewport = NULL; + } +} + +static void +ConfigureViewport(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + SDL_VideoData *viddata = data->waylandData; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + + if (NeedFullscreenViewport(window)) { + int fs_width, fs_height; + int src_width, src_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, &src_width, &src_height); + SetViewport(window, src_width, src_height, output->width, output->height); + + data->damage_region.x = 0; + data->damage_region.y = 0; + data->damage_region.w = output->width; + data->damage_region.h = output->height; + + data->pointer_scale_x = (float)fs_width / (float)output->width; + data->pointer_scale_y = (float)fs_height / (float)output->height; + } else { + if (NeedWindowedViewport(window)) { + int src_width, src_height; + + GetWindowBufferSize(window, &src_width, &src_height); + SetViewport(window, src_width, src_height, window->w, window->h); + } else { + UnsetViewport(window); + } + + SDL_zero(data->damage_region); + + data->pointer_scale_x = 1.0f; + data->pointer_scale_y = 1.0f; + } + + /* + * If mouse_rect is not empty, re-create the confinement region with the new scale value. + * If the pointer is locked to the general surface with unspecified coordinates, it will + * be confined to the viewport region, so no update is required. + */ + if (!SDL_RectEmpty(&window->mouse_rect)) { + Wayland_input_confine_pointer(viddata->input, window); + } +} + +static void +SetDrawScale(SDL_Window *window) +{ + SDL_WindowData *data = window->driverdata; + + if (NeedFullscreenViewport(window)) { + int fs_width, fs_height; + + GetFullScreenDimensions(window, &fs_width, &fs_height, &data->drawable_width, &data->drawable_height); + + /* Set the buffer scale to 1 since a viewport will be used. */ + wl_surface_set_buffer_scale(data->surface, 1); + } else { + GetWindowBufferSize(window, &data->drawable_width, &data->drawable_height); + + if (NeedWindowedViewport(window)) { + /* Set the buffer scale to 1 since a viewport will be used. */ + wl_surface_set_buffer_scale(data->surface, 1); + } else { + wl_surface_set_buffer_scale(data->surface, (int32_t)data->scale_factor); + } + } +} + +static void +SetMinMaxDimensions(SDL_Window *window, SDL_bool commit) { SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = wind->waylandData; int min_width, min_height, max_width, max_height; + /* Pop-ups don't get to change size */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + if (window->flags & SDL_WINDOW_FULLSCREEN) { min_width = 0; min_height = 0; @@ -66,7 +347,7 @@ CommitMinMaxDimensions(SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -88,23 +369,34 @@ CommitMinMaxDimensions(SDL_Window *window) xdg_toplevel_set_max_size(wind->shell_surface.xdg.roleobj.toplevel, max_width, max_height); - wl_surface_commit(wind->surface); + if (commit) { + wl_surface_commit(wind->surface); + } } } static void -SetFullscreen(SDL_Window *window, struct wl_output *output) +SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit) { SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = wind->waylandData; + /* Pop-ups don't get to be fullscreened */ + if (WINDOW_IS_XDG_POPUP(window)) { + /* ... but we still want to commit, particularly for ShowWindow */ + if (commit) { + wl_surface_commit(wind->surface); + } + return; + } + /* The desktop may try to enforce min/max sizes here, so turn them off for * fullscreen and on (if applicable) for windowed */ - CommitMinMaxDimensions(window); + SetMinMaxDimensions(window, SDL_FALSE); #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -134,6 +426,9 @@ SetFullscreen(SDL_Window *window, struct wl_output *output) } else { xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel); } + if (commit) { + wl_surface_commit(wind->surface); + } } } @@ -145,6 +440,11 @@ handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) SDL_WindowData *wind = (SDL_WindowData *) data; SDL_AtomicSet(&wind->swap_interval_ready, 1); /* mark window as ready to present again. */ + if (!SDL_RectEmpty(&wind->damage_region)) { + wl_surface_damage(wind->surface, wind->damage_region.x, wind->damage_region.y, + wind->damage_region.w, wind->damage_region.h); + } + /* reset this callback to fire again once a new frame was presented and compositor wants the next one. */ wind->frame_callback = wl_surface_frame(wind->frame_surface_wrapper); wl_callback_destroy(cb); @@ -215,7 +515,7 @@ handle_configure_xdg_toplevel(void *data, if (!fullscreen) { if (window->flags & SDL_WINDOW_FULLSCREEN) { /* We might need to re-enter fullscreen after being restored from minimized */ - SetFullscreen(window, driverdata->output); + SetFullscreen(window, driverdata->output, SDL_FALSE); /* Foolishly do what the compositor says here. If it's wrong, don't * blame us, we were explicitly instructed to do this. @@ -224,14 +524,16 @@ handle_configure_xdg_toplevel(void *data, * us a completely stateless, sizeless configure, with which we have * to enforce our own state anyway. */ - if (width != 0 && height != 0) { + if (width != 0 && height != 0 && (window->w != width || window->h != height)) { window->w = width; window->h = height; + wind->needs_resize_event = SDL_TRUE; } /* This part is good though. */ - if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) && wind->scale_factor != driverdata->scale_factor) { wind->scale_factor = driverdata->scale_factor; + wind->needs_resize_event = SDL_TRUE; } return; @@ -284,8 +586,11 @@ handle_configure_xdg_toplevel(void *data, } /* Store this now so the xdg_surface configure knows what to resize to */ - window->w = width; - window->h = height; + if (window->w != width || window->h != height) { + window->w = width; + window->h = height; + wind->needs_resize_event = SDL_TRUE; + } } else { /* For fullscreen, foolishly do what the compositor says. If it's wrong, * don't blame us, we were explicitly instructed to do this. @@ -293,14 +598,21 @@ handle_configure_xdg_toplevel(void *data, * UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug: * https://bugs.kde.org/show_bug.cgi?id=444962 */ - if (width != 0 && height != 0) { - window->w = width; - window->h = height; + if (!NeedFullscreenViewport(window)) { + if (width != 0 && height != 0 && (window->w != width || window->h != height)) { + window->w = width; + window->h = height; + wind->needs_resize_event = SDL_TRUE; + } + } else { + GetFullScreenDimensions(window, &window->w, &window->h, NULL, NULL); + wind->needs_resize_event = SDL_TRUE; } /* This part is good though. */ - if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { + if ((window->flags & SDL_WINDOW_ALLOW_HIGHDPI) && wind->scale_factor != driverdata->scale_factor) { wind->scale_factor = driverdata->scale_factor; + wind->needs_resize_event = SDL_TRUE; } } } @@ -317,6 +629,60 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = { handle_close_xdg_toplevel }; +static void +handle_configure_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + /* No-op, we don't use x/y and width/height are fixed-size */ +} + +static void +handle_done_xdg_popup(void *data, struct xdg_popup *xdg_popup) +{ + SDL_WindowData *window = (SDL_WindowData *)data; + SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0); +} + +static void +handle_repositioned_xdg_popup(void *data, + struct xdg_popup *xdg_popup, + uint32_t token) +{ + /* No-op, configure does all the work we care about */ +} + +static const struct xdg_popup_listener popup_listener_xdg = { + handle_configure_xdg_popup, + handle_done_xdg_popup, + handle_repositioned_xdg_popup +}; + +#define TOOLTIP_CURSOR_OFFSET 8 /* FIXME: Arbitrary, eyeballed from X tooltip */ + +static int +Wayland_PopupWatch(void *data, SDL_Event *event) +{ + if (event->type == SDL_MOUSEMOTION) { + SDL_Window *window = (SDL_Window *) data; + SDL_WindowData *wind = window->driverdata; + + /* Coordinates might be relative to the popup, which we don't want */ + if (event->motion.windowID == wind->shell_surface.xdg.roleobj.popup.parentID) { + xdg_positioner_set_offset(wind->shell_surface.xdg.roleobj.popup.positioner, + event->motion.x + TOOLTIP_CURSOR_OFFSET, + event->motion.y + TOOLTIP_CURSOR_OFFSET); + xdg_popup_reposition(wind->shell_surface.xdg.roleobj.popup.popup, + wind->shell_surface.xdg.roleobj.popup.positioner, + 0); + } + } + return 1; +} + #ifdef HAVE_LIBDECOR_H static void decoration_frame_configure(struct libdecor_frame *frame, @@ -330,6 +696,7 @@ decoration_frame_configure(struct libdecor_frame *frame, enum libdecor_window_state window_state; int width, height; + float scale_factor = wind->scale_factor; SDL_bool focused = SDL_FALSE; SDL_bool fullscreen = SDL_FALSE; @@ -356,7 +723,7 @@ decoration_frame_configure(struct libdecor_frame *frame, if (!fullscreen) { if (window->flags & SDL_WINDOW_FULLSCREEN) { /* We might need to re-enter fullscreen after being restored from minimized */ - SetFullscreen(window, driverdata->output); + SetFullscreen(window, driverdata->output, SDL_FALSE); fullscreen = SDL_TRUE; floating = SDL_FALSE; } @@ -386,24 +753,31 @@ decoration_frame_configure(struct libdecor_frame *frame, * Always assume the configure is wrong. */ if (fullscreen) { - /* FIXME: We have been explicitly told to respect the fullscreen size - * parameters here, even though they are known to be wrong on GNOME at - * bare minimum. If this is wrong, don't blame us, we were explicitly - * told to do this. - */ - if (!libdecor_configuration_get_content_size(configuration, frame, - &width, &height)) { - width = window->w; - height = window->h; + if (!NeedFullscreenViewport(window)) { + /* FIXME: We have been explicitly told to respect the fullscreen size + * parameters here, even though they are known to be wrong on GNOME at + * bare minimum. If this is wrong, don't blame us, we were explicitly + * told to do this. + */ + if (!libdecor_configuration_get_content_size(configuration, frame, + &width, &height)) { + width = window->w; + height = window->h; + } + } else { + GetFullScreenDimensions(window, &width, &height, NULL, NULL); } + wind->needs_resize_event = SDL_TRUE; + /* This part is good though. */ if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { - wind->scale_factor = driverdata->scale_factor; + scale_factor = driverdata->scale_factor; } - } else if (!(window->flags & SDL_WINDOW_RESIZABLE)) { + } else if (!(window->flags & SDL_WINDOW_RESIZABLE) || (floating && wind->floating_resize_pending)) { width = window->windowed.w; height = window->windowed.h; + wind->floating_resize_pending = SDL_FALSE; } else { /* This will never set 0 for width/height unless the function returns false */ if (!libdecor_configuration_get_content_size(configuration, frame, &width, &height)) { @@ -427,11 +801,11 @@ decoration_frame_configure(struct libdecor_frame *frame, } /* Do the resize on the SDL side (this will set window->w/h)... */ - Wayland_HandleResize(window, width, height, wind->scale_factor); + Wayland_HandleResize(window, width, height, scale_factor); wind->shell_surface.libdecor.initial_configure_seen = SDL_TRUE; /* ... then commit the changes on the libdecor side. */ - state = libdecor_state_new(width, height); + state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); libdecor_frame_commit(frame, state, configuration); libdecor_state_free(state); @@ -540,9 +914,28 @@ Wayland_move_window(SDL_Window *window, int i, numdisplays = SDL_GetNumVideoDisplays(); for (i = 0; i < numdisplays; i += 1) { if (SDL_GetDisplay(i)->driverdata == driverdata) { - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, - SDL_WINDOWPOS_CENTERED_DISPLAY(i), - SDL_WINDOWPOS_CENTERED_DISPLAY(i)); + /* We want to send a very very specific combination here: + * + * 1. A coordinate that tells the application what display we're on + * 2. Exactly (0, 0) + * + * Part 1 is useful information but is also really important for + * ensuring we end up on the right display for fullscreen, while + * part 2 is important because numerous applications use a specific + * combination of GetWindowPosition and GetGlobalMouseState, and of + * course neither are supported by Wayland. Since global mouse will + * fall back to just GetMouseState, we need the window position to + * be zero so the cursor math works without it going off in some + * random direction. See UE5 Editor for a notable example of this! + * + * This may be an issue some day if we're ever able to implement + * SDL_GetDisplayUsableBounds! + * + * -flibit + */ + SDL_Rect bounds; + SDL_GetDisplayBounds(i, &bounds); + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, bounds.x, bounds.y); break; } } @@ -610,6 +1003,19 @@ static const struct wl_surface_listener surface_listener = { handle_surface_leave }; +static void +Wayland_FillEmptyShellInfo(SDL_SysWMinfo * info, const Uint32 version) +{ + info->info.wl.xdg_surface = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = NULL; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } +} + SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { @@ -642,23 +1048,40 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) info->info.wl.egl_window = data->egl_window; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor && data->shell_surface.libdecor.frame != NULL) { - info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (WINDOW_IS_LIBDECOR(viddata, window)) { + if (data->shell_surface.libdecor.frame != NULL) { + info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 17)) { + info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame); + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } + } else { + /* Not mapped yet */ + Wayland_FillEmptyShellInfo(info, version); } } else #endif if (viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) { info->info.wl.xdg_surface = data->shell_surface.xdg.surface; if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = data->shell_surface.xdg.roleobj.toplevel; + SDL_bool popup = WINDOW_IS_XDG_POPUP(window); + info->info.wl.xdg_toplevel = popup ? NULL : data->shell_surface.xdg.roleobj.toplevel; + if (version >= SDL_VERSIONNUM(2, 0, 22)) { + if (popup) { + info->info.wl.xdg_popup = data->shell_surface.xdg.roleobj.popup.popup; + info->info.wl.xdg_positioner = data->shell_surface.xdg.roleobj.popup.positioner; + } else { + info->info.wl.xdg_popup = NULL; + info->info.wl.xdg_positioner = NULL; + } + } } } else { - info->info.wl.xdg_surface = NULL; - if (version >= SDL_VERSIONNUM(2, 0, 17)) { - info->info.wl.xdg_toplevel = NULL; - } + /* Either it's not mapped yet or we don't have a shell protocol */ + Wayland_FillEmptyShellInfo(info, version); } } @@ -683,6 +1106,10 @@ Wayland_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_wi SDL_WindowData *modal_data = modal_window->driverdata; SDL_WindowData *parent_data = parent_window->driverdata; + if (WINDOW_IS_XDG_POPUP(modal_window) || WINDOW_IS_XDG_POPUP(parent_window)) { + return SDL_SetError("Modal/Parent was a popup, not a toplevel"); + } + #ifdef HAVE_LIBDECOR_H if (viddata->shell.libdecor) { if (modal_data->shell_surface.libdecor.frame == NULL) { @@ -716,17 +1143,27 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) { SDL_VideoData *c = _this->driverdata; SDL_WindowData *data = window->driverdata; - SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); /* Detach any previous buffers before resetting everything, otherwise when - * calling this a second time you'll get an annoying protocol error + * calling this a second time you'll get an annoying protocol error! + * + * FIXME: This was originally moved to HideWindow, which _should_ make + * sense, but for whatever reason UE5's popups require that this actually + * be in both places at once? Possibly from renderers making commits? I can't + * fully remember if this location caused crashes or if I was fixing a pair + * of Hide/Show calls. In any case, UE gives us a pretty good test and having + * both detach calls passes. This bug may be relevant if I'm wrong: + * + * https://bugs.kde.org/show_bug.cgi?id=448856 + * + * -flibit */ wl_surface_attach(data->surface, NULL, 0, 0); wl_surface_commit(data->surface); - /* Create the shell surface and map the toplevel */ + /* Create the shell surface and map the toplevel/popup */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor, data->surface, &libdecor_frame_interface, @@ -744,10 +1181,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) xdg_surface_set_user_data(data->shell_surface.xdg.surface, data); xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data); - /* !!! FIXME: add popup role */ - data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); - xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); - xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + if (WINDOW_IS_XDG_POPUP(window)) { + SDL_Mouse *mouse = SDL_GetMouse(); + SDL_Window *focused = SDL_GetMouseFocus(); + SDL_WindowData *focuseddata = focused->driverdata; + + /* This popup may be a child of another popup! */ + data->shell_surface.xdg.roleobj.popup.parentID = SDL_GetWindowID(focused); + data->shell_surface.xdg.roleobj.popup.child = NULL; + if (WINDOW_IS_XDG_POPUP(focused)) { + SDL_assert(focuseddata->shell_surface.xdg.roleobj.popup.child == NULL); + focuseddata->shell_surface.xdg.roleobj.popup.child = window; + } + + /* Set up the positioner for the popup */ + data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg); + xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner, + mouse->x + TOOLTIP_CURSOR_OFFSET, + mouse->y + TOOLTIP_CURSOR_OFFSET); + + /* Assign the popup role */ + data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface, + focuseddata->shell_surface.xdg.surface, + data->shell_surface.xdg.roleobj.popup.positioner); + xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data); + + /* For tooltips, track mouse motion so it follows the cursor */ + if (window->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(data->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_AddEventWatch(Wayland_PopupWatch, window); + } + } + } else { + data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface); + xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname); + xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data); + } } /* Restore state that was set prior to this call */ @@ -758,13 +1227,12 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) if (window->flags & SDL_WINDOW_MINIMIZED) { Wayland_MinimizeWindow(_this, window); } - Wayland_SetWindowFullscreen(_this, window, display, (window->flags & SDL_WINDOW_FULLSCREEN) != 0); /* We have to wait until the surface gets a "configure" event, or use of * this surface will fail. This is a new rule for xdg_shell. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { if (data->shell_surface.libdecor.frame) { while (!data->shell_surface.libdecor.initial_configure_seen) { WAYLAND_wl_display_flush(c->display); @@ -774,6 +1242,12 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } else #endif if (c->shell.xdg) { + /* Unlike libdecor we need to call this explicitly to prevent a deadlock. + * libdecor will call this as part of their configure event! + * -flibit + */ + SDL_WaylandOutputData *odata = SDL_GetDisplayForWindow(window)->driverdata; + SetFullscreen(window, (window->flags & SDL_WINDOW_FULLSCREEN) ? odata->output : NULL, SDL_TRUE); if (data->shell_surface.xdg.surface) { while (!data->shell_surface.xdg.initial_configure_seen) { WAYLAND_wl_display_flush(c->display); @@ -782,9 +1256,12 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } /* Create the window decorations */ - if (data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { + if (!WINDOW_IS_XDG_POPUP(window) && data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) { data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel); } + } else { + /* Nothing to see here, just commit. */ + wl_surface_commit(data->surface); } /* Unlike the rest of window state we have to set this _after_ flushing the @@ -792,11 +1269,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) * them immediately afterward. */ #ifdef HAVE_LIBDECOR_H - if (c->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(c, window)) { /* ... but don't call it redundantly for libdecor, the decorator * may not interpret a redundant call nicely and cause weird stuff to happen */ - if (window->flags & SDL_WINDOW_BORDERLESS) { + if (data->shell_surface.libdecor.frame && window->flags & SDL_WINDOW_BORDERLESS) { Wayland_SetWindowBordered(_this, window, SDL_FALSE); } } else @@ -822,6 +1299,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window) } } +static void +Wayland_ReleasePopup(_THIS, SDL_Window *popup) +{ + SDL_WindowData *popupdata; + + /* Basic sanity checks to weed out the weird popup closures */ + if (popup == NULL || popup->magic != &_this->window_magic) { + return; + } + popupdata = popup->driverdata; + if (popupdata == NULL) { + return; + } + + /* This may already be freed by a parent popup! */ + if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) { + return; + } + + /* Release the child _first_, otherwise a protocol error triggers */ + if (popupdata->shell_surface.xdg.roleobj.popup.child != NULL) { + Wayland_ReleasePopup(_this, popupdata->shell_surface.xdg.roleobj.popup.child); + popupdata->shell_surface.xdg.roleobj.popup.child = NULL; + } + + if (popup->flags & SDL_WINDOW_TOOLTIP) { + if (xdg_popup_get_version(popupdata->shell_surface.xdg.roleobj.popup.popup) >= 3) { + SDL_DelEventWatch(Wayland_PopupWatch, popup); + } + } + xdg_popup_destroy(popupdata->shell_surface.xdg.roleobj.popup.popup); + xdg_positioner_destroy(popupdata->shell_surface.xdg.roleobj.popup.positioner); + popupdata->shell_surface.xdg.roleobj.popup.popup = NULL; + popupdata->shell_surface.xdg.roleobj.popup.positioner = NULL; +} + void Wayland_HideWindow(_THIS, SDL_Window *window) { SDL_VideoData *data = _this->driverdata; @@ -833,7 +1346,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_unref(wind->shell_surface.libdecor.frame); wind->shell_surface.libdecor.frame = NULL; @@ -841,7 +1354,9 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) } else #endif if (data->shell.xdg) { - if (wind->shell_surface.xdg.roleobj.toplevel) { + if (WINDOW_IS_XDG_POPUP(window)) { + Wayland_ReleasePopup(_this, window); + } else if (wind->shell_surface.xdg.roleobj.toplevel) { xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel); wind->shell_surface.xdg.roleobj.toplevel = NULL; } @@ -850,6 +1365,10 @@ void Wayland_HideWindow(_THIS, SDL_Window *window) wind->shell_surface.xdg.surface = NULL; } } + + /* Be sure to detach after this is done, otherwise ShowWindow crashes! */ + wl_surface_attach(wind->surface, NULL, 0, 0); + wl_surface_commit(wind->surface); } static void @@ -1043,7 +1562,7 @@ Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, { struct wl_output *output = ((SDL_WaylandOutputData*) _display->driverdata)->output; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; - SetFullscreen(window, fullscreen ? output : NULL); + SetFullscreen(window, fullscreen ? output : NULL, SDL_TRUE); WAYLAND_wl_display_flush(viddata->display); } @@ -1054,13 +1573,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + /* Set this flag now even if we never actually maximized, eventually * ShowWindow will take care of it along with the other window state. */ window->flags &= ~SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1083,8 +1606,13 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) { SDL_WindowData *wind = window->driverdata; const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata; + + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame) { libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered); } @@ -1103,7 +1631,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) SDL_VideoData *data = _this->driverdata; const SDL_WindowData *wind = window->driverdata; - if (data->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(data, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1115,7 +1643,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable) } else #endif { - CommitMinMaxDimensions(window); + SetMinMaxDimensions(window, SDL_TRUE); } } @@ -1125,6 +1653,10 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (!(window->flags & SDL_WINDOW_RESIZABLE)) { return; } @@ -1135,7 +1667,7 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window) window->flags |= SDL_WINDOW_MAXIMIZED; #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1158,8 +1690,12 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1250,7 +1786,9 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) data->waylandData = c; data->sdlwindow = window; - data->scale_factor = 1.0; + data->scale_factor = 1.0f; + data->pointer_scale_x = 1.0f; + data->pointer_scale_y = 1.0f; if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { int i; @@ -1297,16 +1835,20 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + data->drawable_width = window->w * data->scale_factor; + data->drawable_height = window->h * data->scale_factor; + if (window->flags & SDL_WINDOW_OPENGL) { - data->egl_window = WAYLAND_wl_egl_window_create(data->surface, - window->w * data->scale_factor, window->h * data->scale_factor); + data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height); +#if SDL_VIDEO_OPENGL_EGL /* Create the GLES window surface */ data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window); if (data->egl_surface == EGL_NO_SURFACE) { - return SDL_SetError("failed to create an EGL window surface"); + return -1; /* SDL_EGL_CreateSurface should have set error */ } +#endif } #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @@ -1326,7 +1868,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window) Wayland_input_lock_pointer(c->input); } - wl_surface_commit(data->surface); + /* Moved this call to ShowWindow: wl_surface_commit(data->surface); */ WAYLAND_wl_display_flush(c->display); /* We may need to create an idle inhibitor for this new window */ @@ -1341,21 +1883,26 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; SDL_VideoData *viddata = data->waylandData; - struct wl_region *region; - window->w = 0; - window->h = 0; - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height); - window->w = width; - window->h = height; - data->scale_factor = scale; - wl_surface_set_buffer_scale(data->surface, data->scale_factor); + if (data->needs_resize_event || window->w != width || window->h != height || data->scale_factor != scale) { + /* We may have already updated window w/h (or only adjusted scale factor), + * so we must override the deduplication logic in the video core */ + window->w = 0; + window->h = 0; + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, width, height); + window->w = width; + window->h = height; + data->needs_resize_event = SDL_FALSE; + } + + /* Configure the backbuffer size and scale factors */ + SetDrawScale(window); if (data->egl_window) { WAYLAND_wl_egl_window_resize(data->egl_window, - window->w * data->scale_factor, - window->h * data->scale_factor, + data->drawable_width, + data->drawable_height, 0, 0); } @@ -1369,21 +1916,30 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale) * It doesn't fix the first frames after resize being glitched visually, * but at least lets us not be terminated by the compositor. * Can be removed once SDL's resize logic becomes compliant. */ - if (viddata->shell.xdg && data->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, window->w, window->h); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(viddata, window) && +#endif + viddata->shell.xdg && + data->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } + + /* Update the viewport */ + ConfigureViewport(window); } void Wayland_SetWindowMinimumSize(_THIS, SDL_Window * window) { - CommitMinMaxDimensions(window); + SetMinMaxDimensions(window, SDL_TRUE); } void Wayland_SetWindowMaximumSize(_THIS, SDL_Window * window) { - CommitMinMaxDimensions(window); + SetMinMaxDimensions(window, SDL_TRUE); } void Wayland_SetWindowSize(_THIS, SDL_Window * window) @@ -1397,25 +1953,27 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) #ifdef HAVE_LIBDECOR_H /* we must not resize the window while we have a static (non-floating) size */ - if (data->shell.libdecor && + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame && !libdecor_frame_is_floating(wind->shell_surface.libdecor.frame)) { + /* Commit the resize when we re-enter floating state */ + wind->floating_resize_pending = SDL_TRUE; return; } #endif - wl_surface_set_buffer_scale(wind->surface, wind->scale_factor); + SetDrawScale(window); if (wind->egl_window) { WAYLAND_wl_egl_window_resize(wind->egl_window, - window->w * wind->scale_factor, - window->h * wind->scale_factor, + wind->drawable_width, + wind->drawable_height, 0, 0); } #ifdef HAVE_LIBDECOR_H - if (data->shell.libdecor && wind->shell_surface.libdecor.frame) { - state = libdecor_state_new(window->w, window->h); + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) { + state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); libdecor_state_free(state); } @@ -1431,8 +1989,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window) wl_region_destroy(region); /* Update the geometry which may have been set by a hack in Wayland_HandleResize */ - if (data->shell.xdg && wind->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, window->w, window->h); + if ( +#ifdef HAVE_LIBDECOR_H + !WINDOW_IS_LIBDECOR(data, window) && +#endif + data->shell.xdg && + wind->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); } } @@ -1441,9 +2005,13 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window) SDL_WindowData *wind = window->driverdata; SDL_VideoData *viddata = _this->driverdata; + if (WINDOW_IS_XDG_POPUP(window)) { + return; + } + if (window->title != NULL) { #ifdef HAVE_LIBDECOR_H - if (viddata->shell.libdecor) { + if (WINDOW_IS_LIBDECOR(viddata, window)) { if (wind->shell_surface.libdecor.frame == NULL) { return; /* Can't do anything yet, wait for ShowWindow */ } @@ -1505,9 +2073,11 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) SDL_WindowData *wind = window->driverdata; if (data) { +#if SDL_VIDEO_OPENGL_EGL if (wind->egl_surface) { SDL_EGL_DestroySurface(_this, wind->egl_surface); } +#endif if (wind->egl_window) { WAYLAND_wl_egl_window_destroy(wind->egl_window); } @@ -1520,6 +2090,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) xdg_activation_token_v1_destroy(wind->activation_token); } + if (wind->viewport) { + wp_viewport_destroy(wind->viewport); + } + SDL_free(wind->outputs); if (wind->frame_callback) { @@ -1543,6 +2117,6 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window) window->driverdata = NULL; } -#endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */ +#endif /* SDL_VIDEO_DRIVER_WAYLAND */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index 8ca090f0c..b1ba98cf9 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -36,16 +36,27 @@ typedef struct { struct xdg_surface *surface; union { struct xdg_toplevel *toplevel; - struct xdg_popup *popup; + struct { + struct xdg_popup *popup; + struct xdg_positioner *positioner; + Uint32 parentID; + SDL_Window *child; + } popup; } roleobj; SDL_bool initial_configure_seen; } SDL_xdg_shell_surface; +#define WINDOW_IS_XDG_POPUP(window) \ + (window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)) + #ifdef HAVE_LIBDECOR_H typedef struct { struct libdecor_frame *frame; SDL_bool initial_configure_seen; } SDL_libdecor_surface; + +#define WINDOW_IS_LIBDECOR(viddata, window) \ + (viddata->shell.libdecor && !WINDOW_IS_XDG_POPUP(window)) #endif typedef struct { @@ -63,13 +74,16 @@ typedef struct { } shell_surface; struct wl_egl_window *egl_window; struct SDL_WaylandInput *keyboard_device; +#if SDL_VIDEO_OPENGL_EGL EGLSurface egl_surface; +#endif struct zwp_locked_pointer_v1 *locked_pointer; struct zwp_confined_pointer_v1 *confined_pointer; struct zxdg_toplevel_decoration_v1 *server_decoration; struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor; struct zwp_idle_inhibitor_v1 *idle_inhibitor; struct xdg_activation_token_v1 *activation_token; + struct wp_viewport *viewport; /* floating dimensions for restoring from maximized and fullscreen */ int floating_width, floating_height; @@ -84,6 +98,12 @@ typedef struct { int num_outputs; float scale_factor; + float pointer_scale_x; + float pointer_scale_y; + int drawable_width, drawable_height; + SDL_Rect damage_region; + SDL_bool needs_resize_event; + SDL_bool floating_resize_pending; } SDL_WindowData; extern void Wayland_ShowWindow(_THIS, SDL_Window *window); diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 471bbee86..ebd0dd1f9 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -40,6 +40,11 @@ /* For GET_X_LPARAM, GET_Y_LPARAM. */ #include +/* For WM_TABLET_QUERYSYSTEMGESTURESTATUS et. al. */ +#if HAVE_TPCSHRD_H +#include +#endif /* HAVE_TPCSHRD_H */ + /* #define WMMSG_DEBUG */ #ifdef WMMSG_DEBUG #include @@ -369,18 +374,18 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data) if (!(keyState & 0x8000)) { WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0); } - data->mouse_button_flags = 0; + data->mouse_button_flags = (WPARAM)-1; } static void -WIN_UpdateFocus(SDL_Window *window) +WIN_UpdateFocus(SDL_Window *window, SDL_bool expect_focus) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; HWND hwnd = data->hwnd; SDL_bool had_focus = (SDL_GetKeyboardFocus() == window) ? SDL_TRUE : SDL_FALSE; SDL_bool has_focus = (GetForegroundWindow() == hwnd) ? SDL_TRUE : SDL_FALSE; - if (had_focus == has_focus) { + if (had_focus == has_focus || has_focus != expect_focus) { return; } @@ -681,7 +686,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without actually being the foreground window, but this appears to get called in all cases where the global foreground window changes to and from this window. */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, !!wParam); WIN_CheckICMProfileChanged(data->window); } break; @@ -689,16 +694,22 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_ACTIVATE: { /* Update the focus in case we changed focus to a child window and then away from the application */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, !!LOWORD(wParam)); } break; case WM_SETFOCUS: + { + /* Update the focus in case it's changing between top-level windows in the same application */ + WIN_UpdateFocus(data->window, SDL_TRUE); + } + break; + case WM_KILLFOCUS: case WM_ENTERIDLE: { /* Update the focus in case it's changing between top-level windows in the same application */ - WIN_UpdateFocus(data->window); + WIN_UpdateFocus(data->window, SDL_FALSE); } break; @@ -732,8 +743,8 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } } } - /* don't break here, fall through to check the wParam like the button presses */ - SDL_FALLTHROUGH; + break; + case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: @@ -1162,10 +1173,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0); break; - default: + case SIZE_RESTORED: SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESTORED, 0, 0); break; + default: + break; } } break; @@ -1285,6 +1298,25 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } break; +#if HAVE_TPCSHRD_H + + case WM_TABLET_QUERYSYSTEMGESTURESTATUS: + /* See https://msdn.microsoft.com/en-us/library/windows/desktop/bb969148(v=vs.85).aspx . + * If we're handling our own touches, we don't want any gestures. + * Not all of these settings are documented. + * The use of the undocumented ones was suggested by https://github.com/bjarkeck/GCGJ/blob/master/Monogame/Windows/WinFormsGameForm.cs . */ + return TABLET_DISABLE_PRESSANDHOLD | /* disables press and hold (right-click) gesture */ + TABLET_DISABLE_PENTAPFEEDBACK | /* disables UI feedback on pen up (waves) */ + TABLET_DISABLE_PENBARRELFEEDBACK | /* disables UI feedback on pen button down (circle) */ + TABLET_DISABLE_TOUCHUIFORCEON | + TABLET_DISABLE_TOUCHUIFORCEOFF | + TABLET_DISABLE_TOUCHSWITCH | + TABLET_DISABLE_FLICKS | /* disables pen flicks (back, forward, drag down, drag up) */ + TABLET_DISABLE_SMOOTHSCROLLING | + TABLET_DISABLE_FLICKFALLBACKKEYS; + +#endif /* HAVE_TPCSHRD_H */ + case WM_DROPFILES: { UINT i; @@ -1555,6 +1587,14 @@ LPTSTR SDL_Appname = NULL; Uint32 SDL_Appstyle = 0; HINSTANCE SDL_Instance = NULL; +static void WIN_CleanRegisterApp(WNDCLASSEX wcex) +{ + if (wcex.hIcon) DestroyIcon(wcex.hIcon); + if (wcex.hIconSm) DestroyIcon(wcex.hIconSm); + SDL_free(SDL_Appname); + SDL_Appname = NULL; +} + /* Register the class for this application */ int SDL_RegisterApp(const char *name, Uint32 style, void *hInst) @@ -1568,19 +1608,16 @@ SDL_RegisterApp(const char *name, Uint32 style, void *hInst) ++app_registered; return (0); } - if (!name && !SDL_Appname) { + SDL_assert(SDL_Appname == NULL); + if (!name) { name = "SDL_app"; #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC) - SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC); + style = (CS_BYTEALIGNCLIENT | CS_OWNDC); #endif - SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); - } - - if (name) { - SDL_Appname = WIN_UTF8ToString(name); - SDL_Appstyle = style; - SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); } + SDL_Appname = WIN_UTF8ToString(name); + SDL_Appstyle = style; + SDL_Instance = hInst ? hInst : GetModuleHandle(NULL); /* Register the application class */ wcex.cbSize = sizeof(WNDCLASSEX); @@ -1611,6 +1648,7 @@ SDL_RegisterApp(const char *name, Uint32 style, void *hInst) } if (!RegisterClassEx(&wcex)) { + WIN_CleanRegisterApp(wcex); return SDL_SetError("Couldn't register application class"); } @@ -1630,14 +1668,14 @@ SDL_UnregisterApp() } --app_registered; if (app_registered == 0) { + /* Ensure the icons are initialized. */ + wcex.hIcon = NULL; + wcex.hIconSm = NULL; /* Check for any registered window classes. */ 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; + WIN_CleanRegisterApp(wcex); } } diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c index 929032516..b9874a543 100644 --- a/src/video/windows/SDL_windowskeyboard.c +++ b/src/video/windows/SDL_windowskeyboard.c @@ -36,6 +36,8 @@ static void IME_Init(SDL_VideoData *videodata, HWND hwnd); static void IME_Enable(SDL_VideoData *videodata, HWND hwnd); static void IME_Disable(SDL_VideoData *videodata, HWND hwnd); static void IME_Quit(SDL_VideoData *videodata); +static void IME_ClearComposition(SDL_VideoData *videodata); +static SDL_bool IME_IsTextInputShown(SDL_VideoData* videodata); #endif /* !SDL_DISABLE_WINDOWS_IME */ #ifndef MAPVK_VK_TO_VSC @@ -62,12 +64,14 @@ WIN_InitKeyboard(_THIS) data->ime_hwnd_main = 0; data->ime_hwnd_current = 0; data->ime_himc = 0; + data->ime_composition_length = 32 * sizeof(WCHAR); + data->ime_composition = (WCHAR*)SDL_malloc(data->ime_composition_length); data->ime_composition[0] = 0; data->ime_readingstring[0] = 0; data->ime_cursor = 0; data->ime_candlist = SDL_FALSE; - SDL_memset(data->ime_candidates, 0, sizeof(data->ime_candidates)); + data->ime_candidates = NULL; data->ime_candcount = 0; data->ime_candref = 0; data->ime_candsel = 0; @@ -272,14 +276,17 @@ WIN_SetTextInputRect(_THIS, SDL_Rect *rect) } } -static SDL_bool -WIN_ShouldShowNativeUI() -{ - return SDL_GetHintBoolean(SDL_HINT_IME_SHOW_UI, SDL_FALSE); -} #ifdef SDL_DISABLE_WINDOWS_IME +void WIN_ClearComposition(_THIS) +{ +} + +SDL_bool WIN_IsTextInputShown(_THIS) +{ + return SDL_FALSE; +} SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoData *videodata) @@ -349,6 +356,7 @@ DEFINE_GUID(IID_ITfThreadMgrEx, 0x3E90ADE3,0x7594 #define SUBLANG() SUBLANGID(LANG()) static void IME_UpdateInputLocale(SDL_VideoData *videodata); +static int IME_ShowCandidateList(SDL_VideoData *videodata); static void IME_ClearComposition(SDL_VideoData *videodata); static void IME_SetWindow(SDL_VideoData* videodata, HWND hwnd); static void IME_SetupAPI(SDL_VideoData *videodata); @@ -361,6 +369,12 @@ static void UILess_ReleaseSinks(SDL_VideoData *videodata); static void UILess_EnableUIUpdates(SDL_VideoData *videodata); static void UILess_DisableUIUpdates(SDL_VideoData *videodata); +static SDL_bool +WIN_ShouldShowNativeUI() +{ + return SDL_GetHintBoolean(SDL_HINT_IME_SHOW_UI, SDL_FALSE); +} + static void IME_Init(SDL_VideoData *videodata, HWND hwnd) { @@ -587,16 +601,16 @@ IME_GetId(SDL_VideoData *videodata, UINT uIndex) char szTemp[256]; HKL hkl = 0; DWORD dwLang = 0; - if (uIndex >= sizeof(dwRet) / sizeof(dwRet[0])) - return 0; + SDL_assert(uIndex < sizeof(dwRet) / sizeof(dwRet[0])); hkl = videodata->ime_hkl; if (hklprev == hkl) return dwRet[uIndex]; - hklprev = hkl; + + SDL_assert(uIndex == 0); dwLang = ((DWORD_PTR)hkl & 0xffff); - if (videodata->ime_uiless && LANG() == LANG_CHT) { + if (videodata->ime_uiless && dwLang == LANG_CHT) { dwRet[0] = IMEID_CHT_VER_VISTA; dwRet[1] = 0; return dwRet[0]; @@ -607,11 +621,11 @@ IME_GetId(SDL_VideoData *videodata, UINT uIndex) && hkl != CHT_HKL_HK_CANTONESE && hkl != CHS_HKL) { dwRet[0] = dwRet[1] = 0; - return dwRet[uIndex]; + return dwRet[0]; } if (ImmGetIMEFileNameA(hkl, szTemp, sizeof(szTemp) - 1) <= 0) { dwRet[0] = dwRet[1] = 0; - return dwRet[uIndex]; + return dwRet[0]; } if (!videodata->GetReadingString) { #define LCID_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) @@ -621,7 +635,7 @@ IME_GetId(SDL_VideoData *videodata, UINT uIndex) && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME1, -1) != 2 && CompareStringA(LCID_INVARIANT, NORM_IGNORECASE, szTemp, -1, CHS_IMEFILENAME2, -1) != 2) { dwRet[0] = dwRet[1] = 0; - return dwRet[uIndex]; + return dwRet[0]; } #undef LCID_INVARIANT dwVerSize = GetFileVersionInfoSizeA(szTemp, &dwVerHandle); @@ -660,7 +674,7 @@ IME_GetId(SDL_VideoData *videodata, UINT uIndex) } } dwRet[0] = dwRet[1] = 0; - return dwRet[uIndex]; + return dwRet[0]; } static void @@ -712,26 +726,13 @@ IME_SetWindow(SDL_VideoData* videodata, HWND hwnd) static void IME_UpdateInputLocale(SDL_VideoData *videodata) { - static HKL hklprev = 0; - videodata->ime_hkl = GetKeyboardLayout(0); - if (hklprev == videodata->ime_hkl) - return; + HKL hklnext = GetKeyboardLayout(0); - hklprev = videodata->ime_hkl; - switch (PRIMLANG()) { - case LANG_CHINESE: - videodata->ime_candvertical = SDL_TRUE; - if (SUBLANG() == SUBLANG_CHINESE_SIMPLIFIED) - videodata->ime_candvertical = SDL_FALSE; + if (hklnext == videodata->ime_hkl) + return; - break; - case LANG_JAPANESE: - videodata->ime_candvertical = SDL_TRUE; - break; - case LANG_KOREAN: - videodata->ime_candvertical = SDL_FALSE; - break; - } + videodata->ime_hkl = hklnext; + videodata->ime_candvertical = (PRIMLANG() == LANG_KOREAN || LANG() == LANG_CHS) ? SDL_FALSE : SDL_TRUE; } static void @@ -754,18 +755,48 @@ IME_ClearComposition(SDL_VideoData *videodata) SDL_SendEditingText("", 0, 0); } +static SDL_bool +IME_IsTextInputShown(SDL_VideoData* videodata) +{ + if (!videodata->ime_initialized || !videodata->ime_available || !videodata->ime_enabled) + return SDL_FALSE; + + return videodata->ime_uicontext != 0 ? SDL_TRUE : SDL_FALSE; +} + static void IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) { - LONG length = ImmGetCompositionStringW(himc, string, videodata->ime_composition, sizeof(videodata->ime_composition) - sizeof(videodata->ime_composition[0])); + LONG length; + DWORD dwLang = ((DWORD_PTR)videodata->ime_hkl & 0xffff); + + length = ImmGetCompositionStringW(himc, string, NULL, 0); + if (length > 0 && videodata->ime_composition_length < length) { + if (videodata->ime_composition != NULL) + SDL_free(videodata->ime_composition); + + videodata->ime_composition = (WCHAR*)SDL_malloc(length + sizeof(WCHAR)); + videodata->ime_composition_length = length; + } + + length = ImmGetCompositionStringW( + himc, + string, + videodata->ime_composition, + videodata->ime_composition_length + ); + if (length < 0) length = 0; - length /= sizeof(videodata->ime_composition[0]); + length /= sizeof(WCHAR); videodata->ime_cursor = LOWORD(ImmGetCompositionStringW(himc, GCS_CURSORPOS, 0, 0)); - if (videodata->ime_cursor > 0 && - videodata->ime_cursor < SDL_arraysize(videodata->ime_composition) && - videodata->ime_composition[videodata->ime_cursor] == 0x3000) { + if ((dwLang == LANG_CHT || dwLang == LANG_CHS) && + videodata->ime_cursor > 0 && + videodata->ime_cursor < (int)(videodata->ime_composition_length / sizeof(WCHAR)) && + (videodata->ime_composition[0] == 0x3000 || videodata->ime_composition[0] == 0x0020)) { + // Traditional Chinese IMEs add a placeholder U+3000 + // Simplified Chinese IMEs seem to add a placeholder U+0020 sometimes int i; for (i = videodata->ime_cursor + 1; i < length; ++i) videodata->ime_composition[i - 1] = videodata->ime_composition[i]; @@ -774,6 +805,39 @@ IME_GetCompositionString(SDL_VideoData *videodata, HIMC himc, DWORD string) } videodata->ime_composition[length] = 0; + + // Get the correct caret position if we've selected a candidate from the candidate window + if (videodata->ime_cursor == 0 && length > 0) { + Sint32 start = 0; + Sint32 end = 0; + + length = ImmGetCompositionStringW(himc, GCS_COMPATTR, NULL, 0); + if (length > 0) { + Uint8* attributes = (Uint8*)SDL_malloc(length); + ImmGetCompositionString(himc, GCS_COMPATTR, attributes, length); + + for (start = 0; start < length; ++start) { + if (attributes[start] == ATTR_TARGET_CONVERTED || + attributes[start] == ATTR_TARGET_NOTCONVERTED) + break; + } + + for (end = start; end < length; ++end) { + if (attributes[end] != ATTR_TARGET_CONVERTED && + attributes[end] != ATTR_TARGET_NOTCONVERTED) + break; + } + + if (start == length) { + start = 0; + end = length; + } + + SDL_free(attributes); + } + + videodata->ime_cursor = end; + } } static void @@ -792,48 +856,66 @@ IME_SendInputEvent(SDL_VideoData *videodata) static void IME_SendEditingEvent(SDL_VideoData *videodata) { - char *s = 0; - WCHAR buffer[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; - const size_t size = SDL_arraysize(buffer); - buffer[0] = 0; + char *s = NULL; + WCHAR *buffer = NULL; + size_t size = videodata->ime_composition_length; if (videodata->ime_readingstring[0]) { size_t len = SDL_min(SDL_wcslen(videodata->ime_composition), (size_t)videodata->ime_cursor); + + size += sizeof(videodata->ime_readingstring); + buffer = (WCHAR*)SDL_malloc(size); + buffer[0] = 0; + SDL_wcslcpy(buffer, videodata->ime_composition, len + 1); SDL_wcslcat(buffer, videodata->ime_readingstring, size); SDL_wcslcat(buffer, &videodata->ime_composition[len], size); } else { + buffer = (WCHAR*)SDL_malloc(size); + buffer[0] = 0; SDL_wcslcpy(buffer, videodata->ime_composition, size); } + s = WIN_StringToUTF8W(buffer); SDL_SendEditingText(s, videodata->ime_cursor + (int)SDL_wcslen(videodata->ime_readingstring), 0); SDL_free(s); + SDL_free(buffer); } static void IME_AddCandidate(SDL_VideoData *videodata, UINT i, LPCWSTR candidate) { - LPWSTR dst = videodata->ime_candidates[i]; + LPWSTR dst = &videodata->ime_candidates[i * MAX_CANDLENGTH]; + LPWSTR end = &dst[MAX_CANDLENGTH - 1]; + SDL_COMPILE_TIME_ASSERT(IME_CANDIDATE_INDEXING_REQUIRES, MAX_CANDLIST == 10); *dst++ = (WCHAR)(TEXT('0') + ((i + videodata->ime_candlistindexbase) % 10)); if (videodata->ime_candvertical) *dst++ = TEXT(' '); - while (*candidate && (SDL_arraysize(videodata->ime_candidates[i]) > (dst - videodata->ime_candidates[i]))) + while (*candidate && dst < end) *dst++ = *candidate++; *dst = (WCHAR)'\0'; } static void -IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata) +IME_GetCandidateList(HWND hwnd, SDL_VideoData *videodata) { - LPCANDIDATELIST cand_list = 0; - DWORD size = ImmGetCandidateListW(himc, 0, 0, 0); - if (size) { + HIMC himc; + DWORD size; + LPCANDIDATELIST cand_list; + + if (IME_ShowCandidateList(videodata) < 0) + return; + himc = ImmGetContext(hwnd); + if (!himc) + return; + size = ImmGetCandidateListW(himc, 0, 0, 0); + if (size != 0) { cand_list = (LPCANDIDATELIST)SDL_malloc(size); - if (cand_list) { + if (cand_list != NULL) { size = ImmGetCandidateListW(himc, 0, cand_list, size); - if (size) { + if (size != 0) { UINT i, j; UINT page_start = 0; videodata->ime_candsel = cand_list->dwSelection; @@ -858,34 +940,44 @@ IME_GetCandidateList(HIMC himc, SDL_VideoData *videodata) } videodata->ime_candpgsize = i - page_start; } else { - videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize, MAX_CANDLIST); - if (videodata->ime_candpgsize > 0) { - page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize; - } else { - page_start = 0; - } + videodata->ime_candpgsize = SDL_min(cand_list->dwPageSize == 0 ? MAX_CANDLIST : cand_list->dwPageSize, MAX_CANDLIST); + page_start = (cand_list->dwSelection / videodata->ime_candpgsize) * videodata->ime_candpgsize; } - SDL_memset(&videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); - for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < (int)videodata->ime_candpgsize; i++, j++) { + for (i = page_start, j = 0; (DWORD)i < cand_list->dwCount && j < videodata->ime_candpgsize; i++, j++) { LPCWSTR candidate = (LPCWSTR)((DWORD_PTR)cand_list + cand_list->dwOffset[i]); IME_AddCandidate(videodata, j, candidate); } - if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0))) - videodata->ime_candsel = -1; + // TODO: why was this necessary? check ime_candvertical instead? PRIMLANG() never equals LANG_CHT ! + //if (PRIMLANG() == LANG_KOREAN || (PRIMLANG() == LANG_CHT && !IME_GetId(videodata, 0))) + // videodata->ime_candsel = -1; } SDL_free(cand_list); } } + ImmReleaseContext(hwnd, himc); } -static void +static int IME_ShowCandidateList(SDL_VideoData *videodata) { + void *candidates; + + videodata->ime_candcount = 0; + candidates = SDL_realloc(videodata->ime_candidates, MAX_CANDSIZE); + if (candidates != NULL) + videodata->ime_candidates = (WCHAR *)candidates; + + if (videodata->ime_candidates == NULL) + return -1; + + SDL_memset(videodata->ime_candidates, 0, MAX_CANDSIZE); + videodata->ime_dirty = SDL_TRUE; videodata->ime_candlist = SDL_TRUE; IME_DestroyTextures(videodata); IME_SendEditingEvent(videodata); + return 0; } static void @@ -906,6 +998,15 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD return SDL_FALSE; switch (msg) { + case WM_KEYDOWN: + if (wParam == VK_PROCESSKEY) + { + videodata->ime_uicontext = 1; + trap = SDL_TRUE; + } + else + videodata->ime_uicontext = 0; + break; case WM_INPUTLANGCHANGE: IME_InputLangChanged(videodata); break; @@ -914,14 +1015,17 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD *lParam = 0; } break; - case WM_IME_STARTCOMPOSITION: + case WM_IME_STARTCOMPOSITION: + videodata->ime_suppress_endcomposition_event = SDL_FALSE; trap = SDL_TRUE; break; case WM_IME_COMPOSITION: trap = SDL_TRUE; himc = ImmGetContext(hwnd); if (*lParam & GCS_RESULTSTR) { + videodata->ime_suppress_endcomposition_event = SDL_TRUE; IME_GetCompositionString(videodata, himc, GCS_RESULTSTR); + SDL_SendEditingText("", 0, 0); IME_SendInputEvent(videodata); } if (*lParam & GCS_COMPSTR) { @@ -934,10 +1038,13 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD ImmReleaseContext(hwnd, himc); break; case WM_IME_ENDCOMPOSITION: + videodata->ime_uicontext = 0; videodata->ime_composition[0] = 0; videodata->ime_readingstring[0] = 0; videodata->ime_cursor = 0; - SDL_SendEditingText("", 0, 0); + if (videodata->ime_suppress_endcomposition_event == SDL_FALSE) + SDL_SendEditingText("", 0, 0); + videodata->ime_suppress_endcomposition_event = SDL_FALSE; break; case WM_IME_NOTIFY: switch (wParam) { @@ -951,16 +1058,12 @@ IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, SDL_VideoD break; trap = SDL_TRUE; - IME_ShowCandidateList(videodata); - himc = ImmGetContext(hwnd); - if (!himc) - break; - - IME_GetCandidateList(himc, videodata); - ImmReleaseContext(hwnd, himc); + videodata->ime_uicontext = 1; + IME_GetCandidateList(hwnd, videodata); break; case IMN_CLOSECANDIDATE: trap = SDL_TRUE; + videodata->ime_uicontext = 0; IME_HideCandidateList(videodata); break; case IMN_PRIVATE: @@ -1007,7 +1110,8 @@ IME_CloseCandidateList(SDL_VideoData *videodata) { IME_HideCandidateList(videodata); videodata->ime_candcount = 0; - SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); + SDL_free(videodata->ime_candidates); + videodata->ime_candidates = NULL; } static void @@ -1020,13 +1124,16 @@ UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pca DWORD pgstart = 0; DWORD pgsize = 0; UINT i, j; + + if (IME_ShowCandidateList(videodata) < 0) + return; + pcandlist->lpVtbl->GetSelection(pcandlist, &selection); pcandlist->lpVtbl->GetCount(pcandlist, &count); pcandlist->lpVtbl->GetCurrentPage(pcandlist, &page); videodata->ime_candsel = selection; videodata->ime_candcount = count; - IME_ShowCandidateList(videodata); pcandlist->lpVtbl->GetPageIndex(pcandlist, 0, 0, &pgcount); if (pgcount > 0) { @@ -1044,8 +1151,6 @@ UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pca } videodata->ime_candpgsize = SDL_min(pgsize, MAX_CANDLIST); videodata->ime_candsel = videodata->ime_candsel - pgstart; - - SDL_memset(videodata->ime_candidates, 0, sizeof(videodata->ime_candidates)); for (i = pgstart, j = 0; (DWORD)i < count && j < videodata->ime_candpgsize; i++, j++) { BSTR bstr; if (SUCCEEDED(pcandlist->lpVtbl->GetString(pcandlist, i, &bstr))) { @@ -1055,8 +1160,9 @@ UILess_GetCandidateList(SDL_VideoData *videodata, ITfCandidateListUIElement *pca } } } - if (PRIMLANG() == LANG_KOREAN) - videodata->ime_candsel = -1; + // TODO: why was this necessary? check ime_candvertical instead? + //if (PRIMLANG() == LANG_KOREAN) + // videodata->ime_candsel = -1; } STDMETHODIMP_(ULONG) TSFSink_AddRef(TSFSink *sink) @@ -1473,7 +1579,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc) SelectObject(hdc, font); for (i = 0; i < candcount; ++i) { - const WCHAR *s = videodata->ime_candidates[i]; + const WCHAR *s = &videodata->ime_candidates[i * MAX_CANDLENGTH]; if (!*s) break; @@ -1535,7 +1641,7 @@ IME_RenderCandidateList(SDL_VideoData *videodata, HDC hdc) SetBkMode(hdc, TRANSPARENT); for (i = 0; i < candcount; ++i) { - const WCHAR *s = videodata->ime_candidates[i]; + const WCHAR *s = &videodata->ime_candidates[i * MAX_CANDLENGTH]; int left, top, right, bottom; if (!*s) break; @@ -1605,6 +1711,18 @@ void IME_Present(SDL_VideoData *videodata) /* FIXME: Need to show the IME bitmap */ } +SDL_bool WIN_IsTextInputShown(_THIS) +{ + SDL_VideoData* videodata = (SDL_VideoData*)_this->driverdata; + return IME_IsTextInputShown(videodata); +} + +void WIN_ClearComposition(_THIS) +{ + SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata; + IME_ClearComposition(videodata); +} + #endif /* SDL_DISABLE_WINDOWS_IME */ #endif /* SDL_VIDEO_DRIVER_WINDOWS */ diff --git a/src/video/windows/SDL_windowskeyboard.h b/src/video/windows/SDL_windowskeyboard.h index 76048e78a..97382c7bd 100644 --- a/src/video/windows/SDL_windowskeyboard.h +++ b/src/video/windows/SDL_windowskeyboard.h @@ -32,6 +32,8 @@ extern void WIN_ResetDeadKeys(void); extern void WIN_StartTextInput(_THIS); extern void WIN_StopTextInput(_THIS); extern void WIN_SetTextInputRect(_THIS, SDL_Rect *rect); +extern void WIN_ClearComposition(_THIS); +extern SDL_bool WIN_IsTextInputShown(_THIS); extern SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 19977e214..bc4ba6326 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -175,11 +175,13 @@ WIN_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) static SDL_Cursor * WIN_CreateBlankCursor() { + SDL_Cursor *cursor = NULL; SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, 32, 32, 32, SDL_PIXELFORMAT_ARGB8888); if (surface) { - return WIN_CreateCursor(surface, 0, 0); + cursor = WIN_CreateCursor(surface, 0, 0); + SDL_FreeSurface(surface); } - return NULL; + return cursor; } static SDL_Cursor * @@ -370,7 +372,8 @@ WIN_QuitMouse(_THIS) } if (SDL_blank_cursor) { - SDL_FreeCursor(SDL_blank_cursor); + WIN_FreeCursor(SDL_blank_cursor); + SDL_blank_cursor = NULL; } } diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 39806930b..4bd2a9831 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/src/video/windows/SDL_windowsvideo.c @@ -216,6 +216,8 @@ WIN_CreateDevice(int devindex) device->StartTextInput = WIN_StartTextInput; device->StopTextInput = WIN_StopTextInput; device->SetTextInputRect = WIN_SetTextInputRect; + device->ClearComposition = WIN_ClearComposition; + device->IsTextInputShown = WIN_IsTextInputShown; device->SetClipboardText = WIN_SetClipboardText; device->GetClipboardText = WIN_GetClipboardText; diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h index 7dae16a4a..d4208c405 100644 --- a/src/video/windows/SDL_windowsvideo.h +++ b/src/video/windows/SDL_windowsvideo.h @@ -37,6 +37,7 @@ #define MAX_CANDLIST 10 #define MAX_CANDLENGTH 256 +#define MAX_CANDSIZE (sizeof(WCHAR) * MAX_CANDLIST * MAX_CANDLENGTH) #include "SDL_windowsclipboard.h" #include "SDL_windowsevents.h" @@ -150,14 +151,16 @@ typedef struct SDL_VideoData SDL_bool ime_available; HWND ime_hwnd_main; HWND ime_hwnd_current; + SDL_bool ime_suppress_endcomposition_event; HIMC ime_himc; - WCHAR ime_composition[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; + WCHAR* ime_composition; + int ime_composition_length; WCHAR ime_readingstring[16]; int ime_cursor; SDL_bool ime_candlist; - WCHAR ime_candidates[MAX_CANDLIST][MAX_CANDLENGTH]; + WCHAR* ime_candidates; DWORD ime_candcount; DWORD ime_candref; DWORD ime_candsel; @@ -188,6 +191,7 @@ typedef struct SDL_VideoData DWORD ime_convmodesinkcookie; TSFSink *ime_uielemsink; TSFSink *ime_ippasink; + LONG ime_uicontext; BYTE pre_hook_key_state[256]; UINT _SDL_WAKEUP; diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index e392e5869..6dcea5bf2 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -28,6 +28,7 @@ #include "../SDL_pixels_c.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" +#include "../../SDL_hints_c.h" #include "SDL_windowsvideo.h" #include "SDL_windowswindow.h" @@ -51,16 +52,17 @@ static const TCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatche static const TCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow"); static ATOM SDL_HelperWindowClass = 0; -/* For borderless Windows, still want the following flags: +/* For borderless Windows, still want the following flag: + - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc. + Additionally, non-fullscreen windows can add: - WS_CAPTION: this seems to enable the Windows minimize animation - WS_SYSMENU: enables system context menu on task bar - - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc. This will also cause the task bar to overlap the window and other windowed behaviors, so only use this for windows that shouldn't appear to be fullscreen */ #define STYLE_BASIC (WS_CLIPSIBLINGS | WS_CLIPCHILDREN) -#define STYLE_FULLSCREEN (WS_POPUP) -#define STYLE_BORDERLESS (WS_POPUP) +#define STYLE_FULLSCREEN (WS_POPUP | WS_MINIMIZEBOX) +#define STYLE_BORDERLESS (WS_POPUP | WS_MINIMIZEBOX) #define STYLE_BORDERLESS_WINDOWED (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) #define STYLE_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) #define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX) @@ -156,7 +158,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags) int w, h; /* Figure out what the window area will be */ - if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) { + if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { top = HWND_TOPMOST; } else { top = HWND_NOTOPMOST; @@ -169,6 +171,13 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags) data->expected_resize = SDL_FALSE; } +static void SDLCALL +WIN_MouseRelativeModeCenterChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_WindowData *data = (SDL_WindowData *)userdata; + data->mouse_relative_mode_center = SDL_GetStringBoolean(hint, SDL_TRUE); +} + static int SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created) { @@ -187,11 +196,13 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE); data->created = created; data->high_surrogate = 0; - data->mouse_button_flags = 0; + data->mouse_button_flags = (WPARAM)-1; data->last_pointer_update = (LPARAM)-1; data->videodata = videodata; data->initializing = SDL_TRUE; + SDL_AddHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data); + window->driverdata = data; /* Associate the data with the window */ @@ -296,7 +307,39 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre return 0; } +static void CleanupWindowData(_THIS, SDL_Window * window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + if (data) { + SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data); + if (data->keyboard_hook) { + UnhookWindowsHookEx(data->keyboard_hook); + } + ReleaseDC(data->hwnd, data->hdc); + RemoveProp(data->hwnd, TEXT("SDL_WindowData")); + if (data->created) { + DestroyWindow(data->hwnd); + if (data->parent) { + DestroyWindow(data->parent); + } + } else { + /* Restore any original event handler... */ + if (data->wndproc != NULL) { +#ifdef GWLP_WNDPROC + SetWindowLongPtr(data->hwnd, GWLP_WNDPROC, + (LONG_PTR) data->wndproc); +#else + SetWindowLong(data->hwnd, GWL_WNDPROC, + (LONG_PTR) data->wndproc); +#endif + } + } + SDL_free(data); + } + window->driverdata = NULL; +} int WIN_CreateWindow(_THIS, SDL_Window * window) @@ -421,6 +464,9 @@ WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data) } } } + } else if (window->flags & SDL_WINDOW_OPENGL) { + /* Try to set up the pixel format, if it hasn't been set by the application */ + WIN_GL_SetupWindow(_this, window); } } #endif @@ -442,39 +488,40 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; HICON hicon = NULL; BYTE *icon_bmp; - int icon_len, mask_len, y; - SDL_RWops *dst; + int icon_len, mask_len, row_len, y; + BITMAPINFOHEADER *bmi; + Uint8 *dst; SDL_bool isstack; /* Create temporary buffer for ICONIMAGE structure */ + SDL_COMPILE_TIME_ASSERT(WIN_SetWindowIcon_uses_BITMAPINFOHEADER_to_prepare_an_ICONIMAGE, sizeof(BITMAPINFOHEADER) == 40); mask_len = (icon->h * (icon->w + 7)/8); - icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len; + icon_len = sizeof(BITMAPINFOHEADER) + icon->h * icon->w * sizeof(Uint32) + mask_len; icon_bmp = SDL_small_alloc(BYTE, icon_len, &isstack); - dst = SDL_RWFromMem(icon_bmp, icon_len); - if (!dst) { - SDL_small_free(icon_bmp, isstack); - return; - } /* Write the BITMAPINFO header */ - SDL_WriteLE32(dst, 40); - SDL_WriteLE32(dst, icon->w); - SDL_WriteLE32(dst, icon->h * 2); - SDL_WriteLE16(dst, 1); - SDL_WriteLE16(dst, 32); - SDL_WriteLE32(dst, BI_RGB); - SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32)); - SDL_WriteLE32(dst, 0); - SDL_WriteLE32(dst, 0); - SDL_WriteLE32(dst, 0); - SDL_WriteLE32(dst, 0); + bmi = (BITMAPINFOHEADER *)icon_bmp; + bmi->biSize = SDL_SwapLE32(sizeof(BITMAPINFOHEADER)); + bmi->biWidth = SDL_SwapLE32(icon->w); + bmi->biHeight = SDL_SwapLE32(icon->h * 2); + bmi->biPlanes = SDL_SwapLE16(1); + bmi->biBitCount = SDL_SwapLE16(32); + bmi->biCompression = SDL_SwapLE32(BI_RGB); + bmi->biSizeImage = SDL_SwapLE32(icon->h * icon->w * sizeof(Uint32)); + bmi->biXPelsPerMeter = SDL_SwapLE32(0); + bmi->biYPelsPerMeter = SDL_SwapLE32(0); + bmi->biClrUsed = SDL_SwapLE32(0); + bmi->biClrImportant = SDL_SwapLE32(0); /* Write the pixels upside down into the bitmap buffer */ SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888); + dst = &icon_bmp[sizeof(BITMAPINFOHEADER)]; + row_len = icon->w * sizeof(Uint32); y = icon->h; while (y--) { Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch; - SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1); + SDL_memcpy(dst, src, row_len); + dst += row_len; } /* Write the mask */ @@ -482,7 +529,6 @@ WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000); - SDL_RWclose(dst); SDL_small_free(icon_bmp, isstack); /* Set the icon for the window */ @@ -573,8 +619,38 @@ WIN_HideWindow(_THIS, SDL_Window * window) void WIN_RaiseWindow(_THIS, SDL_Window * window) { + /* If desired, raise the window more forcefully. + * Technique taken from http://stackoverflow.com/questions/916259/ . + * Specifically, http://stackoverflow.com/a/34414846 . + * + * The issue is that Microsoft has gone through a lot of trouble to make it + * nearly impossible to programmatically move a window to the foreground, + * for "security" reasons. Apparently, the following song-and-dance gets + * around their objections. */ + SDL_bool bForce = SDL_GetHintBoolean(SDL_HINT_FORCE_RAISEWINDOW, SDL_FALSE); + + HWND hCurWnd = NULL; + DWORD dwMyID = 0u; + DWORD dwCurID = 0u; + HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd; + if(bForce) + { + hCurWnd = GetForegroundWindow(); + dwMyID = GetCurrentThreadId(); + dwCurID = GetWindowThreadProcessId(hCurWnd, NULL); + ShowWindow(hwnd, SW_RESTORE); + AttachThreadInput(dwCurID, dwMyID, TRUE); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + } SetForegroundWindow(hwnd); + if (bForce) + { + AttachThreadInput(dwCurID, dwMyID, FALSE); + SetFocus(hwnd); + SetActiveWindow(hwnd); + } } void @@ -658,7 +734,14 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, int x, y; int w, h; - if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { + if (!fullscreen && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0) { + /* Resizing the window on hide causes problems restoring it in Wine, and it's unnecessary. + * Also, Windows would preview the minimized window with the wrong size. + */ + return; + } + + if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) { top = HWND_TOPMOST; } else { top = HWND_NOTOPMOST; @@ -824,15 +907,6 @@ void WIN_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { WIN_UpdateClipCursor(window); - - if (window->flags & SDL_WINDOW_FULLSCREEN) { - UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE; - - if (!(window->flags & SDL_WINDOW_SHOWN)) { - flags |= SWP_NOACTIVATE; - } - WIN_SetWindowPositionInternal(_this, window, flags); - } } void @@ -848,34 +922,7 @@ WIN_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed) void WIN_DestroyWindow(_THIS, SDL_Window * window) { - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - - if (data) { - if (data->keyboard_hook) { - UnhookWindowsHookEx(data->keyboard_hook); - } - ReleaseDC(data->hwnd, data->hdc); - RemoveProp(data->hwnd, TEXT("SDL_WindowData")); - if (data->created) { - DestroyWindow(data->hwnd); - if (data->parent) { - DestroyWindow(data->parent); - } - } else { - /* Restore any original event handler... */ - if (data->wndproc != NULL) { -#ifdef GWLP_WNDPROC - SetWindowLongPtr(data->hwnd, GWLP_WNDPROC, - (LONG_PTR) data->wndproc); -#else - SetWindowLong(data->hwnd, GWL_WNDPROC, - (LONG_PTR) data->wndproc); -#endif - } - } - SDL_free(data); - } - window->driverdata = NULL; + CleanupWindowData(_this, window); } SDL_bool @@ -1007,7 +1054,7 @@ WIN_UpdateClipCursor(SDL_Window *window) if ((mouse->relative_mode || (window->flags & SDL_WINDOW_MOUSE_GRABBED) || (window->mouse_rect.w > 0 && window->mouse_rect.h > 0)) && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { - if (mouse->relative_mode && !mouse->relative_mode_warp) { + if (mouse->relative_mode && !mouse->relative_mode_warp && data->mouse_relative_mode_center) { if (GetWindowRect(data->hwnd, &rect)) { LONG cx, cy; diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index d1570fdb0..659366a9f 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -49,6 +49,7 @@ typedef struct Uint8 focus_click_pending; SDL_bool skip_update_clipcursor; Uint32 last_updated_clipcursor; + SDL_bool mouse_relative_mode_center; SDL_bool windowed_mode_was_maximized; SDL_bool in_window_deactivation; RECT cursor_clipped_rect; diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 0b231b792..6ed5918e7 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -478,8 +478,7 @@ WINRT_InitModes(_THIS) hr = CreateDXGIFactory1(SDL_IID_IDXGIFactory2, (void **)&dxgiFactory2); if (FAILED(hr)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr); - return -1; + return WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr); } for (int adapterIndex = 0; ; ++adapterIndex) { @@ -630,14 +629,12 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) // Make sure that only one window gets created, at least until multimonitor // support is added. if (WINRT_GlobalSDLWindow != NULL) { - SDL_SetError("WinRT only supports one window"); - return -1; + return SDL_SetError("WinRT only supports one window"); } SDL_WindowData *data = new SDL_WindowData; /* use 'new' here as SDL_WindowData may use WinRT/C++ types */ if (!data) { - SDL_OutOfMemory(); - return -1; + return SDL_OutOfMemory(); } window->driverdata = data; data->sdlWindow = window; @@ -673,9 +670,8 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) * be passed into eglCreateWindowSurface. */ if (SDL_EGL_ChooseConfig(_this) != 0) { - char buf[512]; - SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError()); - return SDL_SetError("%s", buf); + /* SDL_EGL_ChooseConfig failed, SDL_GetError() should have info */ + return -1; } if (video_data->winrtEglWindow) { /* ... is the 'old' version of ANGLE/WinRT being used? */ diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index c1260215d..63091fe98 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -380,7 +380,7 @@ X11_GetScrollLockModifierMask(_THIS) return num_mask; } -static void +void X11_ReconcileKeyboardState(_THIS) { SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata; @@ -408,7 +408,22 @@ X11_ReconcileKeyboardState(_THIS) SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED; if (x11KeyPressed && !sdlKeyPressed) { - SDL_SendKeyboardKey(SDL_PRESSED, scancode); + /* Only update modifier state for keys that are pressed in another application */ + switch (SDL_GetKeyFromScancode(scancode)) { + case SDLK_LCTRL: + case SDLK_RCTRL: + case SDLK_LSHIFT: + case SDLK_RSHIFT: + case SDLK_LALT: + case SDLK_RALT: + case SDLK_LGUI: + case SDLK_RGUI: + case SDLK_MODE: + SDL_SendKeyboardKey(SDL_PRESSED, scancode); + break; + default: + break; + } } else if (!x11KeyPressed && sdlKeyPressed) { SDL_SendKeyboardKey(SDL_RELEASED, scancode); } @@ -718,7 +733,6 @@ static void X11_DispatchEvent(_THIS, XEvent *xevent) { SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata; - XkbEvent* xkbEvent = (XkbEvent*) xevent; Display *display; SDL_WindowData *data; int orig_event_type; @@ -805,11 +819,13 @@ X11_DispatchEvent(_THIS, XEvent *xevent) if (!data) { /* The window for KeymapNotify, etc events is 0 */ if (xevent->type == KeymapNotify) { +#ifdef DEBUG_XEVENTS + printf("window %p: KeymapNotify!\n", data); +#endif if (SDL_GetKeyboardFocus() != NULL) { X11_ReconcileKeyboardState(_this); } - } else if (xevent->type == MappingNotify || - (xevent->type == videodata->xkb_event && xkbEvent->any.xkb_type == XkbStateNotify)) { + } else if (xevent->type == MappingNotify) { /* Has the keyboard layout changed? */ const int request = xevent->xmapping.request; @@ -996,8 +1012,9 @@ X11_DispatchEvent(_THIS, XEvent *xevent) } break; - /* Key press? */ - case KeyPress:{ + /* Key press/release? */ + case KeyPress: + case KeyRelease: { KeyCode keycode = xevent->xkey.keycode; KeySym keysym = NoSymbol; char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; @@ -1005,7 +1022,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) SDL_bool handled_by_ime = SDL_FALSE; #ifdef DEBUG_XEVENTS - printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); + printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode); #endif #if 1 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { @@ -1021,7 +1038,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) /* */ SDL_zeroa(text); #ifdef X_HAVE_UTF8_STRING - if (data->ic) { + if (data->ic && xevent->type == KeyPress) { X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text), &keysym, &status); } else { @@ -1033,35 +1050,30 @@ X11_DispatchEvent(_THIS, XEvent *xevent) #ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode); + handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED)); } #endif if (!handled_by_ime) { - /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ - if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { - SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); - } - if(*text) { - SDL_SendKeyboardText(text); + if (xevent->type == KeyPress) { + /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ + if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { + SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); + } + if(*text) { + SDL_SendKeyboardText(text); + } + } else { + if (X11_KeyRepeat(display, xevent)) { + /* We're about to get a repeated key down, ignore the key up */ + break; + } + SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } } - X11_UpdateUserTime(data, xevent->xkey.time); - } - break; - - /* Key release? */ - case KeyRelease:{ - KeyCode keycode = xevent->xkey.keycode; - -#ifdef DEBUG_XEVENTS - printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); -#endif - if (X11_KeyRepeat(display, xevent)) { - /* We're about to get a repeated key down, ignore the key up */ - break; + if (xevent->type == KeyPress) { + X11_UpdateUserTime(data, xevent->xkey.time); } - SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } break; diff --git a/src/video/x11/SDL_x11events.h b/src/video/x11/SDL_x11events.h index fc8a57ae2..de89110d0 100644 --- a/src/video/x11/SDL_x11events.h +++ b/src/video/x11/SDL_x11events.h @@ -27,6 +27,7 @@ extern void X11_PumpEvents(_THIS); extern int X11_WaitEventTimeout(_THIS, int timeout); extern void X11_SendWakeupEvent(_THIS, SDL_Window *window); extern void X11_SuspendScreenSaver(_THIS); +extern void X11_ReconcileKeyboardState(_THIS); #endif /* SDL_x11events_h_ */ diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index c82570c62..c84bcc798 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -409,6 +409,8 @@ X11_InitKeyboard(_THIS) SDL_IME_Init(); #endif + X11_ReconcileKeyboardState(_this); + return 0; } diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index aafccca9b..9bc9702c0 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -830,10 +830,11 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int exitcode = 0; close(fds[0]); status = X11_ShowMessageBoxImpl(messageboxdata, buttonid); - if (write(fds[1], &status, sizeof (int)) != sizeof (int)) + if (write(fds[1], &status, sizeof (int)) != sizeof (int)) { exitcode = 1; - else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) + } else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) { exitcode = 1; + } close(fds[1]); _exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */ } else { /* we're the parent */ @@ -846,13 +847,12 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) SDL_assert(rc == pid); /* not sure what to do if this fails. */ if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) { - return SDL_SetError("msgbox child process failed"); + status = SDL_SetError("msgbox child process failed"); + } else if ( (read(fds[0], &status, sizeof (int)) != sizeof (int)) || + (read(fds[0], buttonid, sizeof (int)) != sizeof (int)) ) { + status = SDL_SetError("read from msgbox child process failed"); + *buttonid = 0; } - - if (read(fds[0], &status, sizeof (int)) != sizeof (int)) - status = -1; - else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int)) - status = -1; close(fds[0]); return status; diff --git a/src/video/x11/SDL_x11modes.c b/src/video/x11/SDL_x11modes.c index c1efe243c..f2cbdb45f 100644 --- a/src/video/x11/SDL_x11modes.c +++ b/src/video/x11/SDL_x11modes.c @@ -1011,7 +1011,13 @@ static int (*PreXRRSetScreenSizeErrorHandler)(Display *, XErrorEvent *) = NULL; static int SDL_XRRSetScreenSizeErrHandler(Display *d, XErrorEvent *e) { - return (e->error_code == BadMatch) ? 0 : PreXRRSetScreenSizeErrorHandler(d, e); + /* BadMatch: https://github.com/libsdl-org/SDL/issues/4561 */ + /* BadValue: https://github.com/libsdl-org/SDL/issues/4840 */ + if ((e->error_code == BadMatch) || (e->error_code == BadValue)) { + return 0; + } + + return PreXRRSetScreenSizeErrorHandler(d, e); } int diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index 033df8d28..9eb1ddd30 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -294,14 +294,15 @@ X11_ShowCursor(SDL_Cursor * cursor) SDL_VideoDevice *video = SDL_GetVideoDevice(); Display *display = GetDisplay(); SDL_Window *window; - SDL_WindowData *data; for (window = video->windows; window; window = window->next) { - data = (SDL_WindowData *)window->driverdata; - if (x11_cursor != None) { - X11_XDefineCursor(display, data->xwindow, x11_cursor); - } else { - X11_XUndefineCursor(display, data->xwindow); + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + if (data) { + if (x11_cursor != None) { + X11_XDefineCursor(display, data->xwindow, x11_cursor); + } else { + X11_XUndefineCursor(display, data->xwindow); + } } } X11_XFlush(display); diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c index 64b06340a..3e17e97ff 100644 --- a/src/video/x11/SDL_x11opengl.c +++ b/src/video/x11/SDL_x11opengl.c @@ -247,11 +247,6 @@ X11_GL_LoadLibrary(_THIS, const char *path) X11_GL_UseEGL(_this) ) { #if SDL_VIDEO_OPENGL_EGL X11_GL_UnloadLibrary(_this); - /* Better avoid conflicts! */ - if (_this->gl_config.dll_handle != NULL ) { - GL_UnloadObject(_this->gl_config.dll_handle); - _this->gl_config.dll_handle = NULL; - } _this->GL_LoadLibrary = X11_GLES_LoadLibrary; _this->GL_GetProcAddress = X11_GLES_GetProcAddress; _this->GL_UnloadLibrary = X11_GLES_UnloadLibrary; diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 67b0a793a..762a86596 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -185,7 +185,6 @@ SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),) SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),) SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c),(a,b,c),return) -SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned int d),(a,b,c,d),return) #endif #if NeedWidePrototypes diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 89e9ebbc1..d31ac012a 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -392,6 +392,7 @@ X11_CreateWindow(_THIS, SDL_Window * window) long compositor = 1; Atom _NET_WM_PID; long fevent = 0; + const char *hint = NULL; #if SDL_VIDEO_OPENGL_GLX || SDL_VIDEO_OPENGL_EGL const char *forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID); @@ -591,6 +592,8 @@ X11_CreateWindow(_THIS, SDL_Window * window) wintype_name = "_NET_WM_WINDOW_TYPE_TOOLTIP"; } else if (window->flags & SDL_WINDOW_POPUP_MENU) { wintype_name = "_NET_WM_WINDOW_TYPE_POPUP_MENU"; + } else if ( ((hint = SDL_GetHint(SDL_HINT_X11_WINDOW_TYPE)) != NULL) && *hint ) { + wintype_name = hint; } else { wintype_name = "_NET_WM_WINDOW_TYPE_NORMAL"; compositor = 1; /* disable compositing for "normal" windows */ @@ -675,8 +678,6 @@ X11_CreateWindow(_THIS, SDL_Window * window) /* For _ICC_PROFILE. */ X11_XSelectInput(display, RootWindow(display, screen), PropertyChangeMask); - X11_XkbSelectEvents(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask); - X11_XFlush(display); return 0; @@ -779,11 +780,22 @@ X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon) X11_XFlush(display); } +static SDL_bool caught_x11_error = SDL_FALSE; +static int +X11_CatchAnyError(Display * d, XErrorEvent * e) +{ + /* this may happen during tumultuous times when we are polling anyhow, + so just note we had an error and return control. */ + caught_x11_error = SDL_TRUE; + return 0; +} + void X11_SetWindowPosition(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; + int (*prev_handler) (Display *, XErrorEvent *) = NULL; unsigned int childCount; Window childReturn, root, parent; Window* children; @@ -802,20 +814,27 @@ X11_SetWindowPosition(_THIS, SDL_Window * window) /* Wait a brief time to see if the window manager decided to let this move happen. If the window changes at all, even to an unexpected value, we break out. */ + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + timeout = SDL_GetTicks() + 100; while (SDL_TRUE) { int x, y; + + caught_x11_error = SDL_FALSE; X11_XSync(display, False); X11_XGetWindowAttributes(display, data->xwindow, &attrs); X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), attrs.x, attrs.y, &x, &y, &childReturn); - if ((x != orig_x) || (y != orig_y)) { - window->x = x; - window->y = y; - break; /* window moved, time to go. */ - } else if ((x == window->x) && (y == window->y)) { - break; /* we're at the place we wanted to be anyhow, drop out. */ + if (!caught_x11_error) { + if ((x != orig_x) || (y != orig_y)) { + window->x = x; + window->y = y; + break; /* window moved, time to go. */ + } else if ((x == window->x) && (y == window->y)) { + break; /* we're at the place we wanted to be anyhow, drop out. */ + } } if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) { @@ -824,6 +843,9 @@ X11_SetWindowPosition(_THIS, SDL_Window * window) SDL_Delay(10); } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } void @@ -889,6 +911,7 @@ X11_SetWindowSize(_THIS, SDL_Window * window) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; Display *display = data->videodata->display; + int (*prev_handler) (Display *, XErrorEvent *) = NULL; XWindowAttributes attrs; int orig_w, orig_h; Uint32 timeout; @@ -940,19 +963,25 @@ X11_SetWindowSize(_THIS, SDL_Window * window) X11_XResizeWindow(display, data->xwindow, window->w, window->h); } + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + /* Wait a brief time to see if the window manager decided to let this resize happen. If the window changes at all, even to an unexpected value, we break out. */ timeout = SDL_GetTicks() + 100; while (SDL_TRUE) { + caught_x11_error = SDL_FALSE; X11_XSync(display, False); X11_XGetWindowAttributes(display, data->xwindow, &attrs); - if ((attrs.width != orig_w) || (attrs.height != orig_h)) { - window->w = attrs.width; - window->h = attrs.height; - break; /* window changed, time to go. */ - } else if ((attrs.width == window->w) && (attrs.height == window->h)) { - break; /* we're at the place we wanted to be anyhow, drop out. */ + if (!caught_x11_error) { + if ((attrs.width != orig_w) || (attrs.height != orig_h)) { + window->w = attrs.width; + window->h = attrs.height; + break; /* window changed, time to go. */ + } else if ((attrs.width == window->w) && (attrs.height == window->h)) { + break; /* we're at the place we wanted to be anyhow, drop out. */ + } } if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) { @@ -961,6 +990,9 @@ X11_SetWindowSize(_THIS, SDL_Window * window) SDL_Delay(10); } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } int @@ -1278,6 +1310,22 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis if (X11_IsWindowMapped(_this, window)) { XEvent e; + /* !!! FIXME: most of this waiting code is copy/pasted from elsewhere. */ + int (*prev_handler) (Display *, XErrorEvent *) = NULL; + unsigned int childCount; + Window childReturn, root, parent; + Window* children; + XWindowAttributes attrs; + int orig_w, orig_h, orig_x, orig_y; + Uint64 timeout; + + X11_XSync(display, False); + X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount); + X11_XGetWindowAttributes(display, data->xwindow, &attrs); + X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), + attrs.x, attrs.y, &orig_x, &orig_y, &childReturn); + orig_w = attrs.width; + orig_h = attrs.height; if (!(window->flags & SDL_WINDOW_RESIZABLE)) { /* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we @@ -1327,6 +1375,41 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0, SubstructureNotifyMask | SubstructureRedirectMask, &e); } + + /* Wait a brief time to see if the window manager decided to let this happen. + If the window changes at all, even to an unexpected value, we break out. */ + X11_XSync(display, False); + prev_handler = X11_XSetErrorHandler(X11_CatchAnyError); + + timeout = SDL_GetTicks64() + 100; + while (SDL_TRUE) { + int x, y; + + caught_x11_error = SDL_FALSE; + X11_XSync(display, False); + X11_XGetWindowAttributes(display, data->xwindow, &attrs); + X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display), + attrs.x, attrs.y, &x, &y, &childReturn); + + if (!caught_x11_error) { + if ((x != orig_x) || (y != orig_y) || (attrs.width != orig_w) || (attrs.height != orig_h)) { + window->x = x; + window->y = y; + window->w = attrs.width; + window->h = attrs.height; + break; /* window moved, time to go. */ + } + } + + if (SDL_GetTicks64() >= timeout) { + break; + } + + SDL_Delay(10); + } + + X11_XSetErrorHandler(prev_handler); + caught_x11_error = SDL_FALSE; } else { Uint32 flags; @@ -1656,9 +1739,15 @@ void X11_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - Display *display = data->videodata->display; + Display *display; SDL_bool oldstyle_fullscreen; + if (data == NULL) { + return; + } + + display = data->videodata->display; + /* ICCCM2.0-compliant window managers can handle fullscreen windows If we're using XVidMode to change resolution we need to confine the cursor so we don't pan around the virtual desktop. @@ -1716,7 +1805,13 @@ void X11_SetWindowKeyboardGrab(_THIS, SDL_Window * window, SDL_bool grabbed) { SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - Display *display = data->videodata->display; + Display *display; + + if (data == NULL) { + return; + } + + display = data->videodata->display; if (grabbed) { /* If the window is unmapped, XGrab calls return GrabNotViewable, diff --git a/src/video/yuv2rgb/yuv_rgb_sse_func.h b/src/video/yuv2rgb/yuv_rgb_sse_func.h index 3c5ee0db4..f541017a4 100644 --- a/src/video/yuv2rgb/yuv_rgb_sse_func.h +++ b/src/video/yuv2rgb/yuv_rgb_sse_func.h @@ -426,9 +426,17 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height, const int fix_read_nv12 = 0; #endif +#if YUV_FORMAT == YUV_FORMAT_422 + /* Avoid invalid read on last line */ + const int fix_read_422 = 1; +#else + const int fix_read_422 = 0; +#endif + + if (width >= 32) { uint32_t xpos, ypos; - for(ypos=0; ypos<(height-(uv_y_sample_interval-1)); ypos+=uv_y_sample_interval) + for(ypos=0; ypos<(height-(uv_y_sample_interval-1)) - fix_read_422; ypos+=uv_y_sample_interval) { const uint8_t *y_ptr1=Y+ypos*Y_stride, *y_ptr2=Y+(ypos+1)*Y_stride, @@ -459,6 +467,15 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height, } } + if (fix_read_422) { + const uint8_t *y_ptr=Y+ypos*Y_stride, + *u_ptr=U+(ypos/uv_y_sample_interval)*UV_stride, + *v_ptr=V+(ypos/uv_y_sample_interval)*UV_stride; + uint8_t *rgb_ptr=RGB+ypos*RGB_stride; + STD_FUNCTION_NAME(width, 1, y_ptr, u_ptr, v_ptr, Y_stride, UV_stride, rgb_ptr, RGB_stride, yuv_type); + ypos += uv_y_sample_interval; + } + /* Catch the last line, if needed */ if (uv_y_sample_interval == 2 && ypos == (height-1)) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 665d2d721..330af47c4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -213,7 +213,6 @@ if(PSP) testfilesystem testplatform testthread - testloadso testqsort testaudioinfo testlock diff --git a/test/Makefile.in b/test/Makefile.in index d29dc6ecf..f724618c6 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -364,6 +364,7 @@ DATA = \ testgles2_sdf_img_sdf.bmp \ testyuv.bmp \ unifont-13.0.06.hex \ + utf8.txt \ $(NULL) ifneq ($(srcdir), .) diff --git a/test/testautomation_rect.c b/test/testautomation_rect.c index 26f03e9bb..cd8f65c34 100644 --- a/test/testautomation_rect.c +++ b/test/testautomation_rect.c @@ -408,6 +408,32 @@ void _validateRectEqualsResults( refRectB->x, refRectB->y, refRectB->w, refRectB->h); } +/* ! + * \brief Private helper to check SDL_FRectEquals results + */ +void _validateFRectEqualsResults( + SDL_bool equals, SDL_bool expectedEquals, + SDL_FRect *rectA, SDL_FRect *rectB, SDL_FRect *refRectA, SDL_FRect *refRectB) +{ + int cmpRes; + SDLTest_AssertCheck(equals == expectedEquals, + "Check for correct equals result: expected %s, got %s testing (%f,%f,%f,%f) and (%f,%f,%f,%f)", + (expectedEquals == SDL_TRUE) ? "SDL_TRUE" : "SDL_FALSE", + (equals == SDL_TRUE) ? "SDL_TRUE" : "SDL_FALSE", + rectA->x, rectA->y, rectA->w, rectA->h, + rectB->x, rectB->y, rectB->w, rectB->h); + cmpRes = SDL_memcmp(rectA, refRectA, sizeof(*rectA)); + SDLTest_AssertCheck(cmpRes == 0, + "Check that source rectangle A was not modified: got (%f,%f,%f,%f) expected (%f,%f,%f,%f)", + rectA->x, rectA->y, rectA->w, rectA->h, + refRectA->x, refRectA->y, refRectA->w, refRectA->h); + cmpRes = SDL_memcmp(rectB, refRectB, sizeof(*rectB)); + SDLTest_AssertCheck(cmpRes == 0, + "Check that source rectangle B was not modified: got (%f,%f,%f,%f) expected (%f,%f,%f,%f)", + rectB->x, rectB->y, rectB->w, rectB->h, + refRectB->x, refRectB->y, refRectB->w, refRectB->h); +} + /* ! * \brief Tests SDL_IntersectRect() with B fully inside A * @@ -1574,6 +1600,69 @@ int rect_testRectEqualsParam(void *arg) return TEST_COMPLETED; } +/* ! + * \brief Tests SDL_FRectEquals() with various inputs + * + * \sa + * http://wiki.libsdl.org/SDL_FRectEquals + */ +int rect_testFRectEquals(void *arg) +{ + SDL_FRect refRectA; + SDL_FRect refRectB; + SDL_FRect rectA; + SDL_FRect rectB; + SDL_bool expectedResult; + SDL_bool result; + + /* Equals */ + refRectA.x=(float)SDLTest_RandomIntegerInRange(-1024, 1024); + refRectA.y=(float)SDLTest_RandomIntegerInRange(-1024, 1024); + refRectA.w=(float)SDLTest_RandomIntegerInRange(1, 1024); + refRectA.h=(float)SDLTest_RandomIntegerInRange(1, 1024); + refRectB = refRectA; + expectedResult = SDL_TRUE; + rectA = refRectA; + rectB = refRectB; + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)&rectA, (const SDL_FRect *)&rectB); + _validateFRectEqualsResults(result, expectedResult, &rectA, &rectB, &refRectA, &refRectB); + + return TEST_COMPLETED; +} + +/* ! + * \brief Negative tests against SDL_FRectEquals() with invalid parameters + * + * \sa + * http://wiki.libsdl.org/SDL_FRectEquals + */ +int rect_testFRectEqualsParam(void *arg) +{ + SDL_FRect rectA; + SDL_FRect rectB; + SDL_bool result; + + /* data setup -- For the purpose of this test, the values don't matter. */ + rectA.x=SDLTest_RandomFloat(); + rectA.y=SDLTest_RandomFloat(); + rectA.w=SDLTest_RandomFloat(); + rectA.h=SDLTest_RandomFloat(); + rectB.x=SDLTest_RandomFloat(); + rectB.y=SDLTest_RandomFloat(); + rectB.w=SDLTest_RandomFloat(); + rectB.h=SDLTest_RandomFloat(); + + /* invalid parameter combinations */ + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)NULL, (const SDL_FRect *)&rectB); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 1st parameter is NULL"); + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)&rectA, (const SDL_FRect *)NULL); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 2nd parameter is NULL"); + result = (SDL_bool)SDL_FRectEquals((const SDL_FRect *)NULL, (const SDL_FRect *)NULL); + SDLTest_AssertCheck(result == SDL_FALSE, "Check that function returns SDL_FALSE when 1st and 2nd parameter are NULL"); + + return TEST_COMPLETED; +} + /* ================= Test References ================== */ /* Rect test cases */ @@ -1673,6 +1762,13 @@ static const SDLTest_TestCaseReference rectTest28 = static const SDLTest_TestCaseReference rectTest29 = { (SDLTest_TestCaseFp)rect_testRectEqualsParam, "rect_testRectEqualsParam", "Negative tests against SDL_RectEquals with invalid parameters", TEST_ENABLED }; +/* SDL_FRectEquals */ + +static const SDLTest_TestCaseReference rectTest30 = + { (SDLTest_TestCaseFp)rect_testFRectEquals, "rect_testFRectEquals", "Tests SDL_FRectEquals with various inputs", TEST_ENABLED }; + +static const SDLTest_TestCaseReference rectTest31 = + { (SDLTest_TestCaseFp)rect_testFRectEqualsParam, "rect_testFRectEqualsParam", "Negative tests against SDL_FRectEquals with invalid parameters", TEST_ENABLED }; /* ! * \brief Sequence of Rect test cases; functions that handle simple rectangles including overlaps and merges. @@ -1683,7 +1779,7 @@ static const SDLTest_TestCaseReference rectTest29 = static const SDLTest_TestCaseReference *rectTests[] = { &rectTest1, &rectTest2, &rectTest3, &rectTest4, &rectTest5, &rectTest6, &rectTest7, &rectTest8, &rectTest9, &rectTest10, &rectTest11, &rectTest12, &rectTest13, &rectTest14, &rectTest15, &rectTest16, &rectTest17, &rectTest18, &rectTest19, &rectTest20, &rectTest21, &rectTest22, &rectTest23, &rectTest24, &rectTest25, &rectTest26, &rectTest27, - &rectTest28, &rectTest29, NULL + &rectTest28, &rectTest29, &rectTest30, &rectTest31, NULL }; diff --git a/test/testautomation_render.c b/test/testautomation_render.c index 42fc54dee..0117334a2 100644 --- a/test/testautomation_render.c +++ b/test/testautomation_render.c @@ -187,14 +187,14 @@ int render_testPrimitives (void *arg) ret = SDL_RenderDrawLine(renderer, 79, 59, 50, 30 ); SDLTest_AssertCheck(ret == 0, "Validate result from SDL_RenderDrawLine, expected: 0, got: %i", ret); - - /* Make current */ - SDL_RenderPresent(renderer); - + /* See if it's the same. */ referenceSurface = SDLTest_ImagePrimitives(); _compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE ); + /* Make current */ + SDL_RenderPresent(renderer); + /* Clean up. */ SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -335,13 +335,13 @@ int render_testPrimitivesBlend (void *arg) SDLTest_AssertCheck(checkFailCount2 == 0, "Validate results from calls to SDL_SetRenderDrawBlendMode, expected: 0, got: %i", checkFailCount2); SDLTest_AssertCheck(checkFailCount3 == 0, "Validate results from calls to SDL_RenderDrawPoint, expected: 0, got: %i", checkFailCount3); - /* Make current */ - SDL_RenderPresent(renderer); - /* See if it's the same. */ referenceSurface = SDLTest_ImagePrimitivesBlend(); _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED ); + /* Make current */ + SDL_RenderPresent(renderer); + /* Clean up. */ SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -404,13 +404,13 @@ render_testBlit(void *arg) } SDLTest_AssertCheck(checkFailCount1 == 0, "Validate results from calls to SDL_RenderCopy, expected: 0, got: %i", checkFailCount1); - /* Make current */ - SDL_RenderPresent(renderer); - /* See if it's the same */ referenceSurface = SDLTest_ImageBlit(); _compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE ); + /* Make current */ + SDL_RenderPresent(renderer); + /* Clean up. */ SDL_DestroyTexture( tface ); SDL_FreeSurface(referenceSurface); @@ -478,13 +478,13 @@ render_testBlitColor (void *arg) SDLTest_AssertCheck(checkFailCount1 == 0, "Validate results from calls to SDL_SetTextureColorMod, expected: 0, got: %i", checkFailCount1); SDLTest_AssertCheck(checkFailCount2 == 0, "Validate results from calls to SDL_RenderCopy, expected: 0, got: %i", checkFailCount2); - /* Make current */ - SDL_RenderPresent(renderer); - /* See if it's the same. */ referenceSurface = SDLTest_ImageBlitColor(); _compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE ); + /* Make current */ + SDL_RenderPresent(renderer); + /* Clean up. */ SDL_DestroyTexture( tface ); SDL_FreeSurface(referenceSurface); @@ -555,13 +555,13 @@ render_testBlitAlpha (void *arg) SDLTest_AssertCheck(checkFailCount1 == 0, "Validate results from calls to SDL_SetTextureAlphaMod, expected: 0, got: %i", checkFailCount1); SDLTest_AssertCheck(checkFailCount2 == 0, "Validate results from calls to SDL_RenderCopy, expected: 0, got: %i", checkFailCount2); - /* Make current */ - SDL_RenderPresent(renderer); - /* See if it's the same. */ referenceSurface = SDLTest_ImageBlitAlpha(); _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED ); + /* Make current */ + SDL_RenderPresent(renderer); + /* Clean up. */ SDL_DestroyTexture( tface ); SDL_FreeSurface(referenceSurface); @@ -674,9 +674,10 @@ render_testBlitBlend (void *arg) _testBlitBlendMode( tface, SDL_BLENDMODE_NONE ); referenceSurface = SDLTest_ImageBlitBlendNone(); - /* Make current and compare */ - SDL_RenderPresent(renderer); + /* Compare, then Present */ _compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE ); + SDL_RenderPresent(renderer); + SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -684,9 +685,10 @@ render_testBlitBlend (void *arg) _testBlitBlendMode( tface, SDL_BLENDMODE_BLEND ); referenceSurface = SDLTest_ImageBlitBlend(); - /* Make current and compare */ - SDL_RenderPresent(renderer); + /* Compare, then Present */ _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED ); + SDL_RenderPresent(renderer); + SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -694,9 +696,10 @@ render_testBlitBlend (void *arg) _testBlitBlendMode( tface, SDL_BLENDMODE_ADD ); referenceSurface = SDLTest_ImageBlitBlendAdd(); - /* Make current and compare */ - SDL_RenderPresent(renderer); + /* Compare, then Present */ _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED ); + SDL_RenderPresent(renderer); + SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -704,9 +707,10 @@ render_testBlitBlend (void *arg) _testBlitBlendMode( tface, SDL_BLENDMODE_MOD); referenceSurface = SDLTest_ImageBlitBlendMod(); - /* Make current and compare */ - SDL_RenderPresent(renderer); + /* Compare, then Present */ _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED ); + SDL_RenderPresent(renderer); + SDL_FreeSurface(referenceSurface); referenceSurface = NULL; @@ -753,12 +757,13 @@ render_testBlitBlend (void *arg) /* Clean up. */ SDL_DestroyTexture( tface ); - /* Make current */ - SDL_RenderPresent(renderer); - /* Check to see if final image matches. */ referenceSurface = SDLTest_ImageBlitBlendAll(); _compare(referenceSurface, ALLOWABLE_ERROR_BLENDED); + + /* Make current */ + SDL_RenderPresent(renderer); + SDL_FreeSurface(referenceSurface); referenceSurface = NULL; diff --git a/test/testautomation_surface.c b/test/testautomation_surface.c index fcfaad661..92c078685 100644 --- a/test/testautomation_surface.c +++ b/test/testautomation_surface.c @@ -333,7 +333,7 @@ surface_testCompleteSurfaceConversion(void *arg) SDL_PIXELFORMAT_RGBA8888, SDL_PIXELFORMAT_ABGR8888, SDL_PIXELFORMAT_BGRA8888, - /*SDL_PIXELFORMAT_ARGB2101010,*/ /* SDL_PIXELFORMAT_ARGB2101010 isn't fully supported yet */ + SDL_PIXELFORMAT_ARGB2101010, }; SDL_Surface *face = NULL, *cvt1, *cvt2, *final; SDL_PixelFormat *fmt1, *fmt2; diff --git a/test/testevdev.c b/test/testevdev.c index 572c60a05..76a12ef7e 100644 --- a/test/testevdev.c +++ b/test/testevdev.c @@ -41,6 +41,7 @@ static const struct CLS(SOUND), CLS(TOUCHSCREEN), CLS(ACCELEROMETER), + CLS(TOUCHPAD), #undef CLS { 0, NULL } }; @@ -185,9 +186,7 @@ static const GuessTest guess_tests[] = .bus_type = 0x0003, .vendor_id = 0x054c, .product_id = 0x09cc, - /* TODO: Should this be MOUSE? That's what it most closely - * resembles */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_TOUCHPAD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* X, Y, multitouch */ @@ -596,7 +595,7 @@ static const GuessTest guess_tests[] = * to the arrow, page up and page down keys, so it's a joystick * with a subset of a keyboard attached. */ /* TODO: Should this be JOYSTICK, or even JOYSTICK|KEYBOARD? */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -608,7 +607,7 @@ static const GuessTest guess_tests[] = /* BTN_1, BTN_2, BTN_A, BTN_B, BTN_MODE */ /* 0x100 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x10, /* 0x140 */ ZEROx8, - /* next, previous */ + /* next (keyboard page down), previous (keyboard page up) */ /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4, }, }, @@ -659,7 +658,7 @@ static const GuessTest guess_tests[] = .name = "Wiimote - Classic Controller", /* TODO: Should this be JOYSTICK, or maybe JOYSTICK|KEYBOARD? * It's unusual in the same ways as the Wiimote */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* Hat 1-3 */ @@ -673,7 +672,7 @@ static const GuessTest guess_tests[] = /* A, B, X, Y, MODE, TL, TL2, TR, TR2 */ /* 0x100 */ ZEROx4, 0x00, 0x13, 0xdb, 0x10, /* 0x140 */ ZEROx8, - /* next, previous */ + /* next (keyboard page down), previous (keyboard page up) */ /* 0x180 */ 0x00, 0x00, 0x80, 0x10, ZEROx4, }, }, @@ -718,9 +717,7 @@ static const GuessTest guess_tests[] = .vendor_id = 0x06cb, .product_id = 0x0000, .version = 0x0000, - /* TODO: Should this be MOUSE? That's what it most closely - * resembles */ - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_TOUCHPAD, /* SYN, KEY, ABS */ .ev = { 0x0b }, /* X, Y, pressure, multitouch */ @@ -756,7 +753,8 @@ static const GuessTest guess_tests[] = }, { .name = "Thinkpad ACPI buttons", - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats this as a keyboard because it has a power button */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, MSC, SW */ .ev = { 0x33 }, .keys = { @@ -815,7 +813,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0003, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats KEY_SLEEP as indicating a keyboard */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -841,7 +840,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0001, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats KEY_POWER as indicating a keyboard */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -856,7 +856,8 @@ static const GuessTest guess_tests[] = .vendor_id = 0x0000, .product_id = 0x0006, .version = 0x0000, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + /* SDL treats brightness control, etc. as keyboard keys */ + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -873,7 +874,7 @@ static const GuessTest guess_tests[] = .vendor_id = 0x17aa, .product_id = 0x5054, .version = 0x4101, - .expected = SDL_UDEV_DEVICE_UNKNOWN, + .expected = SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY */ .ev = { 0x03 }, .keys = { @@ -911,9 +912,8 @@ static const GuessTest guess_tests[] = .product_id = 0x6009, /* For some reason the special keys like mute and wlan toggle * show up here instead of, or in addition to, as part of - * the keyboard - so udev reports this as having keys too. - * SDL currently doesn't. */ - .expected = SDL_UDEV_DEVICE_MOUSE, + * the keyboard - so both udev and SDL report this as having keys too. */ + .expected = SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD, /* SYN, KEY, REL, MSC, LED */ .ev = { 0x17, 0x00, 0x02 }, /* X, Y */ diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c index 077a6abd3..17fb60bd3 100644 --- a/test/testgamecontroller.c +++ b/test/testgamecontroller.c @@ -529,6 +529,7 @@ main(int argc, char *argv[]) SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_ROG_CHAKRAM, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_SetHint(SDL_HINT_LINUX_JOYSTICK_DEADZONES, "1"); diff --git a/test/testgesture.c b/test/testgesture.c index b4bce6965..856fd6a2d 100644 --- a/test/testgesture.c +++ b/test/testgesture.c @@ -190,7 +190,8 @@ loop(void) case SDLK_i: { for (i = 0; i < SDL_GetNumTouchDevices(); ++i) { const SDL_TouchID id = SDL_GetTouchDevice(i); - SDL_Log("Fingers Down on device %"SDL_PRIs64": %d", id, SDL_GetNumTouchFingers(id)); + const char *name = SDL_GetTouchName(i); + SDL_Log("Fingers Down on device %"SDL_PRIs64" (%s): %d", id, name, SDL_GetNumTouchFingers(id)); } break; } diff --git a/test/testgles2.c b/test/testgles2.c index b6180aeaa..c42835ebb 100644 --- a/test/testgles2.c +++ b/test/testgles2.c @@ -38,6 +38,18 @@ typedef struct GLES2_Context #undef SDL_PROC } GLES2_Context; +typedef struct shader_data +{ + GLuint shader_program, shader_frag, shader_vert; + + GLint attr_position; + GLint attr_color, attr_mvp; + + int angle_x, angle_y, angle_z; + + GLuint position_buffer; + GLuint color_buffer; +} shader_data; static SDLTest_CommonState *state; static SDL_GLContext *context = NULL; @@ -197,13 +209,13 @@ multiply_matrix(float *lhs, float *rhs, float *r) * source: Passed-in shader source code. * shader_type: Passed to GL, e.g. GL_VERTEX_SHADER. */ -void +static void process_shader(GLuint *shader, const char * source, GLint shader_type) { GLint status = GL_FALSE; const char *shaders[1] = { NULL }; char buffer[1024]; - GLsizei length; + GLsizei length = 0; /* Create shader and load into GL. */ *shader = GL_CHECK(ctx.glCreateShader(shader_type)); @@ -221,13 +233,35 @@ process_shader(GLuint *shader, const char * source, GLint shader_type) /* Dump debug info (source and log) if compilation failed. */ if(status != GL_TRUE) { - ctx.glGetProgramInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); + ctx.glGetShaderInfoLog(*shader, sizeof(buffer), &length, &buffer[0]); buffer[length] = '\0'; - SDL_Log("Shader compilation failed: %s", buffer);fflush(stderr); + SDL_Log("Shader compilation failed: %s", buffer); + fflush(stderr); quit(-1); } } +static void +link_program(struct shader_data *data) +{ + GLint status = GL_FALSE; + char buffer[1024]; + GLsizei length = 0; + + GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); + GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); + GL_CHECK(ctx.glLinkProgram(data->shader_program)); + GL_CHECK(ctx.glGetProgramiv(data->shader_program, GL_LINK_STATUS, &status)); + + if(status != GL_TRUE) { + ctx.glGetProgramInfoLog(data->shader_program, sizeof(buffer), &length, &buffer[0]); + buffer[length] = '\0'; + SDL_Log("Program linking failed: %s", buffer); + fflush(stderr); + quit(-1); + } +} + /* 3D data. Vertex range -0.5..0.5 in all axes. * Z -0.5 is near, 0.5 is far. */ const float _vertices[] = @@ -363,17 +397,6 @@ const char* _shader_frag_src = " gl_FragColor = vec4(vv3color, 1.0); " " } "; -typedef struct shader_data -{ - GLuint shader_program, shader_frag, shader_vert; - - GLint attr_position; - GLint attr_color, attr_mvp; - - int angle_x, angle_y, angle_z; - -} shader_data; - static void Render(unsigned int width, unsigned int height, shader_data* data) { @@ -670,9 +693,7 @@ main(int argc, char *argv[]) data->shader_program = GL_CHECK(ctx.glCreateProgram()); /* Attach shaders and link shader_program */ - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_vert)); - GL_CHECK(ctx.glAttachShader(data->shader_program, data->shader_frag)); - GL_CHECK(ctx.glLinkProgram(data->shader_program)); + link_program(data); /* Get attribute locations of non-fixed attributes like color and texture coordinates. */ data->attr_position = GL_CHECK(ctx.glGetAttribLocation(data->shader_program, "av4position")); @@ -688,8 +709,18 @@ main(int argc, char *argv[]) GL_CHECK(ctx.glEnableVertexAttribArray(data->attr_color)); /* Populate attributes for position, color and texture coordinates etc. */ - GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, _vertices)); - GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, _colors)); + + GL_CHECK(ctx.glGenBuffers(1, &data->position_buffer)); + GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->position_buffer)); + GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_vertices), _vertices, GL_STATIC_DRAW)); + GL_CHECK(ctx.glVertexAttribPointer(data->attr_position, 3, GL_FLOAT, GL_FALSE, 0, 0)); + GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); + + GL_CHECK(ctx.glGenBuffers(1, &data->color_buffer)); + GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, data->color_buffer)); + GL_CHECK(ctx.glBufferData(GL_ARRAY_BUFFER, sizeof(_colors), _colors, GL_STATIC_DRAW)); + GL_CHECK(ctx.glVertexAttribPointer(data->attr_color, 3, GL_FLOAT, GL_FALSE, 0, 0)); + GL_CHECK(ctx.glBindBuffer(GL_ARRAY_BUFFER, 0)); GL_CHECK(ctx.glEnable(GL_CULL_FACE)); GL_CHECK(ctx.glEnable(GL_DEPTH_TEST)); diff --git a/test/testmouse.c b/test/testmouse.c index 0c9f7ee10..11a176066 100644 --- a/test/testmouse.c +++ b/test/testmouse.c @@ -39,6 +39,11 @@ static Line *active = NULL; static Line *lines = NULL; static int buttons = 0; +static SDL_bool wheel_x_active = SDL_FALSE; +static SDL_bool wheel_y_active = SDL_FALSE; +static float wheel_x = SCREEN_WIDTH * 0.5f; +static float wheel_y = SCREEN_HEIGHT * 0.5f; + static SDL_bool done = SDL_FALSE; void @@ -81,6 +86,25 @@ loop(void *arg) /* Check for events */ while (SDL_PollEvent(&event)) { switch (event.type) { + case SDL_MOUSEWHEEL: + if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { + event.wheel.preciseX *= -1.0f; + event.wheel.preciseY *= -1.0f; + event.wheel.x *= -1; + event.wheel.y *= -1; + } + if (event.wheel.preciseX != 0.0f) { + wheel_x_active = SDL_TRUE; + /* "positive to the right and negative to the left" */ + wheel_x += event.wheel.preciseX * 10.0f; + } + if (event.wheel.preciseY != 0.0f) { + wheel_y_active = SDL_TRUE; + /* "positive away from the user and negative towards the user" */ + wheel_y -= event.wheel.preciseY * 10.0f; + } + break; + case SDL_MOUSEMOTION: if (!active) break; @@ -100,6 +124,8 @@ loop(void *arg) case SDL_BUTTON_LEFT: active->r = 255; buttons |= SDL_BUTTON_LMASK; break; case SDL_BUTTON_MIDDLE: active->g = 255; buttons |= SDL_BUTTON_MMASK; break; case SDL_BUTTON_RIGHT: active->b = 255; buttons |= SDL_BUTTON_RMASK; break; + case SDL_BUTTON_X1: active->r = 255; active->b = 255; buttons |= SDL_BUTTON_X1MASK; break; + case SDL_BUTTON_X2: active->g = 255; active->b = 255; buttons |= SDL_BUTTON_X2MASK; break; } break; case SDL_MOUSEBUTTONUP: @@ -110,6 +136,8 @@ loop(void *arg) case SDL_BUTTON_LEFT: buttons &= ~SDL_BUTTON_LMASK; break; case SDL_BUTTON_MIDDLE: buttons &= ~SDL_BUTTON_MMASK; break; case SDL_BUTTON_RIGHT: buttons &= ~SDL_BUTTON_RMASK; break; + case SDL_BUTTON_X1: buttons &= ~SDL_BUTTON_X1MASK; break; + case SDL_BUTTON_X2: buttons &= ~SDL_BUTTON_X2MASK; break; } if (buttons == 0) { @@ -130,6 +158,16 @@ loop(void *arg) SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); + /* Mouse wheel */ + SDL_SetRenderDrawColor(renderer, 0, 255, 128, 255); + if (wheel_x_active) { + SDL_RenderDrawLine(renderer, wheel_x, 0, wheel_x, SCREEN_HEIGHT); + } + if (wheel_y_active) { + SDL_RenderDrawLine(renderer, 0, wheel_y, SCREEN_WIDTH, wheel_y); + } + + /* Lines from mouse clicks */ DrawLines(renderer); if (active) DrawLine(renderer, active); diff --git a/test/testplatform.c b/test/testplatform.c index 107c277b6..5aa649c12 100644 --- a/test/testplatform.c +++ b/test/testplatform.c @@ -25,31 +25,31 @@ badsize(size_t sizeoftype, size_t hardcodetype) return sizeoftype != hardcodetype; } +SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT8, SDL_MAX_SINT8 == 127); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT8, SDL_MIN_SINT8 == -128); +SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT8, SDL_MAX_UINT8 == 255); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT8, SDL_MIN_UINT8 == 0); + +SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT16, SDL_MAX_SINT16 == 32767); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT16, SDL_MIN_SINT16 == -32768); +SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT16, SDL_MAX_UINT16 == 65535); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT16, SDL_MIN_UINT16 == 0); + +SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT32, SDL_MAX_SINT32 == 2147483647); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT32, SDL_MIN_SINT32 == ~0x7fffffff); /* Instead of -2147483648, which is treated as unsigned by some compilers */ +SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT32, SDL_MAX_UINT32 == 4294967295u); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT32, SDL_MIN_UINT32 == 0); + +SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT64, SDL_MAX_SINT64 == 9223372036854775807ll); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT64, SDL_MIN_SINT64 == ~0x7fffffffffffffffll); /* Instead of -9223372036854775808, which is treated as unsigned by compilers */ +SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT64, SDL_MAX_UINT64 == 18446744073709551615ull); +SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT64, SDL_MIN_UINT64 == 0); + int TestTypes(SDL_bool verbose) { int error = 0; - SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT8, SDL_MAX_SINT8 == 127); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT8, SDL_MIN_SINT8 == -128); - SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT8, SDL_MAX_UINT8 == 255); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT8, SDL_MIN_UINT8 == 0); - - SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT16, SDL_MAX_SINT16 == 32767); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT16, SDL_MIN_SINT16 == -32768); - SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT16, SDL_MAX_UINT16 == 65535); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT16, SDL_MIN_UINT16 == 0); - - SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT32, SDL_MAX_SINT32 == 2147483647); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT32, SDL_MIN_SINT32 == ~0x7fffffff); /* Instead of -2147483648, which is treated as unsigned by some compilers */ - SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT32, SDL_MAX_UINT32 == 4294967295u); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT32, SDL_MIN_UINT32 == 0); - - SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT64, SDL_MAX_SINT64 == 9223372036854775807ll); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT64, SDL_MIN_SINT64 == ~0x7fffffffffffffffll); /* Instead of -9223372036854775808, which is treated as unsigned by compilers */ - SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT64, SDL_MAX_UINT64 == 18446744073709551615ull); - SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT64, SDL_MIN_UINT64 == 0); - if (badsize(sizeof(Uint8), 1)) { if (verbose) SDL_Log("sizeof(Uint8) != 1, instead = %u\n", diff --git a/test/testshader.c b/test/testshader.c index 2cee7d9b3..3c2da590f 100644 --- a/test/testshader.c +++ b/test/testshader.c @@ -126,21 +126,52 @@ static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; static SDL_bool CompileShader(GLhandleARB shader, const char *source) { - GLint status; + GLint status = 0; glShaderSourceARB(shader, 1, &source, NULL); glCompileShaderARB(shader); glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); if (status == 0) { - GLint length; + GLint length = 0; char *info; glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); - info = SDL_stack_alloc(char, length+1); - glGetInfoLogARB(shader, length, NULL, info); - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); - SDL_stack_free(info); + info = (char *) SDL_malloc(length + 1); + if (!info) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); + } else { + glGetInfoLogARB(shader, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); + SDL_free(info); + } + return SDL_FALSE; + } else { + return SDL_TRUE; + } +} +static SDL_bool LinkProgram(ShaderData *data) +{ + GLint status = 0; + + glAttachObjectARB(data->program, data->vert_shader); + glAttachObjectARB(data->program, data->frag_shader); + glLinkProgramARB(data->program); + + glGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status); + if (status == 0) { + GLint length = 0; + char *info; + + glGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + info = (char *) SDL_malloc(length + 1); + if (!info) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); + } else { + glGetInfoLogARB(data->program, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:\n%s", info); + SDL_free(info); + } return SDL_FALSE; } else { return SDL_TRUE; @@ -171,9 +202,9 @@ static SDL_bool CompileShaderProgram(ShaderData *data) } /* ... and in the darkness bind them */ - glAttachObjectARB(data->program, data->vert_shader); - glAttachObjectARB(data->program, data->frag_shader); - glLinkProgramARB(data->program); + if (!LinkProgram(data)) { + return SDL_FALSE; + } /* Set up some uniform variables */ glUseProgramObjectARB(data->program); diff --git a/wayland-protocols/tablet-unstable-v2.xml b/wayland-protocols/tablet-unstable-v2.xml new file mode 100644 index 000000000..b286d964a --- /dev/null +++ b/wayland-protocols/tablet-unstable-v2.xml @@ -0,0 +1,1178 @@ + + + + + Copyright 2014 © Stephen "Lyude" Chandler Paul + Copyright 2015-2016 © Red Hat, Inc. + + 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 (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, 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. + + + + This description provides a high-level overview of the interplay between + the interfaces defined this protocol. For details, see the protocol + specification. + + More than one tablet may exist, and device-specifics matter. Tablets are + not represented by a single virtual device like wl_pointer. A client + binds to the tablet manager object which is just a proxy object. From + that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat) + and that returns the actual interface that has all the tablets. With + this indirection, we can avoid merging wp_tablet into the actual Wayland + protocol, a long-term benefit. + + The wp_tablet_seat sends a "tablet added" event for each tablet + connected. That event is followed by descriptive events about the + hardware; currently that includes events for name, vid/pid and + a wp_tablet.path event that describes a local path. This path can be + used to uniquely identify a tablet or get more information through + libwacom. Emulated or nested tablets can skip any of those, e.g. a + virtual tablet may not have a vid/pid. The sequence of descriptive + events is terminated by a wp_tablet.done event to signal that a client + may now finalize any initialization for that tablet. + + Events from tablets require a tool in proximity. Tools are also managed + by the tablet seat; a "tool added" event is sent whenever a tool is new + to the compositor. That event is followed by a number of descriptive + events about the hardware; currently that includes capabilities, + hardware id and serial number, and tool type. Similar to the tablet + interface, a wp_tablet_tool.done event is sent to terminate that initial + sequence. + + Any event from a tool happens on the wp_tablet_tool interface. When the + tool gets into proximity of the tablet, a proximity_in event is sent on + the wp_tablet_tool interface, listing the tablet and the surface. That + event is followed by a motion event with the coordinates. After that, + it's the usual motion, axis, button, etc. events. The protocol's + serialisation means events are grouped by wp_tablet_tool.frame events. + + Two special events (that don't exist in X) are down and up. They signal + "tip touching the surface". For tablets without real proximity + detection, the sequence is: proximity_in, motion, down, frame. + + When the tool leaves proximity, a proximity_out event is sent. If any + button is still down, a button release event is sent before this + proximity event. These button events are sent in the same frame as the + proximity event to signal to the client that the buttons were held when + the tool left proximity. + + If the tool moves out of the surface but stays in proximity (i.e. + between windows), compositor-specific grab policies apply. This usually + means that the proximity-out is delayed until all buttons are released. + + Moving a tool physically from one tablet to the other has no real effect + on the protocol, since we already have the tool object from the "tool + added" event. All the information is already there and the proximity + events on both tablets are all a client needs to reconstruct what + happened. + + Some extra axes are normalized, i.e. the client knows the range as + specified in the protocol (e.g. [0, 65535]), the granularity however is + unknown. The current normalized axes are pressure, distance, and slider. + + Other extra axes are in physical units as specified in the protocol. + The current extra axes with physical units are tilt, rotation and + wheel rotation. + + Since tablets work independently of the pointer controlled by the mouse, + the focus handling is independent too and controlled by proximity. + The wp_tablet_tool.set_cursor request sets a tool-specific cursor. + This cursor surface may be the same as the mouse cursor, and it may be + the same across tools but it is possible to be more fine-grained. For + example, a client may set different cursors for the pen and eraser. + + Tools are generally independent of tablets and it is + compositor-specific policy when a tool can be removed. Common approaches + will likely include some form of removing a tool when all tablets the + tool was used on are removed. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + An object that provides access to the graphics tablets available on this + system. All tablets are associated with a seat, to get access to the + actual tablets, use wp_tablet_manager.get_tablet_seat. + + + + + Get the wp_tablet_seat object for the given seat. This object + provides access to all graphics tablets in this seat. + + + + + + + + Destroy the wp_tablet_manager object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + + An object that provides access to the graphics tablets available on this + seat. After binding to this interface, the compositor sends a set of + wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. + + + + + Destroy the wp_tablet_seat object. Objects created from this + object are unaffected and should be destroyed separately. + + + + + + This event is sent whenever a new tablet becomes available on this + seat. This event only provides the object id of the tablet, any + static information about the tablet (device name, vid/pid, etc.) is + sent through the wp_tablet interface. + + + + + + + This event is sent whenever a tool that has not previously been used + with a tablet comes into use. This event only provides the object id + of the tool; any static information about the tool (capabilities, + type, etc.) is sent through the wp_tablet_tool interface. + + + + + + + This event is sent whenever a new pad is known to the system. Typically, + pads are physically attached to tablets and a pad_added event is + sent immediately after the wp_tablet_seat.tablet_added. + However, some standalone pad devices logically attach to tablets at + runtime, and the client must wait for wp_tablet_pad.enter to know + the tablet a pad is attached to. + + This event only provides the object id of the pad. All further + features (buttons, strips, rings) are sent through the wp_tablet_pad + interface. + + + + + + + + An object that represents a physical tool that has been, or is + currently in use with a tablet in this seat. Each wp_tablet_tool + object stays valid until the client destroys it; the compositor + reuses the wp_tablet_tool object to indicate that the object's + respective physical tool has come into proximity of a tablet again. + + A wp_tablet_tool object's relation to a physical tool depends on the + tablet's ability to report serial numbers. If the tablet supports + this capability, then the object represents a specific physical tool + and can be identified even when used on multiple tablets. + + A tablet tool has a number of static characteristics, e.g. tool type, + hardware_serial and capabilities. These capabilities are sent in an + event sequence after the wp_tablet_seat.tool_added event before any + actual events from this tool. This initial event sequence is + terminated by a wp_tablet_tool.done event. + + Tablet tool events are grouped by wp_tablet_tool.frame events. + Any events received before a wp_tablet_tool.frame event should be + considered part of the same hardware state change. + + + + + Sets the surface of the cursor used for this tool on the given + tablet. This request only takes effect if the tool is in proximity + of one of the requesting client's surfaces or the surface parameter + is the current pointer surface. If there was a previous surface set + with this request it is replaced. If surface is NULL, the cursor + image is hidden. + + The parameters hotspot_x and hotspot_y define the position of the + pointer surface relative to the pointer location. Its top-left corner + is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the + coordinates of the pointer location, in surface-local coordinates. + + On surface.attach requests to the pointer surface, hotspot_x and + hotspot_y are decremented by the x and y parameters passed to the + request. Attach must be confirmed by wl_surface.commit as usual. + + The hotspot can also be updated by passing the currently set pointer + surface to this request with new values for hotspot_x and hotspot_y. + + The current and pending input regions of the wl_surface are cleared, + and wl_surface.set_input_region is ignored until the wl_surface is no + longer used as the cursor. When the use as a cursor ends, the current + and pending input regions become undefined, and the wl_surface is + unmapped. + + This request gives the surface the role of a wp_tablet_tool cursor. A + surface may only ever be used as the cursor surface for one + wp_tablet_tool. If the surface already has another role or has + previously been used as cursor surface for a different tool, a + protocol error is raised. + + + + + + + + + + This destroys the client's resource for this tool object. + + + + + + Describes the physical type of a tool. The physical type of a tool + generally defines its base usage. + + The mouse tool represents a mouse-shaped tool that is not a relative + device but bound to the tablet's surface, providing absolute + coordinates. + + The lens tool is a mouse-shaped tool with an attached lens to + provide precision focus. + + + + + + + + + + + + + + The tool type is the high-level type of the tool and usually decides + the interaction expected from this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + If the physical tool can be identified by a unique 64-bit serial + number, this event notifies the client of this serial number. + + If multiple tablets are available in the same seat and the tool is + uniquely identifiable by the serial number, that tool may move + between tablets. + + Otherwise, if the tool has no serial number and this event is + missing, the tool is tied to the tablet it first comes into + proximity with. Even if the physical tool is used on multiple + tablets, separate wp_tablet_tool objects will be created, one per + tablet. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + + This event notifies the client of a hardware id available on this tool. + + The hardware id is a device-specific 64-bit id that provides extra + information about the tool in use, beyond the wl_tool.type + enumeration. The format of the id is specific to tablets made by + Wacom Inc. For example, the hardware id of a Wacom Grip + Pen (a stylus) is 0x802. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + + Describes extra capabilities on a tablet. + + Any tool must provide x and y values, extra axes are + device-specific. + + + + + + + + + + + + This event notifies the client of any capabilities of this tool, + beyond the main set of x/y axes and tip up/down detection. + + One event is sent for each extra capability available on this tool. + + This event is sent in the initial burst of events before the + wp_tablet_tool.done event. + + + + + + + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the tool to + be complete and finalize initialization of the tool. + + + + + + This event is sent when the tool is removed from the system and will + send no further events. Should the physical tool come back into + proximity later, a new wp_tablet_tool object will be created. + + It is compositor-dependent when a tool is removed. A compositor may + remove a tool on proximity out, tablet removal or any other reason. + A compositor may also keep a tool alive until shutdown. + + If the tool is currently in proximity, a proximity_out event will be + sent before the removed event. See wp_tablet_tool.proximity_out for + the handling of any buttons logically down. + + When this event is received, the client must wp_tablet_tool.destroy + the object. + + + + + + Notification that this tool is focused on a certain surface. + + This event can be received when the tool has moved from one surface to + another, or when the tool has come back into proximity above the + surface. + + If any button is logically down when the tool comes into proximity, + the respective button event is sent after the proximity_in event but + within the same frame as the proximity_in event. + + + + + + + + + Notification that this tool has either left proximity, or is no + longer focused on a certain surface. + + When the tablet tool leaves proximity of the tablet, button release + events are sent for each button that was held down at the time of + leaving proximity. These events are sent before the proximity_out + event but within the same wp_tablet.frame. + + If the tool stays within proximity of the tablet, but the focus + changes from one surface to another, a button release event may not + be sent until the button is actually released or the tool leaves the + proximity of the tablet. + + + + + + Sent whenever the tablet tool comes in contact with the surface of the + tablet. + + If the tool is already in contact with the tablet when entering the + input region, the client owning said region will receive a + wp_tablet.proximity_in event, followed by a wp_tablet.down + event and a wp_tablet.frame event. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool in + logical contact until a minimum physical pressure threshold is + exceeded. + + + + + + + Sent whenever the tablet tool stops making contact with the surface of + the tablet, or when the tablet tool moves out of the input region + and the compositor grab (if any) is dismissed. + + If the tablet tool moves out of the input region while in contact + with the surface of the tablet and the compositor does not have an + ongoing grab on the surface, the client owning said region will + receive a wp_tablet.up event, followed by a wp_tablet.proximity_out + event and a wp_tablet.frame event. If the compositor has an ongoing + grab on this device, this event sequence is sent whenever the grab + is dismissed in the future. + + Note that this event describes logical contact, not physical + contact. On some devices, a compositor may not consider a tool out + of logical contact until physical pressure falls below a specific + threshold. + + + + + + Sent whenever a tablet tool moves. + + + + + + + + Sent whenever the pressure axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that pressure may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + + + + + + + Sent whenever the distance axis on a tool changes. The value of this + event is normalized to a value between 0 and 65535. + + Note that distance may be nonzero even when a tool is not in logical + contact. See the down and up events for more details. + + + + + + + Sent whenever one or both of the tilt axes on a tool change. Each tilt + value is in degrees, relative to the z-axis of the tablet. + The angle is positive when the top of a tool tilts along the + positive x or y axis. + + + + + + + + Sent whenever the z-rotation axis on the tool changes. The + rotation value is in degrees clockwise from the tool's + logical neutral position. + + + + + + + Sent whenever the slider position on the tool changes. The + value is normalized between -65535 and 65535, with 0 as the logical + neutral position of the slider. + + The slider is available on e.g. the Wacom Airbrush tool. + + + + + + + Sent whenever the wheel on the tool emits an event. This event + contains two values for the same axis change. The degrees value is + in the same orientation as the wl_pointer.vertical_scroll axis. The + clicks value is in discrete logical clicks of the mouse wheel. This + value may be zero if the movement of the wheel was less + than one logical click. + + Clients should choose either value and avoid mixing degrees and + clicks. The compositor may accumulate values smaller than a logical + click and emulate click events when a certain threshold is met. + Thus, wl_tablet_tool.wheel events with non-zero clicks values may + have different degrees values. + + + + + + + + Describes the physical state of a button that produced the button event. + + + + + + + + Sent whenever a button on the tool is pressed or released. + + If a button is held down when the tool moves in or out of proximity, + button events are generated by the compositor. See + wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for + details. + + + + + + + + + Marks the end of a series of axis and/or button updates from the + tablet. The Wayland protocol requires axis updates to be sent + sequentially, however all events within a frame should be considered + one hardware event. + + + + + + + + + + + + The wp_tablet interface represents one graphics tablet device. The + tablet interface itself does not generate events; all events are + generated by wp_tablet_tool objects when in proximity above a tablet. + + A tablet has a number of static characteristics, e.g. device name and + pid/vid. These capabilities are sent in an event sequence after the + wp_tablet_seat.tablet_added event. This initial event sequence is + terminated by a wp_tablet.done event. + + + + + This destroys the client's resource for this tablet object. + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + + A system-specific device path that indicates which device is behind + this wp_tablet. This information may be used to gather additional + information about the device, e.g. through libwacom. + + A device may have more than one device path. If so, multiple + wp_tablet.path events are sent. A device may be emulated and not + have a device path, and in that case this event will not be sent. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet.done event. + + + + + + + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet. + + + + + + Sent when the tablet has been removed from the system. When a tablet + is removed, some tools may be removed. + + When this event is received, the client must wp_tablet.destroy + the object. + + + + + + + A circular interaction area, such as the touch ring on the Wacom Intuos + Pro series tablets. + + Events on a ring are logically grouped by the wl_tablet_pad_ring.frame + event. + + + + + Request that the compositor use the provided feedback string + associated with this ring. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the ring is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the ring; compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + ring. Requests providing other serials than the most recent one will be + ignored. + + + + + + + + This destroys the client's resource for this ring object. + + + + + + Describes the source types for ring events. This indicates to the + client how a ring event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + + + + + + + Source information for ring events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_ring.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event + will be sent when the user lifts the finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + + + + + + + Sent whenever the angle on a ring changes. + + The angle is provided in degrees clockwise from the logical + north of the ring in the pad's current rotation. + + + + + + + Stop notification for ring events. + + For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop + event is sent to notify a client that the interaction with the ring + has terminated. This enables the client to implement kinetic scrolling. + See the wp_tablet_pad_ring.source documentation for information on + when this event may be generated. + + Any wp_tablet_pad_ring.angle events with the same source after this + event should be considered as the start of a new interaction. + + + + + + Indicates the end of a set of ring events that logically belong + together. A client is expected to accumulate the data in all events + within the frame before proceeding. + + All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong + logically together. For example, on termination of a finger interaction + on a ring the compositor will send a wp_tablet_pad_ring.source event, + a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event. + + A wp_tablet_pad_ring.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_ring + event. Specifically, a client may get a sequence: angle, frame, + angle, frame, etc. + + + + + + + + A linear interaction area, such as the strips found in Wacom Cintiq + models. + + Events on a strip are logically grouped by the wl_tablet_pad_strip.frame + event. + + + + + Requests the compositor to use the provided feedback string + associated with this strip. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever the strip is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with the strip, and compositors may use this + information to offer visual feedback about the button layout + (eg. on-screen displays). + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + strip. Requests providing other serials than the most recent one will be + ignored. + + + + + + + + This destroys the client's resource for this strip object. + + + + + + Describes the source types for strip events. This indicates to the + client how a strip event was physically generated; a client may + adjust the user interface accordingly. For example, events + from a "finger" source may trigger kinetic scrolling. + + + + + + + Source information for strip events. + + This event does not occur on its own. It is sent before a + wp_tablet_pad_strip.frame event and carries the source information + for all events within that frame. + + The source specifies how this event was generated. If the source is + wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event + will be sent when the user lifts their finger off the device. + + This event is optional. If the source is unknown for an interaction, + no event is sent. + + + + + + + Sent whenever the position on a strip changes. + + The position is normalized to a range of [0, 65535], the 0-value + represents the top-most and/or left-most position of the strip in + the pad's current rotation. + + + + + + + Stop notification for strip events. + + For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop + event is sent to notify a client that the interaction with the strip + has terminated. This enables the client to implement kinetic + scrolling. See the wp_tablet_pad_strip.source documentation for + information on when this event may be generated. + + Any wp_tablet_pad_strip.position events with the same source after this + event should be considered as the start of a new interaction. + + + + + + Indicates the end of a set of events that represent one logical + hardware strip event. A client is expected to accumulate the data + in all events within the frame before proceeding. + + All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong + logically together. For example, on termination of a finger interaction + on a strip the compositor will send a wp_tablet_pad_strip.source event, + a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame + event. + + A wp_tablet_pad_strip.frame event is sent for every logical event + group, even if the group only contains a single wp_tablet_pad_strip + event. Specifically, a client may get a sequence: position, frame, + position, frame, etc. + + + + + + + + A pad group describes a distinct (sub)set of buttons, rings and strips + present in the tablet. The criteria of this grouping is usually positional, + eg. if a tablet has buttons on the left and right side, 2 groups will be + presented. The physical arrangement of groups is undisclosed and may + change on the fly. + + Pad groups will announce their features during pad initialization. Between + the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the + pad group will announce the buttons, rings and strips contained in it, + plus the number of supported modes. + + Modes are a mechanism to allow multiple groups of actions for every element + in the pad group. The number of groups and available modes in each is + persistent across device plugs. The current mode is user-switchable, it + will be announced through the wp_tablet_pad_group.mode_switch event both + whenever it is switched, and after wp_tablet_pad.enter. + + The current mode logically applies to all elements in the pad group, + although it is at clients' discretion whether to actually perform different + actions, and/or issue the respective .set_feedback requests to notify the + compositor. See the wp_tablet_pad_group.mode_switch event for more details. + + + + + Destroy the wp_tablet_pad_group object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + Sent on wp_tablet_pad_group initialization to announce the available + buttons in the group. Button indices start at 0, a button may only be + in one group at a time. + + This event is first sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + Some buttons are reserved by the compositor. These buttons may not be + assigned to any wp_tablet_pad_group. Compositors may broadcast this + event in the case of changes to the mapping of these reserved buttons. + If the compositor happens to reserve all buttons in a group, this event + will be sent with an empty array. + + + + + + + Sent on wp_tablet_pad_group initialization to announce available rings. + One event is sent for each ring available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + + + + + + Sent on wp_tablet_pad initialization to announce available strips. + One event is sent for each strip available on this pad group. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. + + + + + + + Sent on wp_tablet_pad_group initialization to announce that the pad + group may switch between modes. A client may use a mode to store a + specific configuration for buttons, rings and strips and use the + wl_tablet_pad_group.mode_switch event to toggle between these + configurations. Mode indices start at 0. + + Switching modes is compositor-dependent. See the + wp_tablet_pad_group.mode_switch event for more details. + + This event is sent in the initial burst of events before the + wp_tablet_pad_group.done event. This event is only sent when more than + more than one mode is available. + + + + + + + This event is sent immediately to signal the end of the initial + burst of descriptive events. A client may consider the static + description of the tablet to be complete and finalize initialization + of the tablet group. + + + + + + Notification that the mode was switched. + + A mode applies to all buttons, rings and strips in a group + simultaneously, but a client is not required to assign different actions + for each mode. For example, a client may have mode-specific button + mappings but map the ring to vertical scrolling in all modes. Mode + indices start at 0. + + Switching modes is compositor-dependent. The compositor may provide + visual cues to the client about the mode, e.g. by toggling LEDs on + the tablet device. Mode-switching may be software-controlled or + controlled by one or more physical buttons. For example, on a Wacom + Intuos Pro, the button inside the ring may be assigned to switch + between modes. + + The compositor will also send this event after wp_tablet_pad.enter on + each group in order to notify of the current mode. Groups that only + feature one mode will use mode=0 when emitting this event. + + If a button action in the new mode differs from the action in the + previous mode, the client should immediately issue a + wp_tablet_pad.set_feedback request for each changed button. + + If a ring or strip action in the new mode differs from the action + in the previous mode, the client should immediately issue a + wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request + for each changed ring or strip. + + + + + + + + + + A pad device is a set of buttons, rings and strips + usually physically present on the tablet device itself. Some + exceptions exist where the pad device is physically detached, e.g. the + Wacom ExpressKey Remote. + + Pad devices have no axes that control the cursor and are generally + auxiliary devices to the tool devices used on the tablet surface. + + A pad device has a number of static characteristics, e.g. the number + of rings. These capabilities are sent in an event sequence after the + wp_tablet_seat.pad_added event before any actual events from this pad. + This initial event sequence is terminated by a wp_tablet_pad.done + event. + + All pad features (buttons, rings and strips) are logically divided into + groups and all pads have at least one group. The available groups are + notified through the wp_tablet_pad.group event; the compositor will + emit one event per group before emitting wp_tablet_pad.done. + + Groups may have multiple modes. Modes allow clients to map multiple + actions to a single pad feature. Only one mode can be active per group, + although different groups may have different active modes. + + + + + Requests the compositor to use the provided feedback string + associated with this button. This request should be issued immediately + after a wp_tablet_pad_group.mode_switch event from the corresponding + group is received, or whenever a button is mapped to a different + action. See wp_tablet_pad_group.mode_switch for more details. + + Clients are encouraged to provide context-aware descriptions for + the actions associated with each button, and compositors may use + this information to offer visual feedback on the button layout + (e.g. on-screen displays). + + Button indices start at 0. Setting the feedback string on a button + that is reserved by the compositor (i.e. not belonging to any + wp_tablet_pad_group) does not generate an error but the compositor + is free to ignore the request. + + The provided string 'description' is a UTF-8 encoded string to be + associated with this ring, and is considered user-visible; general + internationalization rules apply. + + The serial argument will be that of the last + wp_tablet_pad_group.mode_switch event received for the group of this + button. Requests providing other serials than the most recent one will + be ignored. + + + + + + + + + Destroy the wp_tablet_pad object. Objects created from this object + are unaffected and should be destroyed separately. + + + + + + Sent on wp_tablet_pad initialization to announce available groups. + One event is sent for each pad group available. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. At least one group will be announced. + + + + + + + A system-specific device path that indicates which device is behind + this wp_tablet_pad. This information may be used to gather additional + information about the device, e.g. through libwacom. + + The format of the path is unspecified, it may be a device node, a + sysfs path, or some other identifier. It is up to the client to + identify the string provided. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. + + + + + + + Sent on wp_tablet_pad initialization to announce the available + buttons. + + This event is sent in the initial burst of events before the + wp_tablet_pad.done event. This event is only sent when at least one + button is available. + + + + + + + This event signals the end of the initial burst of descriptive + events. A client may consider the static description of the pad to + be complete and finalize initialization of the pad. + + + + + + Describes the physical state of a button that caused the button + event. + + + + + + + + Sent whenever the physical state of a button changes. + + + + + + + + + Notification that this pad is focused on the specified surface. + + + + + + + + + Notification that this pad is no longer focused on the specified + surface. + + + + + + + + Sent when the pad has been removed from the system. When a tablet + is removed its pad(s) will be removed too. + + When this event is received, the client must destroy all rings, strips + and groups that were offered by this pad, and issue wp_tablet_pad.destroy + the pad itself. + + + + diff --git a/wayland-protocols/viewporter.xml b/wayland-protocols/viewporter.xml new file mode 100644 index 000000000..c732d8c35 --- /dev/null +++ b/wayland-protocols/viewporter.xml @@ -0,0 +1,186 @@ + + + + + Copyright © 2013-2016 Collabora, Ltd. + + 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 (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, + 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. + + + + + The global interface exposing surface cropping and scaling + capabilities is used to instantiate an interface extension for a + wl_surface object. This extended interface will then allow + cropping and scaling the surface contents, effectively + disconnecting the direct relationship between the buffer and the + surface size. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other objects, + wp_viewport objects included. + + + + + + + + + + Instantiate an interface extension for the given wl_surface to + crop and scale its content. If the given wl_surface already has + a wp_viewport object associated, the viewport_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object, which allows the + client to specify the cropping and scaling of the surface + contents. + + This interface works with two concepts: the source rectangle (src_x, + src_y, src_width, src_height), and the destination size (dst_width, + dst_height). The contents of the source rectangle are scaled to the + destination size, and content outside the source rectangle is ignored. + This state is double-buffered, and is applied on the next + wl_surface.commit. + + The two parts of crop and scale state are independent: the source + rectangle, and the destination size. Initially both are unset, that + is, no scaling is applied. The whole of the current wl_buffer is + used as the source, and the surface size is as defined in + wl_surface.attach. + + If the destination size is set, it causes the surface size to become + dst_width, dst_height. The source (rectangle) is scaled to exactly + this size. This overrides whatever the attached wl_buffer size is, + unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + has no content and therefore no size. Otherwise, the size is always + at least 1x1 in surface local coordinates. + + If the source rectangle is set, it defines what area of the wl_buffer is + taken as the source. If the source rectangle is set and the destination + size is not set, then src_width and src_height must be integers, and the + surface size becomes the source rectangle size. This results in cropping + without scaling. If src_width or src_height are not integers and + destination size is not set, the bad_size protocol error is raised when + the surface state is applied. + + The coordinate transformations from buffer pixel coordinates up to + the surface-local coordinates happen in the following order: + 1. buffer_transform (wl_surface.set_buffer_transform) + 2. buffer_scale (wl_surface.set_buffer_scale) + 3. crop and scale (wp_viewport.set*) + This means, that the source rectangle coordinates of crop and scale + are given in the coordinates after the buffer transform and scale, + i.e. in the coordinates that would be the surface-local coordinates + if the crop and scale was not applied. + + If src_x or src_y are negative, the bad_value protocol error is raised. + Otherwise, if the source rectangle is partially or completely outside of + the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + when the surface state is applied. A NULL wl_buffer does not raise the + out_of_buffer error. + + The x, y arguments of wl_surface.attach are applied as normal to + the surface. They indicate how many pixels to remove from the + surface size from the left and the top. In other words, they are + still in the surface-local coordinate system, just like dst_width + and dst_height are. + + If the wl_surface associated with the wp_viewport is destroyed, + all wp_viewport requests except 'destroy' raise the protocol error + no_surface. + + If the wp_viewport object is destroyed, the crop and scale + state is removed from the wl_surface. The change will be applied + on the next wl_surface.commit. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + + + + Set the source rectangle of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If all of x, y, width and height are -1.0, the source rectangle is + unset instead. Any other set of values where width or height are zero + or negative, or x or y are negative, raise the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + + + + Set the destination size of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If width is -1 and height is -1, the destination size is unset + instead. Any other pair of values for width and height that + contains zero or negative values raises the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + diff --git a/wayland-protocols/xdg-output-unstable-v1.xml b/wayland-protocols/xdg-output-unstable-v1.xml new file mode 100644 index 000000000..9a5b79000 --- /dev/null +++ b/wayland-protocols/xdg-output-unstable-v1.xml @@ -0,0 +1,220 @@ + + + + + Copyright © 2017 Red Hat Inc. + + 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 (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, + 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. + + + + This protocol aims at describing outputs in a way which is more in line + with the concept of an output on desktop oriented systems. + + Some information are more specific to the concept of an output for + a desktop oriented system and may not make sense in other applications, + such as IVI systems for example. + + Typically, the global compositor space on a desktop system is made of + a contiguous or overlapping set of rectangular regions. + + Some of the information provided in this protocol might be identical + to their counterparts already available from wl_output, in which case + the information provided by this protocol should be preferred to their + equivalent in wl_output. The goal is to move the desktop specific + concepts (such as output location within the global compositor space, + the connector name and types, etc.) out of the core wl_output protocol. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + A global factory interface for xdg_output objects. + + + + + Using this request a client can tell the server that it is not + going to use the xdg_output_manager object anymore. + + Any objects already created through this instance are not affected. + + + + + + This creates a new xdg_output object for the given wl_output. + + + + + + + + + An xdg_output describes part of the compositor geometry. + + This typically corresponds to a monitor that displays part of the + compositor space. + + For objects version 3 onwards, after all xdg_output properties have been + sent (when the object is created and when properties are updated), a + wl_output.done event is sent. This allows changes to the output + properties to be seen as atomic, even if they happen via multiple events. + + + + + Using this request a client can tell the server that it is not + going to use the xdg_output object anymore. + + + + + + The position event describes the location of the wl_output within + the global compositor space. + + The logical_position event is sent after creating an xdg_output + (see xdg_output_manager.get_xdg_output) and whenever the location + of the output changes within the global compositor space. + + + + + + + + The logical_size event describes the size of the output in the + global compositor space. + + For example, a surface without any buffer scale, transformation + nor rotation set, with the size matching the logical_size will + have the same size as the corresponding output when displayed. + + Most regular Wayland clients should not pay attention to the + logical size and would rather rely on xdg_shell interfaces. + + Some clients such as Xwayland, however, need this to configure + their surfaces in the global compositor space as the compositor + may apply a different scale from what is advertised by the output + scaling property (to achieve fractional scaling, for example). + + For example, for a wl_output mode 3840×2160 and a scale factor 2: + + - A compositor not scaling the surface buffers will advertise a + logical size of 3840×2160, + + - A compositor automatically scaling the surface buffers will + advertise a logical size of 1920×1080, + + - A compositor using a fractional scale of 1.5 will advertise a + logical size of 2560×1440. + + For example, for a wl_output mode 1920×1080 and a 90 degree rotation, + the compositor will advertise a logical size of 1080x1920. + + The logical_size event is sent after creating an xdg_output + (see xdg_output_manager.get_xdg_output) and whenever the logical + size of the output changes, either as a result of a change in the + applied scale or because of a change in the corresponding output + mode(see wl_output.mode) or transform (see wl_output.transform). + + + + + + + + This event is sent after all other properties of an xdg_output + have been sent. + + This allows changes to the xdg_output properties to be seen as + atomic, even if they happen via multiple events. + + For objects version 3 onwards, this event is deprecated. Compositors + are not required to send it anymore and must send wl_output.done + instead. + + + + + + + + Many compositors will assign names to their outputs, show them to the + user, allow them to be configured by name, etc. The client may wish to + know this name as well to offer the user similar behaviors. + + The naming convention is compositor defined, but limited to + alphanumeric characters and dashes (-). Each name is unique among all + wl_output globals, but if a wl_output global is destroyed the same name + may be reused later. The names will also remain consistent across + sessions with the same hardware and software configuration. + + Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do + not assume that the name is a reflection of an underlying DRM + connector, X11 connection, etc. + + The name event is sent after creating an xdg_output (see + xdg_output_manager.get_xdg_output). This event is only sent once per + xdg_output, and the name does not change over the lifetime of the + wl_output global. + + + + + + + Many compositors can produce human-readable descriptions of their + outputs. The client may wish to know this description as well, to + communicate the user for various purposes. + + The description is a UTF-8 string with no convention defined for its + contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11 + output via :1'. + + The description event is sent after creating an xdg_output (see + xdg_output_manager.get_xdg_output) and whenever the description + changes. The description is optional, and may not be sent at all. + + For objects of version 2 and lower, this event is only sent once per + xdg_output, and the description does not change over the lifetime of + the wl_output global. + + + + + +