diff options
author | James Cowgill <jcowgill@debian.org> | 2018-10-16 22:26:31 +0100 |
---|---|---|
committer | James Cowgill <jcowgill@debian.org> | 2018-10-16 22:26:31 +0100 |
commit | f57a5d96a92d1208d252b7d3f97b3b5c3b69fd12 (patch) | |
tree | f2c152c29b5cac3a1b21cbae02c82b006ae7cdb4 | |
parent | 088cbaedcc0634d0949ca8a92236e62a6d6caf71 (diff) | |
parent | 08bb1c372efcc9e2054e64b80959f025c8f43744 (diff) |
Update upstream source from tag 'upstream/2.5.1+dfsg'
Update to upstream version '2.5.1+dfsg'
with Debian dir 8171c41179aa4509b53f92cff2b893d4ceafc883
36 files changed, 987 insertions, 443 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index bb30b46..e821a49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,9 +32,6 @@ endif() if(NOT CMAKE_OSX_ARCHITECTURES) set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "macOS architecture to build; 64-bit is expected" FORCE) endif() -if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7" CACHE STRING "macOS deployement target; 10.7+ is expected" FORCE) -endif() if(NOT CMAKE_OSX_SYSROOT) # query the path to the default SDK, will fail on non-macOS, but it's okay. execute_process(COMMAND xcodebuild -sdk macosx -version Path @@ -53,7 +50,7 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake) # setup version numbers set(VERSION_MAJOR 2) set(VERSION_MINOR 5) -set(VERSION_PATCH 0) +set(VERSION_PATCH 1) # add an option for choosing the build type (shared or static) if(NOT (SFML_OS_IOS OR SFML_OS_ANDROID)) @@ -260,39 +257,10 @@ if(SFML_OS_MACOSX) message(FATAL_ERROR "Only 64-bit architecture is supported") endif() - # Ensure macOS 10.7+ is used - if(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.7") - message(FATAL_ERROR "macOS 10.7 or greater is required for the deployment target.") - endif() - # configure Xcode templates set(XCODE_TEMPLATES_ARCH "\$(NATIVE_ARCH_ACTUAL)") endif() -if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) - set(PKGCONFIG_DIR lib${LIB_SUFFIX}/pkgconfig) - if(SFML_OS_FREEBSD OR SFML_OS_OPENBSD) - set(PKGCONFIG_DIR libdata/pkgconfig) - endif() - if(BUILD_SHARED_LIBS) - sfml_set_option(SFML_INSTALL_PKGCONFIG_FILES FALSE BOOL "TRUE to automatically install pkg-config files so other projects can find SFML") - if(SFML_INSTALL_PKGCONFIG_FILES) - foreach(sfml_module IN ITEMS all system window graphics audio network) - CONFIGURE_FILE( - "tools/pkg-config/sfml-${sfml_module}.pc.in" - "tools/pkg-config/sfml-${sfml_module}.pc" - @ONLY) - INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/tools/pkg-config/sfml-${sfml_module}.pc" - DESTINATION "${CMAKE_INSTALL_PREFIX}/${PKGCONFIG_DIR}") - endforeach() - endif() - else() - if(SFML_INSTALL_PKGCONFIG_FILES) - message(WARNING "No pkg-config files are provided for the static SFML libraries (SFML_INSTALL_PKGCONFIG_FILES will be ignored).") - endif() - endif() -endif() - # enable project folders set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake") @@ -306,16 +274,25 @@ if(SFML_BUILD_DOC) add_subdirectory(doc) endif() -sfml_set_option(SFML_INSTALL_PKGCONFIG_FILES FALSE BOOL "TRUE to automatically install pkg-config files so other projects can find SFML") +# on Linux and BSD-like OS, install pkg-config files by default +set(SFML_INSTALL_PKGCONFIG_DEFAULT FALSE) + +if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD) + set(SFML_INSTALL_PKGCONFIG_DEFAULT TRUE) +endif() + +sfml_set_option(SFML_INSTALL_PKGCONFIG_FILES ${SFML_INSTALL_PKGCONFIG_DEFAULT} BOOL "TRUE to automatically install pkg-config files so other projects can find SFML") + +if(SFML_INSTALL_PKGCONFIG_FILES) + sfml_set_option(SFML_PKGCONFIG_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/${SFML_PKGCONFIG_DIR}" PATH "Install directory for SFML's pkg-config .pc files") -if(SFML_OS_SUPPORTS_PKGCONFIG OR SFML_INSTALL_PKGCONFIG_FILES) foreach(sfml_module IN ITEMS all system window graphics audio network) CONFIGURE_FILE( "tools/pkg-config/sfml-${sfml_module}.pc.in" "tools/pkg-config/sfml-${sfml_module}.pc" @ONLY) INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/tools/pkg-config/sfml-${sfml_module}.pc" - DESTINATION "${CMAKE_INSTALL_PREFIX}/${SFML_OS_PKGCONFIG_DIR}") + DESTINATION "${SFML_PKGCONFIG_INSTALL_PREFIX}") endforeach() endif() diff --git a/changelog.md b/changelog.md index c51ee3a..6174a84 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,53 @@ # Changelog +## SFML 2.5.1 + +Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.5.1 + +### General + + * Various CMake fixes (#1414, #1416, #1436, #1439, #1467, #1470) + * Fixed the installation of pkg-config files (#1466) + * Fixed two conversion warnings (#1454) + * [Android] Fixes all symbols in sfml-main are hidden (#1457, #1460) + * [Android] Fixed some `#define` flag problem (#1458) + * [Android] Fix deadlock in main cleanup (#1265) + * [iOS] Modernized toolchain file (#1411) + * [iOS] Check that `<SFML/Main.hpp>` is used (#1412) + * [macOS] Add `-ObjC` flag to fix static linking on macOS (#1485) + +### Window + +**Bugfixes** + + * [iOS] Use default supported rotations when none are specified (#1417) + * [iOS] Fixed autocomplete window overlaps keyboard (#1473, #1482) + * [Linux] Fixed dual monitor issue (#1226, #1238) + * [Linux] Fixed issue where fullscreen window didn't go over task bars on top and left on in Ubuntu (#1224) + * [Linux] Fixed the Unix clipboard implementation causing an abort due to internal data races in Xlib (#1437) + * [macOS] Added additional system cursors (#1401, #1413, #1425) + * [Windows] Fixed swapped colors for custom cursors (#1464, #1465, #1491) + +### Graphics + +**Bugfixes** + + * Fixed a bug in which a `sf::RenderTexture` would not be re-activated after being re-created (#1438) + * Fixed `sf::RenderTextureImplFBO`'s destructor incorrectly triggering deletion of other `sf::RenderTextureImplFBO`'s active FBOs (#1440) + * Fix `sf::RenderWindow::setActive` incorrectly trying to unbind an FBO during deactivation (#1442) + * Fixed `sf::RenderTexture::display()` dereferencing a NULL pointer when being called before `sf::RenderTexture::create()` (#1446) + * Fixed bug in `sf::Text` when applying an outline color/thickness (#1176) + * Squash duplicated `sf::Font` glyphs to single chars (#1461) + * Fixed two issues with glyph sub-pixel positioning (#1452) + * Reduced context locking & unlocking while creating textures (#1459) + * Fixed the error message when the wrong bitmap font size is selected (#1456, #1474, #1492) + +### Audio + +**Bugfixes** + + * Fixed performance issue with reading WAV files (#1450) + ## SFML 2.5.0 Also available on the website: https://www.sfml-dev.org/changelog.php#sfml-2.5.0 diff --git a/cmake/Config.cmake b/cmake/Config.cmake index 82a094c..0a28660 100644 --- a/cmake/Config.cmake +++ b/cmake/Config.cmake @@ -69,17 +69,12 @@ else() return() endif() -# check if OS or package system supports pkg-config +# set pkgconfig install directory # this could be e.g. macports on mac or msys2 on windows etc. -find_package(PkgConfig QUIET) -if(PKG_CONFIG_EXECUTABLE) - if(EXISTS "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig") - set(SFML_OS_SUPPORTS_PKGCONFIG ON) - set(SFML_OS_PKGCONFIG_DIR "/lib${LIB_SUFFIX}/pkgconfig") - elseif(EXISTS "${CMAKE_INSTALL_PREFIX}/libdata/pkgconfig") - set(SFML_OS_SUPPORTS_PKGCONFIG ON) - set(SFML_OS_PKGCONFIG_DIR "/libdata/pkgconfig") - endif() +set(SFML_PKGCONFIG_DIR "/lib${LIB_SUFFIX}/pkgconfig") + +if(SFML_OS_FREEBSD OR SFML_OS_OPENBSD) + set(SFML_PKGCONFIG_DIR "/libdata/pkgconfig") endif() # detect the compiler and its version diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index be52345..ecb37c8 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -1,7 +1,12 @@ include(CMakeParseArguments) +# This little macro lets you set any Xcode specific property +macro (sfml_set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) + set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) +endmacro () + # set the appropriate standard library on each platform for the given target -# ex: sfml_set_stdlib(sfml-system) +# example: sfml_set_stdlib(sfml-system) function(sfml_set_stdlib target) # for gcc >= 4.0 on Windows, apply the SFML_USE_STATIC_STD_LIBS option if it is enabled if(SFML_OS_WINDOWS AND SFML_COMPILER_GCC AND NOT SFML_GCC_VERSION VERSION_LESS "4") @@ -14,7 +19,7 @@ function(sfml_set_stdlib target) if (SFML_OS_MACOSX) if (${CMAKE_GENERATOR} MATCHES "Xcode") - set_property(TARGET ${target} PROPERTY XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + sfml_set_xcode_property(${target} CLANG_CXX_LIBRARY "libc++") else() target_compile_options(${target} PRIVATE "-stdlib=libc++") target_link_libraries(${target} PRIVATE "-stdlib=libc++") @@ -23,9 +28,9 @@ function(sfml_set_stdlib target) endfunction() # add a new target which is a SFML library -# ex: sfml_add_library(sfml-graphics -# SOURCES sprite.cpp image.cpp ... -# [STATIC]) # Always create a static library and ignore BUILD_SHARED_LIBS +# example: sfml_add_library(sfml-graphics +# SOURCES sprite.cpp image.cpp ... +# [STATIC]) # Always create a static library and ignore BUILD_SHARED_LIBS macro(sfml_add_library target) # parse the arguments @@ -178,11 +183,11 @@ macro(sfml_add_library target) endmacro() # add a new target which is a SFML example -# ex: sfml_add_example(ftp -# SOURCES ftp.cpp ... -# BUNDLE_RESOURCES MainMenu.nib ... # Files to be added in target but not installed next to the executable -# DEPENDS sfml-network -# RESOURCES_DIR resources) # A directory to install next to the executable and sources +# example: sfml_add_example(ftp +# SOURCES ftp.cpp ... +# BUNDLE_RESOURCES MainMenu.nib ... # Files to be added in target but not installed next to the executable +# DEPENDS sfml-network +# RESOURCES_DIR resources) # A directory to install next to the executable and sources macro(sfml_add_example target) # parse the arguments @@ -320,7 +325,7 @@ function(sfml_export_targets) if (SFML_BUILD_FRAMEWORKS) set(config_package_location "SFML.framework/Resources/CMake") else() - set(config_package_location lib/cmake/SFML) + set(config_package_location lib${LIB_SUFFIX}/cmake/SFML) endif() configure_package_config_file("${CURRENT_DIR}/SFMLConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/SFMLConfig.cmake" INSTALL_DESTINATION "${config_package_location}") diff --git a/cmake/SFMLConfigDependencies.cmake.in b/cmake/SFMLConfigDependencies.cmake.in index 2f85b38..1028110 100644 --- a/cmake/SFMLConfigDependencies.cmake.in +++ b/cmake/SFMLConfigDependencies.cmake.in @@ -13,7 +13,11 @@ if(SFML_STATIC_LIBRARIES) elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(FIND_SFML_OS_FREEBSD 1) elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(FIND_SFML_OS_MACOSX 1) + if (DEFINED IOS) + set(FIND_SFML_OS_IOS 1) + else() + set(FIND_SFML_OS_MACOSX 1) + endif() endif() # start with an empty list @@ -51,7 +55,7 @@ if(SFML_STATIC_LIBRARIES) if (FIND_SFML_OS_WINDOWS) set_property(TARGET OpenGL APPEND PROPERTY INTERFACE_LINK_LIBRARIES "OpenGL32") - else() + elseif(NOT FIND_SFML_OS_IOS) sfml_bind_dependency(TARGET OpenGL FRIENDLY_NAME "OpenGL" SEARCH_NAMES "OpenGL" "GL") endif() endif() @@ -66,10 +70,12 @@ if(SFML_STATIC_LIBRARIES) list(FIND SFML_FIND_COMPONENTS "audio" FIND_SFML_AUDIO_COMPONENT_INDEX) if(FIND_SFML_AUDIO_COMPONENT_INDEX GREATER -1) sfml_bind_dependency(TARGET OpenAL FRIENDLY_NAME "OpenAL" SEARCH_NAMES "OpenAL" "openal" "openal32") - sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Ogg" SEARCH_NAMES "ogg") + if (NOT FIND_SFML_OS_IOS) + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisFile" SEARCH_NAMES "vorbisfile") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisEnc" SEARCH_NAMES "vorbisenc") + endif() sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Vorbis" SEARCH_NAMES "vorbis") - sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisFile" SEARCH_NAMES "vorbisfile") - sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "VorbisEnc" SEARCH_NAMES "vorbisenc") + sfml_bind_dependency(TARGET Vorbis FRIENDLY_NAME "Ogg" SEARCH_NAMES "ogg") sfml_bind_dependency(TARGET FLAC FRIENDLY_NAME "FLAC" SEARCH_NAMES "FLAC") endif() diff --git a/cmake/toolchains/iOS.toolchain.cmake b/cmake/toolchains/iOS.toolchain.cmake index abbff03..c697857 100644 --- a/cmake/toolchains/iOS.toolchain.cmake +++ b/cmake/toolchains/iOS.toolchain.cmake @@ -22,13 +22,13 @@ # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. # SIMULATOR - used to build for the Simulator platforms, which have an x86_64 arch. # -# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder +# IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder # By default this location is automatcially chosen based on the IOS_PLATFORM value above. # If set manually, it will override the default location and force the user of a particular Developer Platform # -# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder -# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. -# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. +# IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder +# By default this location is automatcially chosen based on the IOS_DEVELOPER_ROOT value. +# In this case it will always be the most up-to-date SDK found in the IOS_DEVELOPER_ROOT path. # If set manually, this will force the use of a specific SDK version # Macros: @@ -58,8 +58,8 @@ if (CMAKE_UNAME) string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") endif (CMAKE_UNAME) -set(CMAKE_C_COMPILER /usr/bin/gcc CACHE FILEPATH "" FORCE) -set(CMAKE_CXX_COMPILER /usr/bin/g++ CACHE FILEPATH "" FORCE) +set(CMAKE_C_COMPILER /usr/bin/clang CACHE FILEPATH "" FORCE) +set(CMAKE_CXX_COMPILER /usr/bin/clang++ CACHE FILEPATH "" FORCE) set(CMAKE_AR ar CACHE FILEPATH "" FORCE) # Skip the platform compiler checks for cross compiling @@ -105,64 +105,43 @@ endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) if (NOT DEFINED IOS_PLATFORM) set (IOS_PLATFORM "OS") endif (NOT DEFINED IOS_PLATFORM) -set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") - -# Setup building for arm64 or not -if (NOT DEFINED BUILD_ARM64) - set (BUILD_ARM64 true) -endif (NOT DEFINED BUILD_ARM64) -set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not") +set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform: OS or SIMULATOR") # Check the platform selection and setup for developer root -if (${IOS_PLATFORM} STREQUAL OS) - message (STATUS "Targeting iPhone platform") +if (IOS_PLATFORM STREQUAL OS) set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") -elseif (${IOS_PLATFORM} STREQUAL SIMULATOR) - message (STATUS "Targeting iPhoneSimulator platform") - set (SIMULATOR true) +elseif (IOS_PLATFORM STREQUAL SIMULATOR) set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") # This causes the installers to properly locate the output libraries set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") - -else (${IOS_PLATFORM} STREQUAL OS) - message (FATAL_ERROR "Unsupported IOS_PLATFORM value '${IOS_PLATFORM}' selected. Please choose OS or SIMULATOR") -endif (${IOS_PLATFORM} STREQUAL OS) - -# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT -# Note Xcode 4.3 changed the installation location, choose the most recent one available -exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR) -set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) - if (EXISTS ${XCODE_POST_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) - endif (EXISTS ${XCODE_POST_43_ROOT}) -endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) -set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") - -# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT -if (NOT DEFINED CMAKE_IOS_SDK_ROOT) - file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") - if (_CMAKE_IOS_SDKS) - list (SORT _CMAKE_IOS_SDKS) - list (REVERSE _CMAKE_IOS_SDKS) - list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) - else (_CMAKE_IOS_SDKS) - message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") - endif (_CMAKE_IOS_SDKS) - message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") -endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) -set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") +else () + message (FATAL_ERROR "Unsupported IOS_PLATFORM value '${IOS_PLATFORM}' selected. Please choose OS or SIMULATOR") +endif () + +# Setup iOS developer location unless specified manually with IOS_DEVELOPER_ROOT +exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE XCODE_DEVELOPER_DIR) +set (IOS_DEVELOPER_ROOT "${XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer" CACHE PATH "Location of iOS Platform") + +# Find and use the most recent iOS sdk unless specified manually with IOS_SDK_ROOT +if (NOT DEFINED IOS_SDK_ROOT) + file (GLOB _IOS_SDKS "${IOS_DEVELOPER_ROOT}/SDKs/*") + if (_IOS_SDKS) + list (SORT _IOS_SDKS) + list (REVERSE _IOS_SDKS) + list (GET _IOS_SDKS 0 IOS_SDK_ROOT) + else (_IOS_SDKS) + message (FATAL_ERROR "No iOS SDK's found in default search path ${IOS_DEVELOPER_ROOT}. Manually set IOS_SDK_ROOT or install the iOS SDK.") + endif (_IOS_SDKS) + message (STATUS "Toolchain using default iOS SDK: ${IOS_SDK_ROOT}") +endif (NOT DEFINED IOS_SDK_ROOT) +set (IOS_SDK_ROOT ${IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") # Set the sysroot default to the most recent SDK -set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") -message (STATUS "iOS sysroot=${CMAKE_OSX_SYSROOT}") +set (CMAKE_OSX_SYSROOT ${IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") # set the architecture for iOS if (${IOS_PLATFORM} STREQUAL OS) @@ -172,21 +151,19 @@ elseif (${IOS_PLATFORM} STREQUAL SIMULATOR) set (IOS_ARCH x86_64) endif (${IOS_PLATFORM} STREQUAL OS) -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS" FORCE) -set (CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS ${IOS_ARCH}) -message (STATUS "iOS architecture=${IOS_ARCH}") +set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS" FORCE) # Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") +set (CMAKE_FIND_ROOT_PATH ${IOS_DEVELOPER_ROOT} ${IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE STRING "iOS find search path root") # default to searching for frameworks first set (CMAKE_FIND_FRAMEWORK FIRST) # set up the default search directories for frameworks set (CMAKE_SYSTEM_FRAMEWORK_PATH - ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks - ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks - ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks + ${IOS_SDK_ROOT}/System/Library/Frameworks + ${IOS_SDK_ROOT}/System/Library/PrivateFrameworks + ${IOS_SDK_ROOT}/Developer/Library/Frameworks ) # only search the iOS sdks, not the remainder of the host filesystem @@ -195,12 +172,6 @@ set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -# This little macro lets you set any XCode specific property -macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) - set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) -endmacro (set_xcode_property) - - # This macro lets you find executable programs on the host system macro (find_host_package) set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) diff --git a/examples/android/app/src/main/jni/main.cpp b/examples/android/app/src/main/jni/main.cpp index e5445b5..edf67b4 100644 --- a/examples/android/app/src/main/jni/main.cpp +++ b/examples/android/app/src/main/jni/main.cpp @@ -6,7 +6,8 @@ // Do we want to showcase direct JNI/NDK interaction? // Undefine this to get real cross-platform code. -#define USE_JNI +// Uncomment this to try JNI access; this seems to be broken in latest NDKs +//#define USE_JNI #if defined(USE_JNI) // These headers are only needed for direct NDK/JDK interaction diff --git a/examples/cocoa/CMakeLists.txt b/examples/cocoa/CMakeLists.txt index ff63cc0..dfa46be 100644 --- a/examples/cocoa/CMakeLists.txt +++ b/examples/cocoa/CMakeLists.txt @@ -20,7 +20,7 @@ function(compile_xib) endif() # Default args taken from Xcode 9 when it generates a nib from a xib - set(DEFAULT_ARGS --errors --warnings --notices --module cocoa --auto-activate-custom-fonts --target-device mac --minimum-deployment-target ${CMAKE_OSX_DEPLOYMENT_TARGET} --output-format human-readable-text) + set(DEFAULT_ARGS --errors --warnings --notices --module cocoa --auto-activate-custom-fonts --target-device mac --output-format human-readable-text) add_custom_command(OUTPUT "${THIS_OUTPUT}" COMMAND "${IBTOOL}" ${DEFAULT_ARGS} "${THIS_INPUT}" --compile "${THIS_OUTPUT}" diff --git a/examples/iOS/CMakeLists.txt b/examples/iOS/CMakeLists.txt index 96450f4..24aca5f 100644 --- a/examples/iOS/CMakeLists.txt +++ b/examples/iOS/CMakeLists.txt @@ -21,5 +21,5 @@ sfml_add_example(ios_demo GUI_APP "-framework OpenGLES") # The app needs an identifier and signing to work correctly -SET_XCODE_PROPERTY(ios_demo CODE_SIGN_IDENTITY "iPhone Developer") +sfml_set_xcode_property(ios_demo CODE_SIGN_IDENTITY "iPhone Developer") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.sfml.ios_demo") diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp index aae5f54..40b677e 100644 --- a/include/SFML/Config.hpp +++ b/include/SFML/Config.hpp @@ -31,7 +31,7 @@ //////////////////////////////////////////////////////////// #define SFML_VERSION_MAJOR 2 #define SFML_VERSION_MINOR 5 -#define SFML_VERSION_PATCH 0 +#define SFML_VERSION_PATCH 1 //////////////////////////////////////////////////////////// diff --git a/include/SFML/System/FileInputStream.hpp b/include/SFML/System/FileInputStream.hpp index 43618da..ca26797 100644 --- a/include/SFML/System/FileInputStream.hpp +++ b/include/SFML/System/FileInputStream.hpp @@ -35,7 +35,7 @@ #include <cstdio> #include <string> -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID namespace sf { namespace priv @@ -122,7 +122,7 @@ private: //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID priv::ResourceStream* m_file; #else std::FILE* m_file; ///< stdio file stream diff --git a/include/SFML/Window/Clipboard.hpp b/include/SFML/Window/Clipboard.hpp index 436da8f..50ea804 100644 --- a/include/SFML/Window/Clipboard.hpp +++ b/include/SFML/Window/Clipboard.hpp @@ -60,7 +60,12 @@ public: /// This function sets the content of the clipboard as a /// string. /// - /// \param text sf::String containing the data to be sent + /// \warning Due to limitations on some operating systems, + /// setting the clipboard contents is only + /// guaranteed to work if there is currently an + /// open window for which events are being handled. + /// + /// \param text sf::String containing the data to be sent /// to the clipboard /// //////////////////////////////////////////////////////////// @@ -80,6 +85,11 @@ public: /// sf::Clipboard provides an interface for getting and /// setting the contents of the system clipboard. /// +/// It is important to note that due to limitations on some +/// operating systems, setting the clipboard contents is +/// only guaranteed to work if there is currently an open +/// window for which events are being handled. +/// /// Usage example: /// \code /// // get the clipboard content as a string @@ -96,11 +106,12 @@ public: /// // Using Ctrl + V to paste a string into SFML /// if(event.key.control && event.key.code == sf::Keyboard::V) /// string = sf::Clipboard::getString(); +/// +/// // Using Ctrl + C to copy a string out of SFML +/// if(event.key.control && event.key.code == sf::Keyboard::C) +/// sf::Clipboard::setString("Hello World!"); /// } /// } -/// -/// // set the clipboard to a string -/// sf::Clipboard::setString("Hello World!"); /// \endcode /// /// \see sf::String, sf::Event diff --git a/include/SFML/Window/Cursor.hpp b/include/SFML/Window/Cursor.hpp index 30aebd4..9daa13b 100644 --- a/include/SFML/Window/Cursor.hpp +++ b/include/SFML/Window/Cursor.hpp @@ -62,13 +62,16 @@ public: /// sf::Cursor::Hand | yes | yes | yes | /// sf::Cursor::SizeHorizontal | yes | yes | yes | /// sf::Cursor::SizeVertical | yes | yes | yes | - /// sf::Cursor::SizeTopLeftBottomRight | no | no | yes | - /// sf::Cursor::SizeBottomLeftTopRight | no | no | yes | + /// sf::Cursor::SizeTopLeftBottomRight | no | yes* | yes | + /// sf::Cursor::SizeBottomLeftTopRight | no | yes* | yes | /// sf::Cursor::SizeAll | yes | no | yes | /// sf::Cursor::Cross | yes | yes | yes | - /// sf::Cursor::Help | yes | no | yes | + /// sf::Cursor::Help | yes | yes* | yes | /// sf::Cursor::NotAllowed | yes | yes | yes | /// + /// * These cursor types are undocumented so may not + /// be available on all versions, but have been tested on 10.13 + /// //////////////////////////////////////////////////////////// enum Type { diff --git a/src/SFML/Audio/SoundFileReaderWav.cpp b/src/SFML/Audio/SoundFileReaderWav.cpp index dc1dc52..84d92c1 100644 --- a/src/SFML/Audio/SoundFileReaderWav.cpp +++ b/src/SFML/Audio/SoundFileReaderWav.cpp @@ -155,7 +155,11 @@ Uint64 SoundFileReaderWav::read(Int16* samples, Uint64 maxCount) assert(m_stream); Uint64 count = 0; - while ((count < maxCount) && (static_cast<Uint64>(m_stream->tell()) < m_dataEnd)) + Uint64 startPos = m_stream->tell(); + + // Tracking of m_dataEnd is important to prevent sf::Music from reading + // data until EOF, as WAV files may have metadata at the end. + while ((count < maxCount) && (startPos + count * m_bytesPerSample < m_dataEnd)) { switch (m_bytesPerSample) { diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp index 45f6baf..308070a 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -71,10 +71,10 @@ namespace return output; } - // Combine outline thickness, boldness and codepoint into a single 64-bit key - sf::Uint64 combine(float outlineThickness, bool bold, sf::Uint32 codePoint) + // Combine outline thickness, boldness and font glyph index into a single 64-bit key + sf::Uint64 combine(float outlineThickness, bool bold, sf::Uint32 index) { - return (static_cast<sf::Uint64>(reinterpret<sf::Uint32>(outlineThickness)) << 32) | (static_cast<sf::Uint64>(bold) << 31) | codePoint; + return (static_cast<sf::Uint64>(reinterpret<sf::Uint32>(outlineThickness)) << 32) | (static_cast<sf::Uint64>(bold) << 31) | index; } } @@ -346,8 +346,8 @@ const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool b // Get the page corresponding to the character size GlyphTable& glyphs = m_pages[characterSize].glyphs; - // Build the key by combining the code point, bold flag, and outline thickness - Uint64 key = combine(outlineThickness, bold, codePoint); + // Build the key by combining the glyph index (based on code point), bold flag, and outline thickness + Uint64 key = combine(outlineThickness, bold, FT_Get_Char_Index(static_cast<FT_Face>(m_face), codePoint)); // Search the glyph into the cache GlyphTable::const_iterator it = glyphs.find(key); @@ -727,6 +727,7 @@ IntRect Font::findGlyphRect(Page& page, unsigned int width, unsigned int height) // Make the texture 2 times bigger Texture newTexture; newTexture.create(textureWidth * 2, textureHeight * 2); + newTexture.setSmooth(true); newTexture.update(page.texture); page.texture.swap(newTexture); } @@ -776,17 +777,22 @@ bool Font::setCurrentSize(unsigned int characterSize) const err() << "Failed to set bitmap font size to " << characterSize << std::endl; err() << "Available sizes are: "; for (int i = 0; i < face->num_fixed_sizes; ++i) - err() << face->available_sizes[i].height << " "; + { + const unsigned int size = (face->available_sizes[i].y_ppem + 32) >> 6; + err() << size << " "; + } err() << std::endl; } + else + { + err() << "Failed to set font size to " << characterSize << std::endl; + } } return result == FT_Err_Ok; } - else - { - return true; - } + + return true; } diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 7eccf82..9a6e301 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -129,7 +129,7 @@ RenderTarget::RenderTarget() : m_defaultView(), m_view (), m_cache (), -m_id (getUniqueId()) +m_id (0) { m_cache.glStatesSet = false; } @@ -547,6 +547,10 @@ void RenderTarget::initialize() // Set GL states only on first draw, so that we don't pollute user's states m_cache.glStatesSet = false; + + // Generate a unique ID for this RenderTarget to track + // whether it is active within a specific context + m_id = getUniqueId(); } @@ -704,7 +708,7 @@ void RenderTarget::drawPrimitives(PrimitiveType type, std::size_t firstVertex, s GLenum mode = modes[type]; // Draw the primitives - glCheck(glDrawArrays(mode, firstVertex, static_cast<GLsizei>(vertexCount))); + glCheck(glDrawArrays(mode, static_cast<GLint>(firstVertex), static_cast<GLsizei>(vertexCount))); } diff --git a/src/SFML/Graphics/RenderTexture.cpp b/src/SFML/Graphics/RenderTexture.cpp index 0805627..51abee9 100644 --- a/src/SFML/Graphics/RenderTexture.cpp +++ b/src/SFML/Graphics/RenderTexture.cpp @@ -161,7 +161,7 @@ bool RenderTexture::setActive(bool active) void RenderTexture::display() { // Update the target texture - if (priv::RenderTextureImplFBO::isAvailable() || setActive(true)) + if (m_impl && (priv::RenderTextureImplFBO::isAvailable() || setActive(true))) { m_impl->updateTexture(m_texture.m_texture); m_texture.m_pixelsFlipped = true; diff --git a/src/SFML/Graphics/RenderTextureImplFBO.cpp b/src/SFML/Graphics/RenderTextureImplFBO.cpp index 301aa04..c0debd7 100644 --- a/src/SFML/Graphics/RenderTextureImplFBO.cpp +++ b/src/SFML/Graphics/RenderTextureImplFBO.cpp @@ -53,6 +53,29 @@ namespace // Mutex to protect both active and stale frame buffer sets sf::Mutex mutex; + // This function is called either when a RenderTextureImplFBO is + // destroyed or via contextDestroyCallback when context destruction + // might trigger deletion of its contained stale FBOs + void destroyStaleFBOs() + { + sf::Uint64 contextId = sf::Context::getActiveContextId(); + + for (std::set<std::pair<sf::Uint64, unsigned int> >::iterator iter = staleFrameBuffers.begin(); iter != staleFrameBuffers.end();) + { + if (iter->first == contextId) + { + GLuint frameBuffer = static_cast<GLuint>(iter->second); + glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer)); + + staleFrameBuffers.erase(iter++); + } + else + { + ++iter; + } + } + } + // Callback that is called every time a context is destroyed void contextDestroyCallback(void* arg) { @@ -79,14 +102,7 @@ namespace } // Destroy stale frame buffer objects - for (std::set<std::pair<sf::Uint64, unsigned int> >::iterator iter = staleFrameBuffers.begin(); iter != staleFrameBuffers.end(); ++iter) - { - if (iter->first == contextId) - { - GLuint frameBuffer = static_cast<GLuint>(iter->second); - glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer)); - } - } + destroyStaleFBOs(); } } @@ -150,7 +166,7 @@ RenderTextureImplFBO::~RenderTextureImplFBO() staleFrameBuffers.insert(std::make_pair(iter->first, iter->second)); // Clean up FBOs - contextDestroyCallback(0); + destroyStaleFBOs(); // Delete the backup context if we had to create one delete m_context; diff --git a/src/SFML/Graphics/RenderWindow.cpp b/src/SFML/Graphics/RenderWindow.cpp index 906363b..446e906 100644 --- a/src/SFML/Graphics/RenderWindow.cpp +++ b/src/SFML/Graphics/RenderWindow.cpp @@ -81,7 +81,7 @@ bool RenderWindow::setActive(bool active) // If FBOs are available, make sure none are bound when we // try to draw to the default framebuffer of the RenderWindow - if (result && priv::RenderTextureImplFBO::isAvailable()) + if (active && result && priv::RenderTextureImplFBO::isAvailable()) { priv::RenderTextureImplFBO::unbind(); diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index 3773616..6687551 100644 --- a/src/SFML/Graphics/Text.cpp +++ b/src/SFML/Graphics/Text.cpp @@ -50,15 +50,17 @@ namespace // Add a glyph quad to the vertex array void addGlyphQuad(sf::VertexArray& vertices, sf::Vector2f position, const sf::Color& color, const sf::Glyph& glyph, float italicShear, float outlineThickness = 0) { - float left = glyph.bounds.left; - float top = glyph.bounds.top; - float right = glyph.bounds.left + glyph.bounds.width; - float bottom = glyph.bounds.top + glyph.bounds.height; + float padding = 1.0; - float u1 = static_cast<float>(glyph.textureRect.left); - float v1 = static_cast<float>(glyph.textureRect.top); - float u2 = static_cast<float>(glyph.textureRect.left + glyph.textureRect.width); - float v2 = static_cast<float>(glyph.textureRect.top + glyph.textureRect.height); + float left = glyph.bounds.left - padding; + float top = glyph.bounds.top - padding; + float right = glyph.bounds.left + glyph.bounds.width + padding; + float bottom = glyph.bounds.top + glyph.bounds.height + padding; + + float u1 = static_cast<float>(glyph.textureRect.left) - padding; + float v1 = static_cast<float>(glyph.textureRect.top) - padding; + float u2 = static_cast<float>(glyph.textureRect.left + glyph.textureRect.width) + padding; + float v2 = static_cast<float>(glyph.textureRect.top + glyph.textureRect.height) + padding; vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italicShear * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u1, v1))); vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italicShear * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u2, v1))); @@ -444,12 +446,15 @@ void Text::ensureGeometryUpdate() const { Uint32 curChar = m_string[i]; + // Skip the \r char to avoid weird graphical issues + if (curChar == '\r') + continue; + // Apply the kerning offset x += m_font->getKerning(prevChar, curChar, m_characterSize); - prevChar = curChar; // If we're using the underlined style and there's a new line, draw a line - if (isUnderlined && (curChar == L'\n')) + if (isUnderlined && (curChar == L'\n' && prevChar != L'\n')) { addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness); @@ -458,7 +463,7 @@ void Text::ensureGeometryUpdate() const } // If we're using the strike through style and there's a new line, draw a line across all characters - if (isStrikeThrough && (curChar == L'\n')) + if (isStrikeThrough && (curChar == L'\n' && prevChar != L'\n')) { addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness); @@ -466,6 +471,8 @@ void Text::ensureGeometryUpdate() const addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness); } + prevChar = curChar; + // Handle special characters if ((curChar == L' ') || (curChar == L'\n') || (curChar == L'\t')) { diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp index faeef7d..fd94acf 100644 --- a/src/SFML/Graphics/Texture.cpp +++ b/src/SFML/Graphics/Texture.cpp @@ -129,6 +129,11 @@ bool Texture::create(unsigned int width, unsigned int height) return false; } + TransientContextLock lock; + + // Make sure that extensions are initialized + priv::ensureExtensionsInit(); + // Compute the internal texture dimensions depending on NPOT textures support Vector2u actualSize(getValidSize(width), getValidSize(height)); @@ -150,8 +155,6 @@ bool Texture::create(unsigned int width, unsigned int height) m_pixelsFlipped = false; m_fboAttachment = false; - TransientContextLock lock; - // Create the OpenGL texture if it doesn't exist yet if (!m_texture) { @@ -160,9 +163,6 @@ bool Texture::create(unsigned int width, unsigned int height) m_texture = static_cast<unsigned int>(texture); } - // Make sure that extensions are initialized - priv::ensureExtensionsInit(); - // Make sure that the current texture binding will be preserved priv::TextureSaver save; @@ -851,11 +851,6 @@ unsigned int Texture::getNativeHandle() const //////////////////////////////////////////////////////////// unsigned int Texture::getValidSize(unsigned int size) { - TransientContextLock lock; - - // Make sure that extensions are initialized - priv::ensureExtensionsInit(); - if (GLEXT_texture_non_power_of_two) { // If hardware supports NPOT textures, then just return the unmodified size diff --git a/src/SFML/Main/MainAndroid.cpp b/src/SFML/Main/MainAndroid.cpp index fcb8500..5e62133 100644 --- a/src/SFML/Main/MainAndroid.cpp +++ b/src/SFML/Main/MainAndroid.cpp @@ -93,6 +93,13 @@ static void initializeMain(ActivityStates* states) ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); states->looper = looper; + /** + * Acquire increments a reference counter on the looper. This keeps android + * from collecting it before the activity thread has a chance to detach its + * input queue. + */ + ALooper_acquire(states->looper); + // Get the default configuration states->config = AConfiguration_new(); AConfiguration_fromAssetManager(states->config, states->activity->assetManager); @@ -338,7 +345,7 @@ static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* wind // Wait for the event to be taken into account by SFML states->updated = false; - while(!states->updated) + while(!(states->updated | states->terminated)) { states->mutex.unlock(); sf::sleep(sf::milliseconds(10)); @@ -363,7 +370,7 @@ static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* wi // Wait for the event to be taken into account by SFML states->updated = false; - while(!states->updated) + while(!(states->updated | states->terminated)) { states->mutex.unlock(); sf::sleep(sf::milliseconds(10)); @@ -410,8 +417,10 @@ static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { sf::Lock lock(states->mutex); - states->inputQueue = NULL; AInputQueue_detachLooper(queue); + states->inputQueue = NULL; + + ALooper_release(states->looper); } } @@ -464,7 +473,7 @@ static void onLowMemory(ANativeActivity* activity) //////////////////////////////////////////////////////////// -void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) +JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_t savedStateSize) { // Create an activity states (will keep us in the know, about events we care) sf::priv::ActivityStates* states = NULL; @@ -542,7 +551,7 @@ void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, size_ // Wait for the main thread to be initialized states->mutex.lock(); - while (!states->initialized) + while (!(states->initialized | states->terminated)) { states->mutex.unlock(); sf::sleep(sf::milliseconds(20)); diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp index e11f76b..d8effa1 100644 --- a/src/SFML/Network/TcpSocket.cpp +++ b/src/SFML/Network/TcpSocket.cpp @@ -246,7 +246,7 @@ Socket::Status TcpSocket::send(const void* data, std::size_t size, std::size_t& for (sent = 0; sent < size; sent += result) { // Send a chunk of data - result = ::send(getHandle(), static_cast<const char*>(data) + sent, size - sent, flags); + result = ::send(getHandle(), static_cast<const char*>(data) + sent, static_cast<int>(size - sent), flags); // Check for errors if (result < 0) diff --git a/src/SFML/System/FileInputStream.cpp b/src/SFML/System/FileInputStream.cpp index 852470d..89e77c4 100644 --- a/src/SFML/System/FileInputStream.cpp +++ b/src/SFML/System/FileInputStream.cpp @@ -26,7 +26,7 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/System/FileInputStream.hpp> -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID #include <SFML/System/Android/ResourceStream.hpp> #endif @@ -44,7 +44,7 @@ FileInputStream::FileInputStream() //////////////////////////////////////////////////////////// FileInputStream::~FileInputStream() { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID if (m_file) delete m_file; #else @@ -57,7 +57,7 @@ FileInputStream::~FileInputStream() //////////////////////////////////////////////////////////// bool FileInputStream::open(const std::string& filename) { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID if (m_file) delete m_file; m_file = new priv::ResourceStream(filename); @@ -76,7 +76,7 @@ bool FileInputStream::open(const std::string& filename) //////////////////////////////////////////////////////////// Int64 FileInputStream::read(void* data, Int64 size) { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID return m_file->read(data, size); #else if (m_file) @@ -90,7 +90,7 @@ Int64 FileInputStream::read(void* data, Int64 size) //////////////////////////////////////////////////////////// Int64 FileInputStream::seek(Int64 position) { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID return m_file->seek(position); #else if (m_file) @@ -111,7 +111,7 @@ Int64 FileInputStream::seek(Int64 position) //////////////////////////////////////////////////////////// Int64 FileInputStream::tell() { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID return m_file->tell(); #else if (m_file) @@ -125,7 +125,7 @@ Int64 FileInputStream::tell() //////////////////////////////////////////////////////////// Int64 FileInputStream::getSize() { -#ifdef ANDROID +#ifdef SFML_SYSTEM_ANDROID return m_file->getSize(); #else if (m_file) diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index 916c1dc..98ea439 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -229,12 +229,24 @@ sfml_add_library(sfml-window SOURCES ${SRC} ${PLATFORM_SRC}) target_link_libraries(sfml-window PUBLIC sfml-system) +# When static linking on macOS, we need to add this flag for objective C to work +if ((NOT BUILD_SHARED_LIBS) AND SFML_OS_MACOSX) + target_link_libraries(sfml-window PRIVATE -ObjC) +endif() + # find and setup usage for external libraries if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OPENBSD) sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB") target_link_libraries(sfml-window PRIVATE X11) endif() +# CMake 3.11 and later prefer to choose GLVND, but we choose legacy OpenGL for backward compability +# (unless the OpenGL_GL_PREFERENCE was explicitly set) +# See CMP0072 for more details (cmake --help-policy CMP0072) +if ((NOT ${CMAKE_VERSION} VERSION_LESS 3.11) AND (NOT OpenGL_GL_PREFERENCE)) + set(OpenGL_GL_PREFERENCE "LEGACY") +endif() + if(SFML_OPENGL_ES) if(SFML_OS_IOS) target_link_libraries(sfml-window PRIVATE "-framework OpenGLES") @@ -242,7 +254,7 @@ if(SFML_OPENGL_ES) target_link_libraries(sfml-window PRIVATE EGL GLESv1_CM) endif() else() - sfml_find_package(OpenGL INCLUDE "OPENGL_INCLUDE_DIR" LINK "OPENGL_gl_LIBRARY") + sfml_find_package(OpenGL INCLUDE "OPENGL_INCLUDE_DIR" LINK "OPENGL_LIBRARIES") target_link_libraries(sfml-window PRIVATE OpenGL) endif() diff --git a/src/SFML/Window/OSX/CursorImpl.mm b/src/SFML/Window/OSX/CursorImpl.mm index 5f41376..ed905ef 100644 --- a/src/SFML/Window/OSX/CursorImpl.mm +++ b/src/SFML/Window/OSX/CursorImpl.mm @@ -32,6 +32,21 @@ #import <SFML/Window/OSX/NSImage+raw.h> #import <AppKit/AppKit.h> +namespace +{ + +//////////////////////////////////////////////////////////// +NSCursor* loadFromSelector(SEL selector) +{ + // The caller is responsible for retaining the cursor. + if ([NSCursor respondsToSelector:selector]) + return [NSCursor performSelector:selector]; + else + return nil; +} + +} + namespace sf { namespace priv @@ -56,6 +71,8 @@ CursorImpl::~CursorImpl() //////////////////////////////////////////////////////////// bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot) { + [m_cursor release]; + NSSize nssize = NSMakeSize(size.x, size.y); NSImage* image = [NSImage imageWithRawData:pixels andSize:nssize]; NSPoint nshotspot = NSMakePoint(hotspot.x, hotspot.y); @@ -65,10 +82,11 @@ bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hot return m_cursor != nil; } - //////////////////////////////////////////////////////////// bool CursorImpl::loadFromSystem(Cursor::Type type) { + [m_cursor release]; + switch (type) { default: return false; @@ -80,14 +98,28 @@ bool CursorImpl::loadFromSystem(Cursor::Type type) case Cursor::SizeVertical: m_cursor = [NSCursor resizeUpDownCursor]; break; case Cursor::Cross: m_cursor = [NSCursor crosshairCursor]; break; case Cursor::NotAllowed: m_cursor = [NSCursor operationNotAllowedCursor]; break; + + // These cursor types are undocumented, may not be available on some platforms +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + case Cursor::SizeBottomLeftTopRight: + m_cursor = loadFromSelector(@selector(_windowResizeNorthEastSouthWestCursor)); + break; + + case Cursor::SizeTopLeftBottomRight: + m_cursor = loadFromSelector(@selector(_windowResizeNorthWestSouthEastCursor)); + break; + + case Cursor::Help: + m_cursor = loadFromSelector(@selector(_helpCursor)); + break; +#pragma clang diagnostic pop } - // Since we didn't allocate the cursor ourself, we have to retain it - // in order to not break the retain count. - [m_cursor retain]; + if (m_cursor) + [m_cursor retain]; - // For all non-default cases, it was a success. - return true; + return m_cursor != nil; } diff --git a/src/SFML/Window/Unix/ClipboardImpl.cpp b/src/SFML/Window/Unix/ClipboardImpl.cpp index 32ef21b..df2fd95 100644 --- a/src/SFML/Window/Unix/ClipboardImpl.cpp +++ b/src/SFML/Window/Unix/ClipboardImpl.cpp @@ -27,233 +27,356 @@ //////////////////////////////////////////////////////////// #include <SFML/Window/Unix/ClipboardImpl.hpp> #include <SFML/Window/Unix/Display.hpp> -#include <SFML/System/String.hpp> -#include <SFML/System/Sleep.hpp> -#include <iostream> -#include <string> -#include <X11/Xlib.h> +#include <SFML/System/Clock.hpp> +#include <SFML/System/Err.hpp> +#include <X11/Xatom.h> +#include <vector> namespace { + // Filter the events received by windows (only allow those matching a specific window) + Bool checkEvent(::Display*, XEvent* event, XPointer userData) + { + // Just check if the event matches the window + return event->xany.window == reinterpret_cast< ::Window >(userData); + } +} + +namespace sf +{ +namespace priv +{ + //////////////////////////////////////////////////////////// -void initClipboard(); -void* hostSelection(void*); +String ClipboardImpl::getString() +{ + return getInstance().getStringImpl(); +} -sf::String string; -pthread_mutex_t mutex; -pthread_t host_thread; +//////////////////////////////////////////////////////////// +void ClipboardImpl::setString(const String& text) +{ + getInstance().setStringImpl(text); +} -bool is_fail = false; -bool is_init = false; -bool is_host = false; -Display* display = NULL; -Window window = 0; +//////////////////////////////////////////////////////////// +void ClipboardImpl::processEvents() +{ + getInstance().processEventsImpl(); +} -Atom selection = 0; -Atom atom_targ = 0; -Atom atom_text = 0; -Atom utf8_text = 0; -int xa_string = 31; -int xa_atom = 4; //////////////////////////////////////////////////////////// -void initClipboard() +ClipboardImpl::ClipboardImpl() : +m_window (0), +m_requestResponded(false) { - is_init = true; + // Open a connection with the X server + m_display = OpenDisplay(); - display = XOpenDisplay(NULL); - int screen = DefaultScreen(display); - window = XCreateSimpleWindow(display, RootWindow(display, screen), - 0, 0, 1, 1, 0, BlackPixel(display, screen), WhitePixel(display, screen)); + // Get the atoms we need to make use of the clipboard + m_clipboard = getAtom("CLIPBOARD", false); + m_targets = getAtom("TARGETS", false); + m_text = getAtom("TEXT", false); + m_utf8String = getAtom("UTF8_STRING", true ); + m_targetProperty = getAtom("SFML_CLIPBOARD_TARGET_PROPERTY", false); - selection = XInternAtom(display, "CLIPBOARD", false); - atom_targ = XInternAtom(display, "TARGETS", false); - atom_text = XInternAtom(display, "TEXT", false); - utf8_text = XInternAtom(display, "UTF8_STRING", true); + // Create a hidden window that will broker our clipboard interactions with X + m_window = XCreateSimpleWindow(m_display, DefaultRootWindow(m_display), 0, 0, 1, 1, 0, 0, 0); - if(utf8_text == None) - { - std::cerr << "UTF-8 format unavailable on clipboard." << std::endl; - utf8_text = xa_string; - } + // Register the events we are interested in + XSelectInput(m_display, m_window, SelectionNotify | SelectionClear | SelectionRequest); +} - if(pthread_mutex_init(&mutex, NULL)) - { - is_fail = true; - std::cerr << "Unable to initialize mutex. Failed to initialize clipboard." << std::endl; - return; - } - if(pthread_create(&host_thread, NULL, hostSelection, NULL)) +//////////////////////////////////////////////////////////// +ClipboardImpl::~ClipboardImpl() +{ + // Destroy the window + if (m_window) { - is_fail = true; - std::cerr << "Unable to create host thread. Failed to initialize clipboard." << std::endl; - return; + XDestroyWindow(m_display, m_window); + XFlush(m_display); } + + // Close the connection with the X server + CloseDisplay(m_display); } + //////////////////////////////////////////////////////////// -void* hostSelection(void*) +ClipboardImpl& ClipboardImpl::getInstance() { - while(true) - { - if(XPending(display) && is_host) - { - XEvent event; + static ClipboardImpl instance; - pthread_mutex_lock(&mutex); - XNextEvent(display, &event); - pthread_mutex_unlock(&mutex); + return instance; +} - switch(event.type) - { - case SelectionClear: - { - pthread_mutex_lock(&mutex); - is_host = false; - pthread_mutex_unlock(&mutex); - break; - } - case SelectionRequest: - { - if(event.xselectionrequest.selection == selection) - { - XSelectionRequestEvent* sel_req_event = &event.xselectionrequest; - XSelectionEvent sel_event = {0}; - - int result = 0; - sel_event.type = SelectionNotify, - sel_event.display = sel_req_event->display, - sel_event.requestor = sel_req_event->requestor, - sel_event.selection = sel_req_event->selection, - sel_event.time = sel_req_event->time, - sel_event.target = sel_req_event->target, - sel_event.property = sel_req_event->property; - - std::basic_string<unsigned char> str = string.toUtf8(); - - if(sel_event.target == atom_targ) - result = XChangeProperty(sel_event.display, sel_event.requestor, - sel_event.property, xa_atom, 32, PropModeReplace, - reinterpret_cast<unsigned char*>(&utf8_text), 1); - else if(sel_event.target == xa_string || sel_event.target == atom_text) - result = XChangeProperty(sel_event.display, sel_event.requestor, - sel_event.property, xa_string, 8, PropModeReplace, - reinterpret_cast<unsigned char*>(&str[0]), str.size()); - else if(sel_event.target == utf8_text) - result = XChangeProperty(sel_event.display, sel_event.requestor, - sel_event.property, utf8_text, 8, PropModeReplace, - reinterpret_cast<unsigned char*>(&str[0]), str.size()); - else - sel_event.property = None; - - if((result & 2) == 0) - XSendEvent(display, sel_event.requestor, 0, 0, - reinterpret_cast<XEvent*>(&sel_event)); - } - break; - } - default: break; - } - } - else - sf::sleep(sf::milliseconds(20)); +//////////////////////////////////////////////////////////// +String ClipboardImpl::getStringImpl() +{ + // Check if anybody owns the current selection + if (XGetSelectionOwner(m_display, m_clipboard) == None) + { + m_clipboardContents.clear(); + + return m_clipboardContents; } -} + + // Process any already pending events + processEvents(); + + m_requestResponded = false; + + // Request the current selection to be converted to UTF-8 (or STRING + // if UTF-8 is not available) and written to our window property + XConvertSelection( + m_display, + m_clipboard, + (m_utf8String != None) ? m_utf8String : XA_STRING, + m_targetProperty, + m_window, + CurrentTime + ); + + Clock clock; + + // Wait for a response for up to 1000ms + while (!m_requestResponded && (clock.getElapsedTime().asMilliseconds() < 1000)) + processEvents(); + + // If no response was received within the time period, clear our clipboard contents + if (!m_requestResponded) + m_clipboardContents.clear(); + + return m_clipboardContents; } -namespace sf -{ -namespace priv -{ //////////////////////////////////////////////////////////// -String ClipboardImpl::getString() +void ClipboardImpl::setStringImpl(const String& text) { - if(!is_init) - initClipboard(); + m_clipboardContents = text; + + // Set our window as the current owner of the selection + XSetSelectionOwner(m_display, m_clipboard, m_window, CurrentTime); - if(is_fail || is_host) - return string; + // Check if setting the selection owner was successful + if (XGetSelectionOwner(m_display, m_clipboard) != m_window) + err() << "Cannot set clipboard string: Unable to get ownership of X selection" << std::endl; +} - // Dangerous! Wipes all previous events! - XSync(display, true); - XConvertSelection(display, selection, utf8_text, atom_text, window, CurrentTime); +//////////////////////////////////////////////////////////// +void ClipboardImpl::processEventsImpl() +{ XEvent event; - pthread_mutex_lock(&mutex); - XNextEvent(display, &event); - pthread_mutex_unlock(&mutex); + // Pick out the events that are interesting for this window + while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window))) + m_events.push_back(event); - if(event.type == SelectionNotify) + // Handle the events for this window that we just picked out + while (!m_events.empty()) { - if(event.xselection.selection != selection || event.xselection.target != utf8_text) + event = m_events.front(); + m_events.pop_front(); + processEvent(event); + } +} + + +//////////////////////////////////////////////////////////// +void ClipboardImpl::processEvent(XEvent& windowEvent) +{ + switch (windowEvent.type) + { + case SelectionClear: { - std::cerr << "Failed to convert selection." << std::endl; - return string; + // We don't have any resources we need to clean up + // when losing selection ownership so we don't do + // anything when we receive SelectionClear + // We will still respond to any future SelectionRequest + // events since doing so doesn't really do any harm + break; } - - if(event.xselection.property) + case SelectionNotify: { - Atom target; - int format; - unsigned long size; - unsigned long byte_left; - unsigned char* data; + // Notification that the current selection owner + // has responded to our request + + XSelectionEvent& selectionEvent = *reinterpret_cast<XSelectionEvent*>(&windowEvent.xselection); - XGetWindowProperty(event.xselection.display, - event.xselection.requestor, event.xselection.property, - 0L, (~0L), false, AnyPropertyType, - &target, &format, &size, &byte_left, &data); + m_clipboardContents.clear(); - if(target == utf8_text) + // If retrieving the selection fails or conversion is unsuccessful + // we leave the contents of the clipboard empty since we don't + // own it and we don't know what it could currently be + if ((selectionEvent.property == None) || (selectionEvent.selection != m_clipboard)) + break; + + Atom type; + int format; + unsigned long items; + unsigned long remainingBytes; + unsigned char* data = 0; + + // The selection owner should have wrote the selection + // data to the specified window property + int result = XGetWindowProperty( + m_display, + m_window, + m_targetProperty, + 0, + 0x7fffffff, + False, + AnyPropertyType, + &type, + &format, + &items, + &remainingBytes, + &data + ); + + if (result == Success) { - std::basic_string<unsigned char> str(data, size); - string = sf::String::fromUtf8(str.begin(), str.end()); + // We don't support INCR for now + // It is very unlikely that this will be returned + // for purely text data transfer anyway + if (type != getAtom("INCR", false)) + { + // Only copy the data if the format is what we expect + if ((type == m_utf8String) && (format == 8)) + { + m_clipboardContents = String::fromUtf8(data, data + items); + } + else if ((type == XA_STRING) && (format == 8)) + { + // Convert from ANSI std::string to sf::String + m_clipboardContents = std::string(data, data + items); + } + } XFree(data); + + // The selection requestor must always delete the property themselves + XDeleteProperty(m_display, m_window, m_targetProperty); } - XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property); + m_requestResponded = true; + + break; } - } + case SelectionRequest: + { + // Respond to a request for our clipboard contents + XSelectionRequestEvent& selectionRequestEvent = *reinterpret_cast<XSelectionRequestEvent*>(&windowEvent.xselectionrequest); - return string; -} + // Our reply + XSelectionEvent selectionEvent; + selectionEvent.type = SelectionNotify; + selectionEvent.requestor = selectionRequestEvent.requestor; + selectionEvent.selection = selectionRequestEvent.selection; + selectionEvent.property = selectionRequestEvent.property; + selectionEvent.time = selectionRequestEvent.time; -//////////////////////////////////////////////////////////// -void ClipboardImpl::setString(const String& text) -{ - if(!is_init) - initClipboard(); + if (selectionRequestEvent.selection == m_clipboard) + { + if (selectionRequestEvent.target == m_targets) + { + // Respond to a request for our valid conversion targets + std::vector<Atom> targets; - if(is_fail) - return; + targets.push_back(m_targets); + targets.push_back(m_text); + targets.push_back(XA_STRING); - if(!is_host) - { - XSetSelectionOwner(display, selection, window, CurrentTime); + if (m_utf8String != None) + targets.push_back(m_utf8String); - if(XGetSelectionOwner(display, selection) != window) - { - std::cerr << "Unable to get ownership of selection." << std::endl; - return; - } + XChangeProperty( + m_display, + selectionRequestEvent.requestor, + selectionRequestEvent.property, + XA_ATOM, + 32, + PropModeReplace, + reinterpret_cast<unsigned char*>(&targets[0]), + targets.size() + ); - pthread_mutex_lock(&mutex); - is_host = true; - pthread_mutex_unlock(&mutex); - } + // Notify the requestor that they can read the targets from their window property + selectionEvent.target = m_targets; + + XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent)); + + break; + } + else if ((selectionRequestEvent.target == XA_STRING) || ((m_utf8String == None) && (selectionRequestEvent.target == m_text))) + { + // Respond to a request for conversion to a Latin-1 string + std::string data = m_clipboardContents.toAnsiString(); + + XChangeProperty( + m_display, + selectionRequestEvent.requestor, + selectionRequestEvent.property, + XA_STRING, + 8, + PropModeReplace, + reinterpret_cast<const unsigned char*>(data.c_str()), + data.size() + ); - pthread_mutex_lock(&mutex); - string = text; - pthread_mutex_unlock(&mutex); + // Notify the requestor that they can read the data from their window property + selectionEvent.target = XA_STRING; + + XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent)); + + break; + } + else if ((m_utf8String != None) && ((selectionRequestEvent.target == m_utf8String) || (selectionRequestEvent.target == m_text))) + { + // Respond to a request for conversion to a UTF-8 string + // or an encoding of our choosing (we always choose UTF-8) + std::basic_string<Uint8> data = m_clipboardContents.toUtf8(); + + XChangeProperty( + m_display, + selectionRequestEvent.requestor, + selectionRequestEvent.property, + m_utf8String, + 8, + PropModeReplace, + reinterpret_cast<const unsigned char*>(data.c_str()), + data.size() + ); + + // Notify the requestor that they can read the data from their window property + selectionEvent.target = m_utf8String; + + XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent)); + + break; + } + } + + // Notify the requestor that we could not respond to their request + selectionEvent.target = selectionRequestEvent.target; + selectionEvent.property = None; + + XSendEvent(m_display, selectionRequestEvent.requestor, True, NoEventMask, reinterpret_cast<XEvent*>(&selectionEvent)); + + break; + } + default: + break; + } } } // namespace priv diff --git a/src/SFML/Window/Unix/ClipboardImpl.hpp b/src/SFML/Window/Unix/ClipboardImpl.hpp index f4aca98..48ec787 100644 --- a/src/SFML/Window/Unix/ClipboardImpl.hpp +++ b/src/SFML/Window/Unix/ClipboardImpl.hpp @@ -29,6 +29,8 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/System/String.hpp> +#include <X11/Xlib.h> +#include <deque> namespace sf @@ -67,6 +69,82 @@ public: /// //////////////////////////////////////////////////////////// static void setString(const String& text); + + //////////////////////////////////////////////////////////// + /// \brief Process pending events for the hidden clipboard window + /// + /// This function has to be called as part of normal window + /// event processing in order for our application to respond + /// to selection requests from other applications. + /// + //////////////////////////////////////////////////////////// + static void processEvents(); + +private: + + //////////////////////////////////////////////////////////// + /// \brief Constructor + /// + //////////////////////////////////////////////////////////// + ClipboardImpl(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~ClipboardImpl(); + + //////////////////////////////////////////////////////////// + /// \brief Get singleton instance + /// + /// \return Singleton instance + /// + //////////////////////////////////////////////////////////// + static ClipboardImpl& getInstance(); + + //////////////////////////////////////////////////////////// + /// \brief getString implementation + /// + /// \return Current content of the clipboard + /// + //////////////////////////////////////////////////////////// + String getStringImpl(); + + //////////////////////////////////////////////////////////// + /// \brief setString implementation + /// + /// \param text sf::String object containing the data to be sent to the clipboard + /// + //////////////////////////////////////////////////////////// + void setStringImpl(const String& text); + + //////////////////////////////////////////////////////////// + /// \brief processEvents implementation + /// + //////////////////////////////////////////////////////////// + void processEventsImpl(); + + //////////////////////////////////////////////////////////// + /// \brief Process an incoming event from the window + /// + /// \param windowEvent Event which has been received + /// + //////////////////////////////////////////////////////////// + void processEvent(XEvent& windowEvent); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + ::Window m_window; ///< X identifier defining our window + ::Display* m_display; ///< Pointer to the display + Atom m_clipboard; ///< X Atom identifying the CLIPBOARD selection + Atom m_targets; ///< X Atom identifying TARGETS + Atom m_text; ///< X Atom identifying TEXT + Atom m_utf8String; ///< X Atom identifying UTF8_STRING + Atom m_targetProperty; ///< X Atom identifying our destination window property + String m_clipboardContents; ///< Our clipboard contents + std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window + bool m_requestResponded; ///< Holds whether our selection request has been responded to or not }; } // namespace priv diff --git a/src/SFML/Window/Unix/GlxExtensions.hpp b/src/SFML/Window/Unix/GlxExtensions.hpp index abbb132..fb2c7da 100644 --- a/src/SFML/Window/Unix/GlxExtensions.hpp +++ b/src/SFML/Window/Unix/GlxExtensions.hpp @@ -25,11 +25,12 @@ #ifndef SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP #define SF_POINTER_C_GENERATED_HEADER_GLXWIN_HPP -#ifdef __glxext_h_ +#if defined(__glxext_h_) || defined(__glx_glxext_h_) #error Attempt to include glx_exts after including glxext.h #endif #define __glxext_h_ +#define __glx_glxext_h_ #include <X11/Xlib.h> #include <X11/Xutil.h> diff --git a/src/SFML/Window/Unix/WindowImplX11.cpp b/src/SFML/Window/Unix/WindowImplX11.cpp index e2c8d29..da69750 100644 --- a/src/SFML/Window/Unix/WindowImplX11.cpp +++ b/src/SFML/Window/Unix/WindowImplX11.cpp @@ -26,6 +26,7 @@ // Headers //////////////////////////////////////////////////////////// #include <SFML/Window/Unix/WindowImplX11.hpp> +#include <SFML/Window/Unix/ClipboardImpl.hpp> #include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/System/Utf.hpp> @@ -173,7 +174,7 @@ namespace if (result != Success || actualType != XA_WINDOW || numItems != 1) { - if(result == Success) + if (result == Success) XFree(data); sf::priv::CloseDisplay(display); @@ -205,7 +206,7 @@ namespace if (result != Success || actualType != XA_WINDOW || numItems != 1) { - if(result == Success) + if (result == Success) XFree(data); sf::priv::CloseDisplay(display); @@ -269,7 +270,7 @@ namespace windowManagerName = sf::String::fromUtf8(begin, end); } - if(result == Success) + if (result == Success) XFree(data); sf::priv::CloseDisplay(display); @@ -486,6 +487,7 @@ m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (true), m_oldVideoMode (0), +m_oldRRCrtc (0), m_hiddenCursor (0), m_lastCursor (None), m_keyRepeat (true), @@ -534,6 +536,7 @@ m_inputMethod (NULL), m_inputContext (NULL), m_isExternal (false), m_oldVideoMode (0), +m_oldRRCrtc (0), m_hiddenCursor (0), m_lastCursor (None), m_keyRepeat (true), @@ -555,8 +558,17 @@ m_lastInputTime (0) m_screen = DefaultScreen(m_display); // Compute position and size - int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2; - int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2; + Vector2i windowPosition; + if(m_fullscreen) + { + windowPosition = getPrimaryMonitorPosition(); + } + else + { + windowPosition.x = (DisplayWidth(m_display, m_screen) - mode.width) / 2; + windowPosition.y = (DisplayWidth(m_display, m_screen) - mode.height) / 2; + } + int width = mode.width; int height = mode.height; @@ -571,7 +583,7 @@ m_lastInputTime (0) m_window = XCreateWindow(m_display, DefaultRootWindow(m_display), - left, top, + windowPosition.x, windowPosition.y, width, height, 0, visualInfo.depth, @@ -668,9 +680,11 @@ m_lastInputTime (0) { m_useSizeHints = true; XSizeHints* sizeHints = XAllocSizeHints(); - sizeHints->flags = PMinSize | PMaxSize; + sizeHints->flags = PMinSize | PMaxSize | USPosition; sizeHints->min_width = sizeHints->max_width = width; sizeHints->min_height = sizeHints->max_height = height; + sizeHints->x = windowPosition.x; + sizeHints->y = windowPosition.y; XSetWMNormalHints(m_display, m_window, sizeHints); XFree(sizeHints); } @@ -707,7 +721,15 @@ m_lastInputTime (0) // Set fullscreen video mode and switch to fullscreen if necessary if (m_fullscreen) { - setPosition(Vector2i(0, 0)); + // Disable hint for min and max size, + // otherwise some windows managers will not remove window decorations + XSizeHints *sizeHints = XAllocSizeHints(); + long flags = 0; + XGetWMNormalHints(m_display, m_window, sizeHints, &flags); + sizeHints->flags &= ~(PMinSize | PMaxSize); + XSetWMNormalHints(m_display, m_window, sizeHints); + XFree(sizeHints); + setVideoMode(mode); switchToFullscreen(); } @@ -721,11 +743,11 @@ WindowImplX11::~WindowImplX11() cleanup(); // Destroy icon pixmap - if(m_iconPixmap) + if (m_iconPixmap) XFreePixmap(m_display, m_iconPixmap); // Destroy icon mask pixmap - if(m_iconMaskPixmap) + if (m_iconMaskPixmap) XFreePixmap(m_display, m_iconMaskPixmap); // Destroy the cursor @@ -779,6 +801,9 @@ void WindowImplX11::processEvents() m_events.pop_front(); processEvent(event); } + + // Process clipboard window events + priv::ClipboardImpl::processEvents(); } @@ -956,10 +981,10 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8 return; } - if(m_iconPixmap) + if (m_iconPixmap) XFreePixmap(m_display, m_iconPixmap); - if(m_iconMaskPixmap) + if (m_iconMaskPixmap) XFreePixmap(m_display, m_iconMaskPixmap); m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); @@ -1236,53 +1261,99 @@ void WindowImplX11::setVideoMode(const VideoMode& mode) return; // Check if the XRandR extension is present - int version; - if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) + int xRandRMajor, xRandRMinor; + if (!checkXRandR(xRandRMajor, xRandRMinor)) { // XRandR extension is not supported: we cannot use fullscreen mode err() << "Fullscreen is not supported, switching to window mode" << std::endl; return; } - // Get the current configuration - XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); + // Get root window + ::Window rootWindow = RootWindow(m_display, m_screen); - if (!config) + // Get the screen resources + XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow); + if (!res) { - // Failed to get the screen configuration - err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl; + err() << "Failed to get the current screen resources for fullscreen mode, switching to window mode" << std::endl; return; } - // Save the current video mode before we switch to fullscreen - Rotation currentRotation; - m_oldVideoMode = XRRConfigCurrentConfiguration(config, ¤tRotation); + RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor); + + // Get output info from output + XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output); + if (!outputInfo || outputInfo->connection == RR_Disconnected) + { + XRRFreeScreenResources(res); - // Get the available screen sizes - int nbSizes; - XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); + // If outputInfo->connection == RR_Disconnected, free output info + if (outputInfo) + XRRFreeOutputInfo(outputInfo); - // Search for a matching size - for (int i = 0; (sizes && i < nbSizes); ++i) + err() << "Failed to get output info for fullscreen mode, switching to window mode" << std::endl; + return; + } + + // Retreive current RRMode, screen position and rotation + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc); + if (!crtcInfo) { - XRRConfigRotations(config, ¤tRotation); + XRRFreeScreenResources(res); + XRRFreeOutputInfo(outputInfo); + err() << "Failed to get crtc info for fullscreen mode, switching to window mode" << std::endl; + return; + } - if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) - std::swap(sizes[i].height, sizes[i].width); + // Find RRMode to set + bool modeFound = false; + RRMode xRandMode; - if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height))) - { - // Switch to fullscreen mode - XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime); + for (int i = 0; (i < res->nmode) && !modeFound; i++) + { + if (crtcInfo->rotation == RR_Rotate_90 || crtcInfo->rotation == RR_Rotate_270) + std::swap(res->modes[i].height, res->modes[i].width); - // Set "this" as the current fullscreen window - fullscreenWindow = this; - break; + // Check if screen size match + if (res->modes[i].width == static_cast<int>(mode.width) && + res->modes[i].height == static_cast<int>(mode.height)) + { + xRandMode = res->modes[i].id; + modeFound = true; } } - // Free the configuration instance - XRRFreeScreenConfigInfo(config); + if (!modeFound) + { + XRRFreeScreenResources(res); + XRRFreeOutputInfo(outputInfo); + err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl; + return; + } + + // Save the current video mode before we switch to fullscreen + m_oldVideoMode = crtcInfo->mode; + m_oldRRCrtc = outputInfo->crtc; + + // Switch to fullscreen mode + XRRSetCrtcConfig(m_display, + res, + outputInfo->crtc, + CurrentTime, + crtcInfo->x, + crtcInfo->y, + xRandMode, + crtcInfo->rotation, + &output, + 1); + + // Set "this" as the current fullscreen window + fullscreenWindow = this; + + XRRFreeScreenResources(res); + XRRFreeOutputInfo(outputInfo); + XRRFreeCrtcInfo(crtcInfo); } @@ -1291,19 +1362,55 @@ void WindowImplX11::resetVideoMode() { if (fullscreenWindow == this) { - // Get current screen info - XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); - if (config) + // Try to set old configuration + // Check if the XRandR extension + int xRandRMajor, xRandRMinor; + if (checkXRandR(xRandRMajor, xRandRMinor)) { - // Get the current rotation - Rotation currentRotation; - XRRConfigCurrentConfiguration(config, ¤tRotation); + XRRScreenResources* res = XRRGetScreenResources(m_display, DefaultRootWindow(m_display)); + if (!res) + { + err() << "Failed to get the current screen resources to reset the video mode" << std::endl; + return; + } + + // Retreive current screen position and rotation + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, m_oldRRCrtc); + if (!crtcInfo) + { + XRRFreeScreenResources(res); + err() << "Failed to get crtc info to reset the video mode" << std::endl; + return; + } + + RROutput output; + + // if version >= 1.3 get the primary screen else take the first screen + if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1) + { + output = XRRGetOutputPrimary(m_display, DefaultRootWindow(m_display)); - // Reset the video mode - XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); + // Check if returned output is valid, otherwise use the first screen + if (output == None) + output = res->outputs[0]; + } + else{ + output = res->outputs[0]; + } - // Free the configuration instance - XRRFreeScreenConfigInfo(config); + XRRSetCrtcConfig(m_display, + res, + m_oldRRCrtc, + CurrentTime, + crtcInfo->x, + crtcInfo->y, + m_oldVideoMode, + crtcInfo->rotation, + &output, + 1); + + XRRFreeCrtcInfo(crtcInfo); + XRRFreeScreenResources(res); } // Reset the fullscreen window @@ -1499,7 +1606,7 @@ void WindowImplX11::updateLastInputTime(::Time time) { Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true); - if(netWmUserTime) + if (netWmUserTime) { XChangeProperty(m_display, m_window, @@ -1969,6 +2076,106 @@ bool WindowImplX11::processEvent(XEvent& windowEvent) return true; } + +//////////////////////////////////////////////////////////// +bool WindowImplX11::checkXRandR(int& xRandRMajor, int& xRandRMinor) +{ + // Check if the XRandR extension is present + int version; + if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) + { + err() << "XRandR extension is not supported" << std::endl; + return false; + } + + // Check XRandR version, 1.2 required + if (!XRRQueryVersion(m_display, &xRandRMajor, &xRandRMinor) || xRandRMajor < 1 || (xRandRMajor == 1 && xRandRMinor < 2 )) + { + err() << "XRandR is too old" << std::endl; + return false; + } + + return true; +} + + +//////////////////////////////////////////////////////////// +RROutput WindowImplX11::getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor) +{ + // if xRandR version >= 1.3 get the primary screen else take the first screen + if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1) + { + RROutput output = XRRGetOutputPrimary(m_display, rootWindow); + + // Check if returned output is valid, otherwise use the first screen + if (output == None) + return res->outputs[0]; + else + return output; + } + + // xRandr version can't get the primary screen, use the first screen + return res->outputs[0]; +} + + +//////////////////////////////////////////////////////////// +Vector2i WindowImplX11::getPrimaryMonitorPosition() +{ + Vector2i monitorPosition; + + // Get root window + ::Window rootWindow = RootWindow(m_display, m_screen); + + // Get the screen resources + XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow); + if (!res) + { + err() << "Failed to get the current screen resources for.primary monitor position" << std::endl; + return monitorPosition; + } + + // Get xRandr version + int xRandRMajor, xRandRMinor; + if (!checkXRandR(xRandRMajor, xRandRMinor)) + xRandRMajor = xRandRMinor = 0; + + RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor); + + // Get output info from output + XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output); + if (!outputInfo || outputInfo->connection == RR_Disconnected) + { + XRRFreeScreenResources(res); + + // If outputInfo->connection == RR_Disconnected, free output info + if (outputInfo) + XRRFreeOutputInfo(outputInfo); + + err() << "Failed to get output info for.primary monitor position" << std::endl; + return monitorPosition; + } + + // Retreive current RRMode, screen position and rotation + XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc); + if (!crtcInfo) + { + XRRFreeScreenResources(res); + XRRFreeOutputInfo(outputInfo); + err() << "Failed to get crtc info for.primary monitor position" << std::endl; + return monitorPosition; + } + + monitorPosition.x = crtcInfo->x; + monitorPosition.y = crtcInfo->y; + + XRRFreeCrtcInfo(crtcInfo); + XRRFreeOutputInfo(outputInfo); + XRRFreeScreenResources(res); + + return monitorPosition; +} + } // namespace priv } // namespace sf diff --git a/src/SFML/Window/Unix/WindowImplX11.hpp b/src/SFML/Window/Unix/WindowImplX11.hpp index 0ff694b..a025a1a 100644 --- a/src/SFML/Window/Unix/WindowImplX11.hpp +++ b/src/SFML/Window/Unix/WindowImplX11.hpp @@ -34,6 +34,7 @@ #include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib #include <X11/Xlib.h> #include <deque> +#include <X11/extensions/Xrandr.h> namespace sf @@ -265,6 +266,38 @@ private: bool processEvent(XEvent& windowEvent); //////////////////////////////////////////////////////////// + /// \brief Check if a valid version of XRandR extension is present + /// + /// \param xRandRMajor XRandR major version + /// \param xRandRMinor XRandR minor version + /// + /// \return True if a valid XRandR version found, false otherwise + /// + //////////////////////////////////////////////////////////// + bool checkXRandR(int& xRandRMajor, int& xRandRMinor); + + //////////////////////////////////////////////////////////// + /// \brief Get the RROutput of the primary monitor + /// + /// \param rootWindow the root window + /// \param res screen resources + /// \param xRandRMajor XRandR major version + /// \param xRandRMinor XRandR minor version + /// + /// \return RROutput of the primary monitor + /// + //////////////////////////////////////////////////////////// + RROutput getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor); + + //////////////////////////////////////////////////////////// + /// \brief Get coordinates of the primary monitor + /// + /// \return Position of the primary monitor + /// + //////////////////////////////////////////////////////////// + Vector2i getPrimaryMonitorPosition(); + + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// ::Window m_window; ///< X identifier defining our window @@ -275,6 +308,7 @@ private: std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window bool m_isExternal; ///< Tell whether the window has been created externally or by SFML int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen + RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen ::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one ::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? diff --git a/src/SFML/Window/Win32/CursorImpl.cpp b/src/SFML/Window/Win32/CursorImpl.cpp index 28f4274..d1913d6 100755 --- a/src/SFML/Window/Win32/CursorImpl.cpp +++ b/src/SFML/Window/Win32/CursorImpl.cpp @@ -69,7 +69,7 @@ bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hot bitmapHeader.bV5BlueMask = 0x000000ff; bitmapHeader.bV5AlphaMask = 0xff000000; - Uint8* bitmapData = NULL; + Uint32* bitmapData = NULL; HDC screenDC = GetDC(NULL); HBITMAP color = CreateDIBSection( @@ -89,7 +89,12 @@ bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hot } // Fill our bitmap with the cursor color data - std::memcpy(bitmapData, pixels, size.x * size.y * 4); + // We'll have to swap the red and blue channels here + Uint32* bitmapOffset = bitmapData; + for (std::size_t remaining = size.x * size.y; remaining > 0; --remaining, pixels += 4) + { + *bitmapOffset++ = (pixels[3] << 24) | (pixels[0] << 16) | (pixels[1] << 8) | pixels[2]; + } // Create a dummy mask bitmap (it won't be used) HBITMAP mask = CreateBitmap(size.x, size.y, 1, 1, NULL); diff --git a/src/SFML/Window/iOS/SFAppDelegate.mm b/src/SFML/Window/iOS/SFAppDelegate.mm index 6b17384..ea69f41 100644 --- a/src/SFML/Window/iOS/SFAppDelegate.mm +++ b/src/SFML/Window/iOS/SFAppDelegate.mm @@ -56,6 +56,10 @@ namespace //////////////////////////////////////////////////////////// + (SFAppDelegate*)getInstance { + NSAssert(delegateInstance, + @"SFAppDelegate instance is nil, this means SFML was not properly initialized. " + "Make sure that the file defining your main() function includes <SFML/Main.hpp>"); + return delegateInstance; } @@ -173,7 +177,7 @@ namespace NSArray *supportedOrientations = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UISupportedInterfaceOrientations"]; if (!supportedOrientations) - return false; + return (1 << orientation) & [rootViewController supportedInterfaceOrientations]; int appFlags = 0; if ([supportedOrientations containsObject:@"UIInterfaceOrientationPortrait"]) diff --git a/src/SFML/Window/iOS/SFView.mm b/src/SFML/Window/iOS/SFView.mm index 063c61a..940d0a8 100644 --- a/src/SFML/Window/iOS/SFView.mm +++ b/src/SFML/Window/iOS/SFView.mm @@ -202,5 +202,11 @@ return self; } +//////////////////////////////////////////////////////////// +- (UITextAutocorrectionType) autocorrectionType +{ + return UITextAutocorrectionTypeNo; +} + @end diff --git a/src/SFML/Window/iOS/SFViewController.hpp b/src/SFML/Window/iOS/SFViewController.hpp index b8a77aa..2b65d35 100644 --- a/src/SFML/Window/iOS/SFViewController.hpp +++ b/src/SFML/Window/iOS/SFViewController.hpp @@ -56,14 +56,6 @@ - (BOOL)shouldAutorotate; //////////////////////////////////////////////////////////// -/// \brief Returns the supported orientations (iOS >= 6) -/// -/// \return A combination of all the supported orientations -/// -//////////////////////////////////////////////////////////// -- (NSUInteger)supportedInterfaceOrientations; - -//////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// @property (nonatomic) bool orientationCanChange; ///< Tells whether the controller's view can rotate or not diff --git a/src/SFML/Window/iOS/SFViewController.mm b/src/SFML/Window/iOS/SFViewController.mm index d8be047..8c23cdc 100644 --- a/src/SFML/Window/iOS/SFViewController.mm +++ b/src/SFML/Window/iOS/SFViewController.mm @@ -46,12 +46,4 @@ return self.orientationCanChange; } - -//////////////////////////////////////////////////////////// -- (NSUInteger)supportedInterfaceOrientations -{ - return UIInterfaceOrientationMaskAll; -} - - @end |